twelvebitDocsllms.txtSign in
View as Markdown

Proxy the script through your domain

Some ad blockers block analytics scripts from other domains. When you serve the script and the event endpoint from your own domain, more visits are counted.

You need two routes on your domain:

Your pathGoes to
/tb/script.jshttps://twelvebit.app/js/script.js
/tb/ehttps://twelvebit.app/api/e

Then change the script tag. data-api is required: without it, the script sends events to /api/e on the script's origin, which is now your site.

html
<script defer data-website-id="tb_YOUR_SITE_ID" data-domain="example.com" data-api="/tb/e" src="/tb/script.js"></script>

Pick neutral paths. Paths with "analytics" or "tracking" in them are more likely to be blocked.

Next.js#

ts
// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  async rewrites() {
    return [
      { source: "/tb/script.js", destination: "https://twelvebit.app/js/script.js" },
      { source: "/tb/e", destination: "https://twelvebit.app/api/e" },
    ];
  },
};

export default nextConfig;

With next/script, use src="/tb/script.js" and add data-api="/tb/e".

Vercel (any framework)#

json
{
  "rewrites": [
    { "source": "/tb/script.js", "destination": "https://twelvebit.app/js/script.js" },
    { "source": "/tb/e", "destination": "https://twelvebit.app/api/e" }
  ]
}

Put this in vercel.json in the project root.

Netlify#

text
# public/_redirects (or the publish folder)
/tb/script.js  https://twelvebit.app/js/script.js  200
/tb/e          https://twelvebit.app/api/e  200

Status 200 makes Netlify proxy the request instead of redirecting it.

Cloudflare Workers#

Add a route for example.com/tb/* to this Worker:

js
// worker.js
const UPSTREAM = { "/tb/script.js": "https://twelvebit.app/js/script.js", "/tb/e": "https://twelvebit.app/api/e" };

export default {
  async fetch(request) {
    const target = UPSTREAM[new URL(request.url).pathname];
    if (!target) return fetch(request);
    const headers = new Headers();
    headers.set("User-Agent", request.headers.get("User-Agent") ?? "");
    headers.set("Content-Type", request.headers.get("Content-Type") ?? "text/plain");
    const ip = request.headers.get("CF-Connecting-IP");
    if (ip) headers.set("X-Forwarded-For", ip);
    return fetch(target, {
      method: request.method,
      headers,
      body: request.method === "POST" ? await request.text() : undefined,
    });
  },
};

Visitor location behind a proxy#

Forward these headers when your proxy lets you:

  • User-Agent: always. twelvebit uses it for the browser, the device and bot filtering.
  • X-Forwarded-For (or X-Real-IP) with the visitor's IP address. twelvebit uses the first address for IP exclusions and for the cookieless daily hash.

Country, region and city come from the location headers that the network edge in front of twelvebit adds, based on the address that connects to it. Behind a proxy, that address can be your proxy server, and some edges replace forwarded IP headers with the connecting address. Then every visitor shows the location of your proxy, IP exclusions do not match, and in cookieless mode many visitors can merge into one.

Check after you set up the proxy: open the Live view and look at your own visit. If it shows your city, the proxy forwards enough. If every visit shows the same city, load the script directly from https://twelvebit.app (location works there) or accept less precise location data.

Content Security Policy#

With a proxy, the script and the requests are same-origin, so script-src 'self' and connect-src 'self' are enough. Without a proxy, add https://twelvebit.app to both.