whichbrowser/parser
PHP user-agent parser for browser sniffing (use sparingly). WhichBrowser/Parser identifies browser, engine, OS and device with names and versions. Works on PHP 7.0+ including PHP 8; useful for analytics or UX edge cases.
Installation
composer require whichbrowser/parser
Add to composer.json if not auto-loaded:
"autoload": {
"psr-4": {
"App\\": "app/",
"WhichBrowser\\Parser\\": "vendor/whichbrowser/parser/src/"
}
}
Run composer dump-autoload.
First Use Case Parse a user-agent string in a controller or middleware:
use WhichBrowser\Parser\Parser;
$parser = new Parser();
$browser = $parser->parse($_SERVER['HTTP_USER_AGENT'] ?? '');
// Outputs something like: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
echo $browser->getBrowserName(); // "Chrome"
echo $browser->getVersion(); // "120.0.0.0"
Where to Look First
src/WhichBrowser/Parser/Parser.php for core logic.tests/ directory for edge cases (e.g., malformed user-agents).Attach to Laravel’s middleware stack to enrich requests:
namespace App\Http\Middleware;
use WhichBrowser\Parser\Parser;
use Closure;
class DetectBrowser
{
public function handle($request, Closure $next)
{
$parser = new Parser();
$browser = $parser->parse($request->userAgent());
$request->merge([
'browser' => $browser->getBrowserName(),
'browser_version' => $browser->getVersion(),
'is_mobile' => $browser->isMobile(),
'is_bot' => $browser->isBot(),
]);
return $next($request);
}
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\DetectBrowser::class,
];
Use the parsed data to serve tailored content:
@if($request->browser === 'Safari' && $request->browser_version < 15)
<script>
alert('Please upgrade Safari for full functionality.');
</script>
@endif
Avoid reprocessing the same user-agent repeatedly (e.g., in APIs):
$cacheKey = 'browser_'.md5($userAgent);
$browser = cache()->remember($cacheKey, now()->addHours(1), function() use ($userAgent) {
return (new Parser())->parse($userAgent);
});
Filter search results by browser:
$results = Product::search('laptop')->browser('Chrome')->get();
Requires a custom Scout extension (see Extension Points below).
Bind the parser as a singleton for dependency injection:
namespace App\Providers;
use WhichBrowser\Parser\Parser;
use Illuminate\Support\ServiceProvider;
class BrowserServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(Parser::class, function () {
return new Parser();
});
}
}
Use in controllers:
use WhichBrowser\Parser\Parser;
public function __construct(Parser $parser) {
$this->parser = $parser;
}
Include browser info in API responses:
return response()->json([
'data' => $product,
'metadata' => [
'browser' => $request->browser,
'is_mobile' => $request->is_mobile,
],
]);
Log browser data to a third-party service (e.g., Mixpanel, Google Analytics):
$analytics->track('Browser Visit', [
'browser' => $browser->getBrowserName(),
'version' => $browser->getVersion(),
'device' => $browser->isMobile() ? 'mobile' : 'desktop',
]);
isBot() method may misclassify legitimate crawlers (e.g., Googlebot).botlib/botlib.try {
$browser = $parser->parse($userAgent);
} catch (\Exception $e) {
$browser = new \WhichBrowser\Parser\Browser();
\Log::warning("Failed to parse user-agent: {$userAgent}", ['error' => $e]);
}
getBrowserFamily() for broader categorization:
$browser->getBrowserFamily(); // "Blink" for Chrome, "WebKit" for Safari
Dump the full parsed object to debug:
dd($browser->toArray());
Output includes:
[
'browser' => 'Chrome',
'version' => '120.0.0.0',
'os' => 'Windows',
'device' => 'desktop',
'is_mobile' => false,
'is_bot' => false,
// ... and more
]
The package uses a static database of user-agent patterns. To update:
composer require whichbrowser/parser:dev-main
Or manually pull updates from the GitHub repo.
Extend the parser to handle proprietary or niche user-agents:
$parser = new Parser();
$parser->addRule('MyCustomBrowser', '/MyCustomBrowser\/(\d+\.\d+)/');
$browser = $parser->parse('MyCustomBrowser/1.2.3');
echo $browser->getBrowserName(); // "MyCustomBrowser"
Add browser-based filtering to Scout:
namespace App\Scout;
use WhichBrowser\Parser\Parser;
use Laravel\Scout\Builder;
class BrowserExtensions
{
public function extend(Builder $builder)
{
$builder->macro('browser', function ($browserName) use ($builder) {
$parser = app(Parser::class);
$userAgent = $builder->query->get('user_agent');
$browser = $parser->parse($userAgent);
return $builder->where('browser', $browserName);
});
}
}
Register in AppServiceProvider:
\App\Scout\BrowserExtensions::extend(app('scout'));
Trigger actions based on browser detection:
namespace App\Listeners;
use WhichBrowser\Parser\Browser;
class LogBrowserEvent
{
public function handle($event)
{
$browser = $event->browser;
if ($browser->getBrowserName() === 'Firefox') {
\Log::info("Firefox user detected", ['version' => $browser->getVersion()]);
}
}
}
Dispatch in middleware:
event(new \App\Events\BrowserDetected($browser));
The parser checks for updates on initialization. Disable with:
$parser = new Parser();
$parser->setUpdateCheck(false);
How can I help you explore Laravel packages today?