# Proxy with Laravel

> Serve the MetricRaven script and events from a Laravel app with the HTTP client.

Source: https://metricraven.com/docs/proxy-laravel  
Markdown: https://metricraven.com/docs/proxy-laravel.md  
Section: Proxy

A small route file relays the script and events with Laravel's HTTP client.

## Set it up

1. **Create routes/metricraven.php**

   ```php title="routes/metricraven.php"
   <?php
   // routes/metricraven.php
   use Illuminate\Http\Request;
   use Illuminate\Support\Facades\Http;
   use Illuminate\Support\Facades\Route;

   Route::match(['get', 'post'], '/a/{kind}', function (Request $request, string $kind) {
       $script = $kind === 'script' && $request->isMethod('get');
       $event = $kind === 'event' && $request->isMethod('post');
       abort_unless($script || $event, 404);

       $client = Http::timeout(15)->withHeaders(array_filter([
           'Origin' => $request->header('Origin'),
           'User-Agent' => $request->userAgent(),
           'X-Visitor-IP' => $request->ip(),
       ]));
       $upstream = $script
           ? $client->get('https://metricraven.com/js/script.js')
           : $client
               ->withBody($request->getContent(), $request->header('Content-Type', 'text/plain'))
               ->post('https://metricraven.com/api/v1/collect');

       return response($upstream->body(), $upstream->status())
           ->header('Content-Type', $upstream->header('Content-Type') ?: 'application/octet-stream')
           ->header('Cache-Control', $script ? 'public, max-age=3600' : 'no-store');
   })->whereIn('kind', ['script', 'event']);
   ```

2. **Load it outside the web middleware group**

   In `bootstrap/app.php`, add the `then` callback to your existing `withRouting` call. The routes then skip sessions and CSRF checks, which the tracker can't send.

   ```php title="bootstrap/app.php"
   // bootstrap/app.php · Laravel 11 or later
   use Illuminate\Support\Facades\Route;

   return Application::configure(basePath: dirname(__DIR__))
       ->withRouting(
           web: __DIR__.'/../routes/web.php',
           commands: __DIR__.'/../routes/console.php',
           health: '/up',
           // Outside the "web" group: no session cookie and no CSRF check on the tracker routes.
           then: function () {
               Route::group([], base_path('routes/metricraven.php'));
           },
       )
       ->withMiddleware(function (Middleware $middleware) {
           // Behind a load balancer or CDN? Trust it so $request->ip() is the visitor.
           // $middleware->trustProxies(at: '*');
       })
       // ...the rest of your existing configuration
   ```

3. **Add the script tag to your Blade layout**

   Paste it before `</head>` in the layout every page extends, for example `resources/views/layouts/app.blade.php`.

4. **Point your script tag at your own paths**

   Replace your MetricRaven tag with this one. `src` loads the tracker from your domain and `data-api` sends its events there too.

   ```html title="Your website's shared layout"
   <script defer src="/a/script" data-api="/a/event" data-site-id="YOUR_SITE_ID"></script>
   ```

> **Verify it works**
>
> Open your live site. In the browser's Network panel, `/a/script` loads the tracker and `/a/event` answers with `ok: true`. Nothing goes to `metricraven.com` from the browser.
>
> In **Traffic**, your own visit should show your real country and city. If every visit appears to come from your server's or host's location, the visitor IP isn't being forwarded.

## Notes

- If a CDN or load balancer sits in front of this server, the connecting address is that proxy, not the visitor. Use the visitor IP header it sets (and only one it overwrites, so visitors can't fake it).
- In Laravel, trust your load balancer with `$middleware->trustProxies()` so `$request->ip()` is the visitor.
- On Laravel 10 or earlier, register the file in `RouteServiceProvider` without the `web` middleware instead.

How the proxy works and which headers it must send: [Use your own domain](https://metricraven.com/docs/proxy).

## Details

- The proxy forwards only `Content-Type`, `Origin`, `User-Agent` and the visitor's IP as `x-visitor-ip`. Your site's cookies and auth headers never leave your server.
- `Origin` matters: MetricRaven checks it against your site's allowed domains. A missing or wrong origin is refused with `domain_not_allowed`.
- MetricRaven allows about 120 events per minute per visitor IP. Without `x-visitor-ip`, all of your visitors share the proxy's IP, so busy sites lose events as well as locations.
- A proxy doesn't guarantee that every blocker will allow tracking.
