wi3edigital/laravel-posthog-tracker (1.1.0)

Published 2026-07-27 08:12:03 +02:00 by renovate.bot

Installation

{
	"repositories": [{
			"type": "composer",
			"url": ""
		}
	]
}
composer require wi3edigital/laravel-posthog-tracker:1.1.0

About this package

PostHog analytics tracker for Laravel applications.

Laravel PostHog Tracker

PostHog analytics for Laravel. Server-side event capture with optional JS client-side proxy support.

Requirements

  • PHP 8.4+
  • Laravel 12+

Installation

composer require wi3edigital/laravel-posthog-tracker

Package auto-discovers via Laravel's package discovery.

Configuration

Publish the config file:

php artisan vendor:publish --tag=posthog-config

Add to .env:

POSTHOG_API_KEY=phc_your_key_here
POSTHOG_HOST=https://us.i.posthog.com

Config reference

// config/posthog.php
'api_key' => env('POSTHOG_API_KEY'),
'host'    => env('POSTHOG_HOST', 'https://us.i.posthog.com'),

// null  = auto (only in production when api_key is set)
// true  = always enabled (when api_key is set)
// false = always disabled
'enabled' => env('POSTHOG_ENABLED'),

// Tracking only fires once the visitor has granted consent (e.g. via a
// cookie banner). Consent is read from a plain-text cookie, so it must be
// excluded from Laravel's cookie encryption (`encryptCookies(except: [...])`
// in bootstrap/app.php) — both client-side JS and PHP need to read the same
// raw value.
'consent' => [
    'required'      => env('POSTHOG_CONSENT_REQUIRED', true), // false = skip the consent check entirely
    'cookie'        => env('POSTHOG_CONSENT_COOKIE', 'posthog_consent'),
    'granted_value' => 'all',
],

'route' => [
    'prefix'     => env('POSTHOG_ROUTE_PREFIX', 'analytics'),
    'middleware' => ['web'],
    'name'       => 'analytics.capture',
],

capture() and identify() no-op until the visitor has consented — checked live per call via PosthogTracker::hasConsent(), which reads the posthog.consent.cookie cookie for the granted_value. The host application is responsible for the consent UI (e.g. a cookie banner) that sets this cookie, and for excluding it from cookie encryption so client-side JS can read/write it too.

Set posthog.consent.required to false to skip the check entirely (e.g. for internal/staging environments).

Usage

Capture events

use Wi3eDigital\PosthogTracker\Facades\PosthogTracker;

// Authenticated user (auto-resolved from Auth::user() if null)
PosthogTracker::capture(user: $user, event: 'order.placed', properties: [
    'order_id' => $order->id,
    'total'    => $order->total,
]);

// Anonymous / guest (uses session ID as distinct ID)
PosthogTracker::capture(user: null, event: 'page.viewed');

// Custom distinct ID
PosthogTracker::capture(user: null, event: 'signup.started', options: [
    'distinct_id' => 'temp-uuid-or-token',
]);

// Group analytics
PosthogTracker::capture(user: $user, event: 'invoice.sent', options: [
    'groups' => ['company' => $company->id],
]);

Events are dispatched via defer() — no blocking HTTP calls during the request.

Identify users

PosthogTracker::identify(user: $user, traits: [
    'name'  => $user->name,
    'email' => $user->email,
    'plan'  => $user->plan,
]);

Custom properties / traits resolvers

Register in a ServiceProvider::boot() to automatically attach properties to every event:

use Wi3eDigital\PosthogTracker\PosthogTracker;

// Extra properties on every capture
PosthogTracker::resolvePropertiesUsing(function ($user) {
    return [
        'tenant_id' => $user->tenant_id,
        'plan'      => $user->plan,
    ];
});

// Default traits on every identify
PosthogTracker::resolveTraitsUsing(function ($user) {
    return [
        'name'  => $user->name,
        'email' => $user->email,
    ];
});

Default properties included on every event

Property Value
user_id Authenticated user's ID
environment app()->environment()
app_version config('app.version')
request_path Current request path
user_agent_hash SHA-256 hash of User-Agent

JavaScript setup

Client-side PostHog (optional)

Publish the JS stubs:

php artisan vendor:publish --tag=posthog-stubs

This publishes two files to resources/js/:

File Purpose
posthog.js Initialises PostHog JS SDK (production only)
analytics-tracker.js DOM attribute tracker + server-side proxy

Add to .env:

VITE_POSTHOG_API_KEY=phc_your_key_here
VITE_POSTHOG_HOST=https://us.i.posthog.com
VITE_POSTHOG_UI_HOST=https://us.posthog.com
VITE_APP_ENV=production

Import in your JS entry point:

import './posthog.js';
import './analytics-tracker.js';

Server-side capture route

The package registers POST /analytics/capture (name: analytics.capture). The JS tracker proxies client-side events through this route so your PostHog API key stays server-side.

Add to your Blade layout to support a custom route prefix:

<meta name="posthog-capture-url" content="{{ route('analytics.capture') }}">

HTML attribute tracking

Capture events declaratively in HTML without writing JS:

<!-- Simple event -->
<button data-analytics-event="cta.clicked">Sign up</button>

<!-- With properties -->
<button
    data-analytics-event="plan.selected"
    data-analytics-properties='{"plan":"pro","billing":"monthly"}'
>
    Choose Pro
</button>

<!-- With custom distinct ID -->
<button
    data-analytics-event="share.clicked"
    data-analytics-distinct-id="{{ $shareToken }}"
>
    Share
</button>

JS API

window.analyticsTracker.capture('video.played', { video_id: 123 });

Testing

use Wi3eDigital\PosthogTracker\Facades\PosthogTracker;

$fake = PosthogTracker::fake();

// ... trigger code that calls PosthogTracker::capture()

$fake->assertCaptured('order.placed');

$fake->assertCaptured('order.placed', function (array $payload): bool {
    return $payload['properties']['order_id'] === 42;
});

$fake->assertNotCaptured('payment.failed');

$fake->assertNothingCaptured();

$fake->assertIdentified($user);

$fake->assertIdentified($user, function (array $payload): bool {
    return $payload['traits']['plan'] === 'pro';
});

License

MIT

Dependencies

Dependencies

ID Version
illuminate/contracts ^12.0
illuminate/http ^12.0
illuminate/support ^12.0
php ^8.4
posthog/posthog-php ^4.0

Development dependencies

ID Version
larastan/larastan ^3.0
laravel/pint ^1.0
orchestra/testbench ^10.0
pestphp/pest ^4.0
pestphp/pest-plugin-laravel ^4.0
Details
Composer
2026-07-27 08:12:03 +02:00
160
MIT
17 KiB
Assets (1)
Versions (5) View all
1.1.1 2026-09-03
1.1.0 2026-07-27
1.0.4 2026-05-21
1.0.3 2026-05-20
1.0.2 2026-05-20