Stickybeak Docs Dashboard Get early access

Backends

Laravel

Laravel analytics with Stickybeak starts by adding its script to your rendered pages; this guide shows you where it belongs and how to track page views, goals and purchase revenue. It is a lighter alternative to Google Analytics for Laravel, with live visitors, goals and revenue attribution in one script.

Add the script

  1. Add the site ID to config

    Copy the ID from Settings in the dashboard and add it to your production .env:

    STICKYBEAK_SITE_ID=YOUR_SITE_ID

    Then read it in config/services.php, so it still works once config is cached:

    'stickybeak' => [
        'site_id' => env('STICKYBEAK_SITE_ID'),
    ],
  2. Add Laravel visitor tracking to your layout

    Put this before </head> in the layout your pages share.

    <script>window.stickybeak = window.stickybeak || function () { (window.stickybeak.q = window.stickybeak.q || []).push(arguments); };</script>
    @production
        @if (config('services.stickybeak.site_id'))
            <script
                defer
                data-site="{{ config('services.stickybeak.site_id') }}"
                data-domain="example.com"
                src="https://app.usestickybeak.com/_cfw/s.js"
            ></script>
        @endif
    @endproduction

Check it's working

Deploy first.

See Verify your install.

Track goals

Give any button or link a data-goal attribute. Extra data-goal-* attributes become properties. See Custom goals.

<a href="{{ route('pricing') }}" data-goal="view_pricing" data-goal-from="hero">See pricing</a>

Fire a goal after a redirect

When a controller saves something and redirects, flash the goal to the session:

public function store(Request $request)
{
    $data = $request->validate([
        'name'     => ['required', 'string', 'max:255'],
        'email'    => ['required', 'email', 'unique:users'],
        'password' => ['required', 'min:8'],
    ]);

    $user = User::create([...$data, 'password' => Hash::make($data['password'])]);
    Auth::login($user);

    return redirect()->route('dashboard')->with('stickybeak_goal', [
        'name'  => 'signup',
        'props' => ['plan' => $request->input('plan', 'free')],
    ]);
}
@if ($goal = session('stickybeak_goal'))
    <script>window.stickybeak({{ Js::from($goal['name']) }}, {{ Js::from($goal['props'] ?? []) }});</script>
@endif

Track purchases

Fire a purchase on your order confirmation page, with the amount, currency and order ID.

public function success(Order $order)
{
    session()->now('stickybeak_goal', [
        'name'  => 'purchase',
        'props' => [
            'revenue'  => $order->total,
            'currency' => $order->currency,
            'order_id' => (string) $order->id,
        ],
    ]);

    return view('checkout.success', ['order' => $order]);
}

Payment webhooks (Stripe, Paddle, Cashier) can't fire goals, because there's no visitor's browser on the other end.

See Revenue.

Page changes

Path-changing Livewire and Inertia visits count; same-path, query-only and replace visits do not.

Livewire

public function subscribe()
{
    $this->validate();
    Subscriber::create(['email' => $this->email]);

    $this->js("window.stickybeak('newsletter_signup')");
}

Use fixed goal names with $this->js(); never interpolate user input.

Inertia

Inertia::flash('stickybeak_goal', ['name' => 'signup', 'props' => ['plan' => $user->plan]]);

return redirect()->route('dashboard');
import { router } from "@inertiajs/vue3"; // or @inertiajs/react, @inertiajs/svelte

router.on("flash", (event) => {
  const goal = event.detail.flash.stickybeak_goal;
  if (goal) window.stickybeak(goal.name, goal.props);
});

Listen once with router.on("flash"); older versions can share the session goal through HandleInertiaRequests::share().

If it isn't working

  • Read environment values through config; direct env() calls return nothing after config is cached.

See Troubleshooting.