Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Device Intelligence Bundle Laravel Package

nowo-tech/device-intelligence-bundle

A Symfony bundle for device intelligence: detect device type, browser, OS, and capabilities from user-agent data, with configurable detection rules and Twig/PHP integration for responsive, device-aware applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register

composer require nowo-tech/device-intelligence-bundle

This is a Symfony bundle, not a Laravel package — there is no service provider or publishable Laravel config. In a Symfony app, add it to config/bundles.php:

return [
    // ...
    NowoTech\DeviceIntelligenceBundle\DeviceIntelligenceBundle::class => ['all' => true],
];

In a Laravel app you do not get first-class support. Realistically you have three options before adopting:

  1. Run it in a Symfony sidecar (recommended for day-to-day use).
  2. Extract the matching/risk-scoring services into your own classes if they are framework-agnostic.
  3. Skip it and evaluate equivalent standalone libraries.

Because there are 0 stars and 0 dependents, treat this as an early-stage bundle: read README.md, src/, and config/ in the repo before wiring it into anything user-facing.

Where to look first

  • src/DependencyInjection/ — what config keys are exposed and what services are registered.
  • src/Controller/ — the collect endpoint route and its payload shape.
  • Services implementing matching and scoring — these are the parts you will call from your own code.
  • config/routes.yaml (or a route attribute) — how the collect endpoint is mounted.

Minimal config

Create config/packages/device_intelligence.yaml matching the options the bundle actually declares. If config keys are not documented in the README, inspect the Configuration class in src/DependencyInjection/Configuration.php — that is the source of truth.

First use case

The natural first integration is login and checkout risk scoring:

  1. Your frontend sends device signals to the collect endpoint.
  2. On a sensitive action (login, password reset, checkout), the backend asks the bundle for a match/risk result.
  3. You decide: allow, challenge (2FA/CAPTCHA), or block.

Start by hitting the collect endpoint manually (curl or Insomnia) and inspecting the response before writing any JavaScript.

Implementation Patterns

1. Collect endpoint wiring

The bundle exposes a collect endpoint. Front-load it with a small JS snippet on pages where you need signals (login form, checkout, registration). Keep the snippet isolated in a single entry point rather than scattering calls — consistent with the bundle's frontend rules (src/Resources/assets, src/Resources/public/build).

Pattern:

// one module, one init
export function initDeviceIntelligence() {
    window.addEventListener('load', async () => {
        await fetch(collectUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'same-origin',
            body: JSON.stringify({ /* token + payload per the bundle spec */ }),
        });
    });
}

Call initDeviceIntelligence() from the layout or form pages that matter — not from every page.

2. Risk scoring on sensitive actions

Wrap the call in your own service so the bundle stays a dependency, not a public API:

final class RiskGate
{
    public function __construct(private readonly RiskScoringService $risk) {}

    public function requiresChallenge(string $deviceId, string $userAgent): bool
    {
        $score = $this->risk->score($deviceId, $userAgent);
        return $score >= $this->threshold;
    }
}

Then use it in a listener, form handler, or middleware-style check. Keep the threshold in your config, not in the bundle config, so you can tune per environment.

3. Probabilistic matching

Use matching when you need to associate the current request with previously seen devices — e.g., "is this the same user agent + profile combination seen last week?". Store the returned device ID (and a match confidence, if the bundle exposes one) in your own table:

$deviceId = $matcher->match($signals); // returns null or a candidate ID

// persist the match + confidence for auditability
DeviceHistory::create([
    'user_id' => $userId,
    'device_id' => $deviceId,
    'confidence' => $confidence,
    'ip' => request()->ip(),
]);

This gives you an audit trail and lets you change thresholds later without rewriting the bundle integration.

4. Integration with authentication flows

Typical insertion points:

  • After login: record the device ID on the session/user.
  • On password reset / sensitive settings changes: compare against the stored device ID and elevate friction if the match is weak.
  • On checkout: combine the score with other signals (IP reputation, velocity) rather than blocking on the score alone.

Don't hard-block based on a single probabilistic match — the value is in adding friction at the right moment.

5. Testing

Mock the bundle services at the boundary (the risk scoring service and the matcher). Do not test against the collect endpoint in unit tests; that endpoint depends on real client signals. Add an integration test against a fixture payload instead.

Gotchas and Tips

Device IDs are not credentials. The package description says this explicitly. Treat every device ID as a hint, never as proof. Never authorize a user, reset a session, or grant access based on a device ID match alone. Use it to add friction (2FA, CAPTCHA) not to remove it.

You are trusting client input. The collect endpoint receives data the client controls. Assume a hostile client:

  • Rate-limit the endpoint.
  • Validate payload size and shape.
  • Never trust it before authentication is complete, and never let it leak other users' data.
  • Do not echo back internal IDs or scores that reveal your thresholds.

Probabilistic matching has false positives and negatives. The same user across two browsers may not match; a new device on the same network may match. Design your flow so a "no match" is a soft signal (challenge) rather than a hard failure.

No Laravel integration exists. There is no DeviceIntelligence::class facade, no config/device-intelligence.php, no published migrations. If you are on Laravel, don't expect php artisan to help. Use a Symfony sidecar or copy the logic.

Compatibility window. The bundle targets PHP ≥ 8.1 and Symfony 6/7/8. A Laravel app that is still on PHP 8.0, or a legacy Symfony 5 app, will not install cleanly.

Config caching. In Symfony, remember bin/console cache:clear after changing the bundle's config. In a Laravel port, config is cached separately and needs php artisan config:clear.

Version pinning. Zero stars, zero dependents, no release history to speak of. Pin the version in composer.json and re-check the changelog on upgrades; a ^1.0 constraint may drift.

Debugging the collect endpoint. First confirm the route is reachable (bin/console debug:router | grep -i device). If responses are empty or 4xx, check:

  • CSRF or auth middleware in front of the endpoint.
  • Payload content-type mismatch.
  • Rate limiting / WAF rules.

Look at the bundle's own controller — it will show you what it expects.

Extension points. Prefer wrapping bundle services in your own thin services (RiskGate, DeviceHistoryWriter) rather than calling bundle services from controllers. This makes replacement easy if the bundle is abandoned and prevents your public API from depending on a zero-star dependency.

Privacy. You are collecting device and user-agent data for scoring. Check your privacy notice and retention policy before you ship. If a GDPR-style consent flow applies, gate collection on consent.

Release hygiene. The bundle's own rules mention CHANGELOG.md and UPGRADING.md. Read them before upgrading; the bundle explicitly preserves backward compatibility but is early enough that behavior may still change.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource