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

Browser Laravel Package

ikimea/browser

Ikimea Browser provides reliable user-agent detection for PHP and Laravel apps, identifying browser name and version, operating system, platform, device type, and bots. Its simple API helps tailor content, handle mobile visitors, and enrich analytics.

Deep Wiki
Context7

Getting Started

Install with Composer — there is no Laravel service provider baked in:

composer require ikimea/browser

The package exposes a single class, Ikimea\Browser\Browser. Construct it once and ask it about the current request:

use Ikimea\Browser\Browser;

$browser = new Browser();

$browser->getBrowser();        // Browser::BROWSER_CHROME
$browser->getVersion();        // '120.0.0.0'
$browser->getPlatform();       // Browser::PLATFORM_WINDOWS
$browser->isMobile();          // bool
$browser->isRobot();           // bool
$browser->getUserAgent();      // raw UA string
$browser->getAcceptLanguages();// ['en-US', 'en', 'fr']

Where to look first:

  • src/Browser.php — the detection logic and every constant you will branch on. Read the constant block (BROWSER_*, PLATFORM_*) before writing conditionals.
  • src/AcceptLanguage.php — the Accept-Language parser used by getAcceptLanguages().

First real use case: feature-gating a legacy asset bundle or showing an "upgrade your browser" banner. Because the constructor accepts overrides, you can verify behavior without a real browser:

$browser = new Browser('Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko');

if ($browser->getBrowser() === Browser::BROWSER_IE && version_compare($browser->getVersion(), '11', '<=')) {
    // serve legacy CSS / show banner
}

Implementation Patterns

Bind it as a singleton in a service provider. The UA does not change during a request, so parse it once:

$this->app->singleton(Browser::class, fn () => new Browser(
    request()->userAgent(),
    request()->header('Accept-Language')
));

Then inject Browser into controllers, middleware, or jobs. Using the request headers explicitly (rather than relying on $_SERVER) keeps it testable and consistent behind proxies.

Middleware for coarse routing. A mobile redirect or a "block ancient IE" middleware is a natural fit:

public function handle($request, Closure $next)
{
    $browser = app(Browser::class);

    if ($browser->isRobot() || $browser->getBrowser() === Browser::BROWSER_UNKNOWN) {
        return $next($request); // never redirect bots or unknown UAs
    }

    if ($request->is('desktop/*') && $browser->isMobile()) {
        return redirect()->to(str_replace('desktop', 'm', $request->fullUrl()));
    }

    return $next($request);
}

Blade / view composer for conditional assets. Share a small view-model instead of calling the class in templates:

View::composer('layouts.app', function ($view) {
    $b = app(Browser::class);
    $view->with('legacyBrowser', $b->getBrowser() === Browser::BROWSER_IE
        && version_compare($b->getVersion(), '11', '<='));
});

Localization fallback. getAcceptLanguages() returns languages in preference order, which is ideal for choosing a default locale on first visit:

$supported = ['en', 'fr', 'de'];
$locale = collect($browser->getAcceptLanguages())
    ->map(fn ($l) => substr($l, 0, 2))
    ->first(fn ($l) => in_array($l, $supported)) ?? config('app.locale');

Analytics and logging. Store getBrowser(), getVersion(), getPlatform(), and isMobile() as columns/attributes on request logs. Keep the raw UA too — it is the only way to re-parse historical data when detection rules change.

Feature flags. Wrap version checks in a dedicated policy class (BrowserPolicy::supportsWebp()) rather than sprinkling constants through controllers; the underlying library is stable but the policy will need to evolve.

Gotchas and Tips

  • Versions are strings, not floats. Never do $browser->getVersion() > 10; use version_compare($browser->getVersion(), '10', '>='). Chrome's UA reduction often reports 120.0.0.0, and some UAs only expose a major version.
  • Detection is UA parsing, not capability detection. It tells you the browser claims to be; it does not tell you what CSS/JS it supports. Use @supports, Modernizr, or navigator.userAgentData client-side for real capability gating.
  • Newer browsers may hide behind Chrome. Chromium-based Edge, Brave, Vivaldi, and Opera GX all include Chrome/ in their UA. If a specific browser matters, verify against getUserAgent() and add extra checks rather than trusting a single constant.
  • Order of checks matters in the parser. Chrome contains Safari, Edge contains Chrome, Opera contains Chrome — the library handles this internally, but if you extend detection, always test the most specific token first.
  • BROWSER_UNKNOWN is your "do not trust this" bucket. Empty UA, curl, and spoofed strings land here. Do not treat unknown as an error; branch safely.
  • Robots before mobile. Googlebot's UA looks mobile in some variants. Check isRobot() first, otherwise you will redirect crawlers to a mobile site and hurt SEO.
  • Do not use it for security. UA is trivially spoofed — never gate authentication, rate limiting, or access control on getBrowser().
  • Testability comes from the constructor. Pass synthetic UA and Accept-Language strings in unit tests instead of mutating $_SERVER; this also avoids global-state bleed between tests.
  • Language parsing is header-only. getAcceptLanguages() reads Accept-Language and ignores cookies/session. If a user has already chosen a locale, respect that before consulting this.
  • No auto-discovery / facade. In modern Laravel, register the singleton manually; otherwise you will construct a new parser per resolution. If you need a facade, create one — the package does not ship it.
  • Consider the maintenance story. The API is small and stable, but browser detection lists age quickly. If long-term accuracy matters (especially for fraud/analytics), evaluate matomo/device-detector or whichbrowser/parser, which maintain larger and regularly updated regex datasets; ikimea/browser is best when you want a lightweight, dependency-free check for coarse branching.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package