Backend frameworks · 5 min setup

How to add analytics to a Laravel app

To add VisitTrack to Laravel, put the script tag in the <head> of your main Blade layout (for example resources/views/layouts/app.blade.php, or app.blade.php with Inertia), wrapped in @production. Livewire wire:navigate and Inertia page visits are counted as pageviews automatically.

Updated

The browser tag covers traffic. Laravel apps usually also want two server-side pieces: signups recorded where the account is actually created, and revenue tied to the visit that earned it. Both use the visitor id the tracker stores in a first-party _vt_vid cookie — which Laravel can read once you exclude it from cookie encryption.

Laravel at a glance

Where the tag goes
Main Blade layout <head> (layouts/app.blade.php / app.blade.php)
Production only
@production … @endproduction
SPA-style navigation
Livewire wire:navigate and Inertia tracked
Server events
Http::withToken()->post('/api/track')
Revenue
Cashier checkout() with client_reference_id

How to install VisitTrack on Laravel

  1. Step 1: Add your keys to config/services.php

    Put the site id (public) and a secret API key from VisitTrack's Settings → API / MCP in .env, and expose them through config.

    config/services.php
    // config/services.php
    'visitrack' => [
        'site_id' => env('VISITRACK_SITE_ID'),
        'key' => env('VISITRACK_API_KEY'), // server-side only
    ],
  2. Step 2: Add the tag to your Blade layout

    In the layout every page extends, inside <head>. @production renders it only when APP_ENV=production.

    resources/views/layouts/app.blade.php
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        @vite(['resources/css/app.css', 'resources/js/app.js'])
        @production
            <script defer data-site="{{ config('services.visitrack.site_id') }}" src="https://visitrack.app/tracker.js"></script>
        @endproduction
    </head>
  3. Step 3: Let Laravel read the visitor cookie

    Laravel encrypts cookies and ignores ones it can't decrypt. The tracker's _vt_vid cookie is written by the browser, so exclude it from encryption (Laravel 11+ shown; on Laravel 10, add it to $except in App\Http\Middleware\EncryptCookies).

    bootstrap/app.php
    // bootstrap/app.php
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->encryptCookies(except: ['_vt_vid']);
    })
  4. Step 4: Deploy and browse

    Deploy with APP_ENV=production, open the live site and click around. Local php artisan serve traffic is excluded twice over: by @production and by the tracker's localhost check.

How to check VisitTrack is working on Laravel

  1. View source on the live site — the tag is in <head> with your site id.
  2. Browse two pages; VisitTrack's live view shows you and the Pages tab lists both routes.
  3. In DevTools → Application → Cookies, you'll see _vt_vid on your domain (standard mode). That's the id your controllers can now read.

Classic Blade apps do full page loads — one pageview each. With Livewire's wire:navigate or Inertia, pages change without a reload and the URL is updated through the History API, which the tracker follows. Livewire runs scripts in <head> only on the first visit and keeps them across navigations, so the tag isn't executed twice.

Keep logged-in areas out of your marketing numbers with data-exclude="/dashboard*,/admin*" on the tag, or use a separate VisitTrack site for the app.

How to track custom events and goals in Laravel

Record signups on the server, where you know the account exists. Breeze and Jetstream fire Illuminate\Auth\Events\Registered after creating a user, so a listener is the cleanest hook:

app/Listeners/SendSignupToVisitTrack.php
// app/Listeners/SendSignupToVisitTrack.php
namespace App\Listeners;

use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Http;

class SendSignupToVisitTrack
{
    public function handle(Registered $event): void
    {
        $visitorId = request()->cookie('_vt_vid');
        if (! $visitorId) return; // cookieless mode or blocked tracker

        Http::withToken(config('services.visitrack.key'))
            ->timeout(3)
            ->post('https://visitrack.app/api/track', [
                'type' => 'event',
                'visitorId' => $visitorId,
                'name' => 'signup',
                'props' => ['method' => 'email'],
            ]);

        Http::withToken(config('services.visitrack.key'))
            ->timeout(3)
            ->post('https://visitrack.app/api/track', [
                'type' => 'identify',
                'visitorId' => $visitorId,
                'externalId' => (string) $event->user->id,
                'traits' => ['email' => $event->user->email, 'plan' => 'free'],
            ]);
    }
}

Laravel 11+ discovers listeners in app/Listeners automatically. An event named signup fills the Signups tab; identify puts the user in People. Prefer a queued listener (implements ShouldQueue) — but then capture the cookie value in the controller first, since a queued job has no request. Browser-side, data-vt-goal="…" and window.visitrack() work in Blade and Livewire views as usual. Reference: server-side events.

Revenue attribution on Laravel

