Agent setup: authorize Sight MCP and ask your agent to call get_tracking_setup. It configures this integration automatically.

Laravel

Laravel middleware that forwards AI-crawler page requests to Sight's POST /api/v1/track, preserving the original User-Agent. Crawlers don't run JavaScript, so the browser tracker never fires for them unless they also fetch the script URL. This is the origin-side path.

Humans are not recorded here — they still use the browser tracker. Tracking every request would double-count people.

Part of Sight — see sightapp/sight-backend SPEC.md and tasks/plan.md (Track B4).

Install

composer require sightapp/sight-laravel

.env:

SIGHT_API_KEY=sk_...

Register the middleware (Laravel 11+, bootstrap/app.php):

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\Sight\Laravel\SightCrawlerMiddleware::class);
})

Laravel 10 and earlier, app/Http/Kernel.php's $middleware array:

protected $middleware = [
    ...,
    \Sight\Laravel\SightCrawlerMiddleware::class,
];

SightServiceProvider (auto-discovered) binds the middleware from config('sight.*'), which reads the env vars above — see config/sight.php. Publish it if you want to override the values in-repo instead of via env: php artisan vendor:publish --tag=sight-config.

Notes

  • GET requests only; other methods are ignored.
  • The UA token list matches sight-backend's internal/api/agents.go (GPTBot, ClaudeBot, PerplexityBot, …). Keep them in sync when that list grows.
  • The send is a short (3s timeout), synchronous curl call — PHP has no built-in async HTTP client without extra extensions. If you already run a queue worker, dispatch this via a queued job instead for zero request-path cost; a 3s-max crawler-only call is a reasonable default otherwise.

Verify

curl -s http://localhost:8000/pricing -A "GPTBot/1.0"
curl -s "https://api.usesight.dev/api/v1/query/agent-traffic?days=1" \
  -H "X-API-Key: YOUR_API_KEY"

GPTBot should show up. A request with a Chrome UA should not.

Tests

composer install
./vendor/bin/phpunit

5 tests, all passing against real Illuminate\Http\Request objects (no mocked framework internals): agent detection, a GPTBot GET producing exactly one tracked call with the right path/UA, a human GET producing none, and the required-apiKey check. Along the way, found and fixed a real bug in the test suite itself: Laravel's Request::path() returns without a leading slash ("pricing", not "/pricing") — send() normalizes this before POSTing to Sight.

Source repository