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

Mobile Detect Bundle Laravel Package

tattali/mobile-detect-bundle

Symfony bundle that wraps the Mobile Detect library to identify mobile phones, tablets, and desktop browsers from user agents, with service and Twig integration for device-aware routing, views, and responsive experiences.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer; Flex registers the bundle automatically (otherwise add MobileDetectBundle\MobileDetectBundle to config/bundles.php):

composer require tattali/mobile-detect-bundle

Where to look first: the bundle's README.md config block, then bin/console debug:container mobile_detect and bin/console debug:twig to see what is actually registered in your installed version — the config tree has changed between majors, so trust the installed source over blog posts.

First use case — inject and branch. Nothing needs configuring for detection; the services are available out of the box:

use MobileDetectBundle\DeviceDetector\MobileDetectorInterface;

final class BillingController
{
    public function __construct(private MobileDetectorInterface $mobileDetector) {}

    public function checkout(): Response
    {
        if ($this->mobileDetector->isMobile() && !$this->mobileDetector->isTablet()) {
            // lighter payload, fewer upsells, Apple/Google Pay
        }
    }
}

In Twig the extension is registered for you:

{% if is_mobile() %}...{% endif %}
{% if is_tablet() %}...{% endif %}

First "real" feature is usually the redirect: send phone visitors to a mobile subdomain, tablet visitors to a tablet one, then widen that into view switching later.

Implementation Patterns

1. Subdomain redirect (the bundle's headline feature). This is the pattern 90% of installs want — no controller code at all:

# config/packages/mobile_detect.yaml
mobile_detect:
    redirect:
        mobile:
            host: m.example.com
            action: redirect        # redirect | no_redirect | allow
            status_code: 302
        tablet:
            host: t.example.com
            action: redirect
            status_code: 302

A kernel.request listener inspects the User-Agent and issues the redirect before your controllers run. Use 301 only if the mapping is permanent (it is not — devices change); 302 is the sane default.

2. View switching on a single domain (responsive + separate templates). Enable the switcher so ?device_view=mobile|tablet|full is honoured and persisted in a cookie:

mobile_detect:
    switch_device_view:
        save_referrer: true
        cookie_key: device_view

Then build a "view this site as: Mobile / Tablet / Desktop" footer with {{ path('homepage', {device_view: 'mobile'}) }}. Pair this with action: allow on the redirect config so an explicit choice isn't immediately undone by the auto-redirect — that combination is the whole reason allow exists.

3. Template selection instead of redirects. In a base controller or a kernel.controller listener, pick the template directory:

$view = $deviceView->getDeviceView(); // full / mobile / tablet
$request->attributes->set('_view', $view);

Then render("pages/{$_view}/index.html.twig"). Keeps one URL per page (good for SEO and analytics) while still shipping a distinct mobile layout.

4. Twig-level nudges. The cheapest win: gate app-store banners, sticky "call us" bars, and <video> autoplay behind is_mobile(). Do this before you commit to a second hostname — it is often all you actually need.

5. Service-layer policy. Inject MobileDetectorInterface into services that need degradation logic (image transcoding, feature flags). Avoid injecting it into entities or value objects; pass a boolean in instead.

6. Testing. Set the UA in functional tests — no mocking needed:

$client->request('GET', '/', [], [], [
    'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) ...',
]);

For unit tests, mock MobileDetectorInterface or alias the service:

# config/services_test.yaml
services:
    MobileDetectBundle\DeviceDetector\MobileDetectorInterface: '@App\Tests\Fake\AlwaysMobileDetector'

Keep a small set of canned UAs (iPhone, iPad, Android tablet, Android phone, desktop Chrome) in a fixture file and use them everywhere — otherwise you get flaky assertions from hand-typed UA strings.

Gotchas and Tips

  • Redirect loops. If m.example.com serves the same Symfony app with the same config, verify the listener doesn't bounce the user again. Guard in your web server / front controller by only enabling the redirect config on the desktop host, or lean on action: allow plus the view cookie.
  • The listener only fires on main, safe requests. Subrequests, ESI fragments, and non-GET traffic are generally skipped. Don't expect a POST to a desktop URL to redirect mid-flight — redirecting a POST loses the body. Redirect before forms, not after.
  • HTTP caching will bite you. A response that varies by User-Agent needs Vary: User-Agent (and Vary: Cookie once view switching is on) or your CDN/Varnish will serve a mobile page to desktop users. Set this explicitly on the redirect response and on any cached page whose template depends on is_mobile(). Better still: keep device-dependent markup out of the anonymous, long-lived cache and load it via ESI/JSON.
  • User-Agent detection is spoofable and aging out. iPadOS 13+ sends a desktop Safari UA by default; Android tablets frequently omit Mobile; some Android phones include it. Test isTablet() carefully — "not mobile and not desktop" is a common source of surprise. Client Hints (Sec-CH-UA-Mobile) are not consulted by this bundle; if you need them, decorate the detector.
  • Cookie units and lifetime. cookie_expire is an integer whose unit has differed across versions (minutes in current docs). Confirm in vendor/tattali/mobile-detect-bundle before shipping — and remember the cookie only exists once switch_device_view is enabled; a getDeviceView() call without it always returns the full view.
  • save_referrer is what makes "back to full site" work. Turn it on if you expose a switcher; without it the user is stranded on the mobile view.
  • host vs. full URL. host: expects the target host; if you need a path prefix, check whether your version accepts a full URL. A missing scheme or a trailing slash is the most common silent misconfiguration — dump the resolved config with bin/console debug:config mobile_detect after every change.
  • Extension points. Everything is a normal Symfony service: decorate mobile_detect to add your own isRobot()-style methods (handy for excluding bots from redirects — bots following a 302 to a mobile host is a real SEO problem), or provide your own detector via the bundle's service config key so the Twig helpers use your implementation.
  • Don't treat this as responsive design. It answers "is this a phone?", not "is the viewport 360px?". CSS media queries remain the source of truth for layout; use this bundle for routing, redirects, and payload decisions only.
  • 38 stars ≠ unmaintained, but it is a small surface. You are one composer update away from a broken Twig function name. Pin the major, and write one smoke test per Twig helper you use (is_mobile, is_tablet, is_full_view) so an upgrade failure shows up in CI rather than in production.
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.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table