Sign up

Proxy

Proxy with PHP

On this page

One PHP file relays the script and events. It works on most shared hosting.

Set it up

  1. Upload a.php to your web root

    It needs PHP 7.4 or later with the curl extension, which most hosts enable.

    a.php
    <?php
    // a.php · plain PHP 7.4+ with the curl extension, next to your site's index.php
    $kind = $_GET['kind'] ?? '';
    $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
    $isScript = $kind === 'script' && $method === 'GET';
    $isEvent = $kind === 'event' && $method === 'POST';
    if (!$isScript && !$isEvent) {
        http_response_code(404);
        exit;
    }
    
    // Behind a CDN or load balancer, REMOTE_ADDR is that proxy: use the header it sets instead.
    $headers = ['X-Visitor-IP: ' . $_SERVER['REMOTE_ADDR']];
    $forward = ['CONTENT_TYPE' => 'Content-Type', 'HTTP_ORIGIN' => 'Origin', 'HTTP_USER_AGENT' => 'User-Agent'];
    foreach ($forward as $key => $name) {
        if (!empty($_SERVER[$key])) $headers[] = $name . ': ' . $_SERVER[$key];
    }
    
    $ch = curl_init($isScript ? 'https://metricraven.com/js/script.js' : 'https://metricraven.com/api/v1/collect');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_TIMEOUT => 15,
        CURLOPT_ENCODING => '',
    ]);
    if ($isEvent) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents('php://input'));
    }
    $body = curl_exec($ch);
    if ($body === false) {
        http_response_code(502);
        exit;
    }
    http_response_code(curl_getinfo($ch, CURLINFO_RESPONSE_CODE));
    header('Content-Type: ' . (curl_getinfo($ch, CURLINFO_CONTENT_TYPE) ?: 'application/octet-stream'));
    header('Cache-Control: ' . ($isScript ? 'public, max-age=3600' : 'no-store'));
    echo $body;
  2. Map /a/script and /a/event to it

    On Apache, add this to the .htaccess in the same folder:

    .htaccess
    # .htaccess · Apache with mod_rewrite: serve a.php at /a/script and /a/event
    RewriteEngine On
    RewriteRule ^a/(script|event)$ a.php?kind=$1 [L,QSA]

    Can't use rewrites? Skip this step and use this tag instead of the one below:

    index.html
    <script
      defer
      src="/a.php?kind=script"
      data-api="/a.php?kind=event"
      data-site-id="YOUR_SITE_ID"
    ></script>
  3. 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.

    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).
  • On WordPress, Laravel or another framework, prefer its own routing; see Laravel.

How the proxy works and which headers it must send: Use your own domain.

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.