Suivi
Proxy (first-party)
Servez le tracker et l’endpoint de collecte depuis votre propre domaine avec Next.js, vercel.json, nginx, Caddy ou un Cloudflare Worker.
Les bloqueurs de publicités et les extensions de confidentialité bloquent souvent les requêtes vers les hôtes d’analytique tiers. Servir le script et l’endpoint de collecte depuis votre propre domaine rend Globatics first-party par construction : le navigateur ne parle qu’à votre site.
Pourquoi un proxy
- Moins de visites bloquées, donc des chiffres plus proches de la réalité. Combien dépend de votre audience.
- Un hôte tiers de moins dans votre Content Security Policy.
- Passez trois chemins par le proxy :
script.js,vitals.js(chargé depuis le même dossier que le script) etapi/collect. Puis faites pointer la balise vers eux :
<script defer data-site="SITE_ID" data-api="/_glb/api/collect" src="/_glb/script.js"></script>data-api est obligatoire
Sans data-api, le tracker envoie ses requêtes à /api/collect sur l’origine d’où il a été chargé, c’est-à-dire désormais votre propre site. Gardez l’attribut et utilisez un préfixe neutre comme /_glb : les bloqueurs ciblent les chemins et sous-domaines nommés « analytics », « tracking » ou « telemetry ».
Rewrites Next.js
import type { NextConfig } from "next";
const GLOBATICS = "https://globatics.live";
const nextConfig: NextConfig = {
async rewrites() {
return [
{ source: "/_glb/script.js", destination: `${GLOBATICS}/script.js` },
{ source: "/_glb/vitals.js", destination: `${GLOBATICS}/vitals.js` },
{ source: "/_glb/api/collect", destination: `${GLOBATICS}/api/collect` },
];
},
};
export default nextConfig;Les rewrites ne peuvent pas ajouter d’en-tête : que l’adresse du visiteur parvienne ou non à Globatics dépend donc de votre hébergeur (voir Transmettre l’IP du visiteur). Vérifiez une fois : ouvrez le direct, puis visitez votre site depuis votre téléphone en données mobiles. Si vous apparaissez dans la région de votre hébergeur au lieu de votre ville, gardez les deux rewrites du script et servez l’endpoint de collecte avec un route handler qui transmet l’adresse :
// "%5Fglb" est "_glb" encodé pour l'URL : les dossiers commençant par "_" sont privés dans l'App Router.
const GLOBATICS = "https://globatics.live";
export async function POST(req: Request) {
// sur Vercel, la première entrée de X-Forwarded-For est le visiteur
const ip = (req.headers.get("x-forwarded-for") ?? "").split(",")[0].trim();
const res = await fetch(`${GLOBATICS}/api/collect`, {
method: "POST",
body: await req.text(),
headers: {
"content-type": "text/plain",
"user-agent": req.headers.get("user-agent") ?? "",
"x-globatics-ip": ip,
// quel site a envoyé le hit : c'est ce qui valide l'installation
origin: req.headers.get("origin") ?? "",
"x-forwarded-host": new URL(req.url).host,
},
});
return new Response(null, { status: res.status });
}Il en va de même pour les rewrites vercel.json des autres frameworks hébergés sur Vercel : mêmes trois paires source et destination, même vérification.
nginx
location = /_glb/script.js { proxy_pass https://globatics.live/script.js; include globatics.conf; }
location = /_glb/vitals.js { proxy_pass https://globatics.live/vitals.js; include globatics.conf; }
location = /_glb/api/collect { proxy_pass https://globatics.live/api/collect; include globatics.conf; }
# /etc/nginx/globatics.conf
proxy_set_header Host globatics.live;
proxy_set_header X-Forwarded-Host $host; # votre domaine (l'en-tête Origin du navigateur passe aussi)
proxy_set_header X-Globatics-IP $remote_addr; # derrière Cloudflare : $http_cf_connecting_ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie ""; # n'envoyez jamais les cookies de votre site
proxy_ssl_server_name on;
proxy_http_version 1.1;Caddy
example.com {
# /_glb/script.js → /script.js, /_glb/api/collect → /api/collect
handle_path /_glb/* {
reverse_proxy https://globatics.live {
header_up Host {upstream_hostport}
header_up X-Globatics-IP {remote_host}
header_up -Cookie
}
}
# …le reste de votre site
}Cloudflare Worker
const UPSTREAM = "https://globatics.live";
const ALLOWED = new Set(["/script.js", "/vitals.js", "/api/collect"]);
export default {
async fetch(request) {
const path = new URL(request.url).pathname.replace(/^\/_glb/, "");
if (!ALLOWED.has(path)) return new Response("Not found", { status: 404 });
const headers = new Headers(request.headers); // conserve l'Origin du navigateur
headers.set("X-Forwarded-Host", new URL(request.url).host);
headers.set("X-Globatics-IP", request.headers.get("CF-Connecting-IP") || "");
headers.delete("Cookie");
return fetch(UPSTREAM + path, {
method: request.method,
headers,
body: request.method === "POST" ? request.body : undefined,
});
},
};Transmettre l’IP du visiteur
Globatics n’utilise l’IP du visiteur que pour trois choses : le pays et la ville, le hachage quotidien du visiteur et la protection contre les rafales. Elle n’est jamais enregistrée. Derrière un proxy, chaque requête provient de l’adresse du proxy. En l’état, chaque visiteur serait placé dans la ville de votre proxy, les visiteurs ayant la même version de navigateur pourraient être fusionnés en un seul, et tous partageraient une même limite de débit.
Envoyez l’adresse du visiteur dans X-Globatics-IP, comme le font les recettes nginx, Caddy, Worker et route handler ci-dessus. Globatics y accepte une adresse publique et la géolocalise à la place de celle du proxy. Globatics hébergé tourne sur Vercel, qui remplace X-Forwarded-For par l’adresse qui s’est connectée à lui : cet en-tête est donc la méthode fiable.
Compromis
L’en-tête ne peut pas être signé : n’importe qui peut l’envoyer. Une valeur falsifiée ne change que la localisation et le hachage de visiteur des propres hits de l’expéditeur. La protection contre les rafales s’applique toujours par adresse de connexion : un proxy dispose de 20 fois le budget d’un visiteur isolé (environ 600 requêtes par seconde par instance de serveur), et ses requêtes au-delà sont décomptées du proxy comme d’habitude.
En auto-hébergement, définissez GLOBATICS_TRUST_PROXY=1 quand votre propre proxy se trouve devant Globatics. L’adresse est alors lue dans CF-Connecting-IP, puis X-Real-IP, puis la première entrée de X-Forwarded-For. Sans cette variable, Globatics prend l’adresse publique la plus à droite, qu’un visiteur ne peut pas usurper mais qui est celle de votre proxy. X-Globatics-IP fonctionne dans les deux cas.
GLOBATICS_TRUST_PROXY=1Pour vérifier, ouvrez votre site depuis votre téléphone en données mobiles : si le direct affiche la ville de votre serveur au lieu de la vôtre, l’adresse ne parvient pas à Globatics.
Vérification de l’installation derrière un proxy
Globatics ne marque un site comme installé que lorsqu’un hit provient réellement de l’une de ses pages. Il le lit dans la requête, jamais dans l’URL contenue dans le hit : l’en-tête Origin du navigateur (votre domaine) ou, quand un proxy le supprime, l’en-tête X-Forwarded-Host du proxy. Il doit s’agir du domaine de votre site ou de l’un de ses sous-domaines. Voici ce que transmet chacune des recettes ci-dessus :
| Recette | Origin | X-Forwarded-Host | X-Globatics-IP |
|---|---|---|---|
| Rewrites Next.js, auto-hébergé (next start) | Transmis tel quel | Votre hôte (défini par Next.js) | Non |
| Rewrites Next.js ou vercel.json sur Vercel | Transmis tel quel | Non utilisé | Non |
| Route handler Next.js | Copié par la recette | Votre hôte (défini par la recette) | Oui |
| nginx | Transmis tel quel (nginx transmet les en-têtes du client) | $host (défini par la recette) | Oui |
| Caddy | Transmis tel quel | Votre hôte (défini par Caddy) | Oui |
| Cloudflare Worker | Copié avec les en-têtes de la requête | Votre hôte (défini par la recette) | Oui |
Vous écrivez votre propre proxy ? Transmettez l’en-tête Origin tel quel, ou définissez X-Forwarded-Host sur l’hôte demandé par le visiteur. Un proxy qui n’envoie ni l’un ni l’autre compte quand même les visites, mais l’installation reste non vérifiée dans Settings → Tracking.