Laravel Cashier (Stripe) creates Stripe Checkout Sessions, and its checkout() methods accept session options — so passing the visitor id as client_reference_id is one line. Connect Stripe in VisitTrack's Settings → Revenue and every payment is credited to the referrer, campaign and landing page that first brought that visitor. See Stripe revenue attribution.

Checkout controller
// One-off payment
return $request->user()->checkout(['price_xxx' => 1], [
    'success_url' => route('checkout.success'),
    'cancel_url' => route('pricing'),
    'client_reference_id' => $request->cookie('_vt_vid'),
]);

// Subscription
return $request->user()
    ->newSubscription('default', 'price_monthly')
    ->checkout([
        'success_url' => route('dashboard'),
        'cancel_url' => route('pricing'),
        'client_reference_id' => $request->cookie('_vt_vid'),
    ]);

Track AI crawlers in Laravel

GPTBot, ClaudeBot and PerplexityBot don't run JavaScript, so the browser tag never sees them. A terminable middleware reports each request after the response has been sent, so crawlers never wait. Keep in mind that files in public/ (like robots.txt) are served by your web server without reaching Laravel — serve robots.txt from a route if you want those requests counted. Background: AI crawler tracking.

app/Http/Middleware/ReportCrawlers.php
// app/Http/Middleware/ReportCrawlers.php — append it in bootstrap/app.php
public function handle(Request $request, Closure $next): Response
{
    return $next($request);
}

public function terminate(Request $request, Response $response): void
{
    try {
        Http::timeout(2)->post('https://visitrack.app/api/collect-bot', [
            'siteId' => config('services.visitrack.site_id'),
            'path' => '/' . ltrim($request->path(), '/'),
            'userAgent' => $request->userAgent(),
            'ip' => $request->ip(),
        ]);
    } catch (\Throwable) {
        // never let analytics break a request
    }
}

Script options you might need on Laravel

All optional — add them to the same tag. Full reference: script configuration.

AttributeWhat it does
data-cookielessStore nothing in the browser; the server derives a daily-rotating id. See cookieless mode.
data-exclude="/app/*"Never track these paths (comma-separated, * wildcard). Checked on every navigation.
data-allow-localTrack on localhost and *.local — for testing an install only.
data-debugLog every event the script sends, and why it skipped one, to the console.
data-auto="false"Turn off automatic events (downloads, contact clicks, form submits, rage clicks, JS errors, 404s).

Laravel troubleshooting

$request->cookie('_vt_vid') is always null

The cookie is still being decrypted. Exclude _vt_vid from EncryptCookies as in step 3. In cookieless mode there is no cookie at all — use your own user id as visitorId, as described in cookieless mode.

The tag doesn't render on the server

@production only renders when APP_ENV=production. Check your environment, and clear cached views with php artisan view:clear.

/api/track answers 401

The API key is missing or wrong. Create a key in Settings → API / MCP and check config('services.visitrack.key') isn't cached empty (php artisan config:clear).

Signups counted twice

You're sending signup from the listener and from the browser. Report each signup from one place only.

CSP blocks the tracker

If you use a CSP package such as spatie/laravel-csp, allow the origin: script-src 'self' https://visitrack.app; connect-src 'self' https://visitrack.app;

Laravel analytics FAQ

Where do I add an analytics script in Laravel?

In the <head> of the Blade layout every page extends — resources/views/layouts/app.blade.php in Breeze/Jetstream, resources/views/app.blade.php with Inertia. Wrap it in @production so local and staging environments don't send data.

Does VisitTrack work with Livewire wire:navigate and Inertia?

Yes. Both update the URL through the History API, and the tracker counts each pathname change as a pageview. Head scripts aren't re-run on navigation, so nothing is double-counted.

How do I track Laravel signups server-side?

Listen for the Registered event and POST a signup event to /api/track with a secret API key, using the _vt_vid cookie as visitorId. See server-side events.

Can VisitTrack attribute Laravel Cashier revenue?

Yes, for Stripe Checkout: pass client_reference_id with the visitor id in Cashier's checkout() options and connect Stripe in Settings → Revenue. Paddle (Cashier Paddle) is supported too via custom_data — see Paddle.

Why is the _vt_vid cookie unreadable in Laravel?

Laravel's EncryptCookies middleware tries to decrypt every cookie and drops ones it can't. Add _vt_vid to its except list so the plain value reaches your controllers.

Is VisitTrack GDPR-friendly for a Laravel SaaS?

In cookieless mode nothing is stored on the device and IPs are never stored. Server-side signup attribution then uses your own user id. General information, not legal advice.

Keep going

Add VisitTrack to your Laravel site

Cookie-free analytics with revenue attribution, live visitors, funnels and session replays. One script tag, every feature on every plan. 14 days free, no card required.

Not on Laravel? See all 29 integration guides.