Laravel
Integrate vTilt with Laravel — render the SDK in your Blade layout, identify on every authenticated request, send server-side events from queued jobs.
For full-stack Laravel apps using Blade (with or without Livewire/Inertia), this guide covers the basics: render the Browser SDK in your layout, identify the authenticated user on every page load, and send server-side events over HTTP.
#1. Configure services
// config/services.php
return [
'vtilt' => [
'token' => env('VTILT_TOKEN'),
'host' => env('VTILT_HOST', 'https://www.vtilt.com'),
],
];php
# .env
VTILT_TOKEN=YOUR_PROJECT_TOKEN
VTILT_HOST=https://www.vtilt.comtext
#2. Render the SDK in your Blade layout
{{-- resources/views/layouts/app.blade.php --}}
<!doctype html>
<html lang="en">
<head>
<script>
window.__vtilt = {
token: @json(config('services.vtilt.token')),
host: @json(config('services.vtilt.host')),
user: @json(auth()->check() ? [
'id' => (string) auth()->id(),
'email' => auth()->user()->email,
'name' => auth()->user()->name,
] : null),
};
</script>
<script>
!(function(t,e){/* ...vTilt loader snippet from Quick start... */})(document, window.vt || []);
vt.init(window.__vtilt.token, {
api_host: window.__vtilt.host,
autocapture: true,
capture_pageview: true,
capture_pageleave: true,
});
if (window.__vtilt.user) {
vt.identify(window.__vtilt.user.id, {
email: window.__vtilt.user.email,
name: window.__vtilt.user.name,
});
}
</script>
</head>
<body>@yield('content')</body>
</html>blade
#3. Server-side capture helper
For events that fire outside a browser session (webhooks, scheduled jobs, queued payment callbacks), POST directly to vTilt with Http.
// app/Services/VTilt.php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class VTilt
{
public static function capture(string $distinctId, string $event, array $properties = []): void
{
try {
Http::timeout(2)
->withHeaders(['Content-Type' => 'application/json'])
->post(config('services.vtilt.host') . '/api/e', [
'api_key' => config('services.vtilt.token'),
'event' => $event,
'distinct_id' => $distinctId,
'properties' => $properties,
]);
} catch (\Throwable $e) {
Log::warning('vtilt capture failed', ['e' => $e->getMessage()]);
}
}
}php
// app/Http/Controllers/CheckoutController.php
use App\Services\VTilt;
public function complete(Request $request)
{
VTilt::capture(
(string) $request->user()->id,
'purchase_completed',
['amount' => 99.99],
);
return response()->json(['ok' => true]);
}php
#4. Run captures in a queue
Queue server-side captures so analytics never block the user-facing response. Network failures shouldn't surface to your users.
// app/Jobs/CaptureVTiltEvent.php
namespace App\Jobs;
use App\Services\VTilt;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CaptureVTiltEvent implements ShouldQueue
{
use Dispatchable, Queueable, SerializesModels;
public function __construct(
public string $distinctId,
public string $event,
public array $properties = [],
) {}
public function handle(): void
{
VTilt::capture($this->distinctId, $this->event, $this->properties);
}
}php
CaptureVTiltEvent::dispatch((string) $user->id, 'subscription_renewed', ['plan' => $user->plan]);php
#Next steps
- Vue + PHP integration guide — full Vue + Laravel/PHP walkthrough.
- Identify & alias — anonymous → known user merge.
- Event forwarding — fan events out to GA4, Meta CAPI, PostHog.