Proxy first-party (anti-adblock)
Les domaines d’analytics connus finissent dans EasyPrivacy : 25 à 40 % des visiteurs tech sont invisibles sans proxy. La parade : servir le script et poster les événements depuis le domaine du site suivi, qui reverse-proxie vers Elvn. Quasi imblocable sans casser le site.
Principe
Section intitulée « Principe »Deux réécritures, avec des noms neutres (/stats/… par convention —
n’importe quel path neutre convient, éviter track, analytics, collect) :
GET /stats/t.js -> https://elvn.live/js/t.jsPOST /stats/e -> https://elvn.live/api/eSnippet correspondant (le dashboard le génère dans Settings → Tracking, onglet « proxy ») :
<script defer src="/stats/t.js" data-site="SITE_PUBLIC_ID" data-api="/stats/e"></script>Deux exigences côté proxy :
- Transmettre l’en-tête
Originde la requête entrante (comportement par défaut de tous les proxys ci-dessous) : le tracker envoieuen path relatif, le Worker valide alors l’origine via ce header contre le domaine déclaré du site. - Transmettre le User-Agent entrant (défaut partout) : il sert au hash visiteur et aux dimensions navigateur/OS/appareil.
Limites connues (à assumer)
Section intitulée « Limites connues (à assumer) »Le Worker de collecte lit l’IP de connexion et la géolocalisation Cloudflare de la requête qui lui parvient. Derrière un proxy serveur, c’est l’IP du serveur du site :
- les visiteurs uniques sont dégradés (tous les visiteurs partagent l’IP du proxy : ils ne sont plus distingués que par leur User-Agent) ;
- la géolocalisation affichée est celle du serveur, pas du visiteur ;
- le rate limiting (par site + IP) s’applique à l’IP du proxy, donc à tout le trafic proxifié du site.
Aucun en-tête X-Forwarded-For n’est lu (il serait falsifiable sans mécanisme
de confiance). Le proxy first-party est donc un compromis : plus de
couverture, moins de précision uniques/geo. La variante « Worker route sur la
zone du site » a exactement la même limite.
Variante nginx
Section intitulée « Variante nginx »location = /stats/t.js { proxy_pass https://elvn.live/js/t.js; proxy_set_header Host elvn.live; proxy_ssl_server_name on; proxy_ssl_name elvn.live; # cache local optionnel : le script est déjà servi avec max-age=86400 + ETag}
location = /stats/e { proxy_pass https://elvn.live/api/e; proxy_set_header Host elvn.live; proxy_ssl_server_name on; proxy_ssl_name elvn.live;}Origin et User-Agent sont transmis par défaut (nginx ne réécrit que
Host et Connection).
Variante Next.js (rewrites)
Section intitulée « Variante Next.js (rewrites) »next.config.js (ou .mjs/.ts) :
/** @type {import('next').NextConfig} */const nextConfig = { async rewrites() { return [ { source: "/stats/t.js", destination: "https://elvn.live/js/t.js" }, { source: "/stats/e", destination: "https://elvn.live/api/e" }, ]; },};
module.exports = nextConfig;Puis le snippet proxy dans le layout :
<Script defer src="/stats/t.js" data-site="SITE_PUBLIC_ID" data-api="/stats/e" />(ou une balise <script> classique dans app/layout.tsx / _document.tsx.)
Variante Worker route (site déjà sur une zone Cloudflare)
Section intitulée « Variante Worker route (site déjà sur une zone Cloudflare) »Un petit Worker déployé sur la zone du site suivi, avec la route
www.exemple.fr/stats/* :
// stats-proxy — Worker sur la zone du site suiviexport default { async fetch(request) { const url = new URL(request.url);
if (request.method === "GET" && url.pathname === "/stats/t.js") { return fetch("https://elvn.live/js/t.js", { headers: { "User-Agent": request.headers.get("User-Agent") ?? "" }, cf: { cacheTtl: 86400, cacheEverything: true }, }); }
if (request.method === "POST" && url.pathname === "/stats/e") { // Transmet le body et les en-têtes entrants (Origin, User-Agent, Sec-GPC…) return fetch("https://elvn.live/api/e", { method: "POST", headers: request.headers, body: request.body, }); }
return new Response(null, { status: 404 }); },};wrangler.jsonc du proxy :
{ "name": "stats-proxy", "main": "src/index.js", "compatibility_date": "2026-07-01", "routes": [{ "pattern": "www.exemple.fr/stats/*", "zone_name": "exemple.fr" }],}Variante Caddy
Section intitulée « Variante Caddy »exemple.fr { handle /stats/t.js { rewrite * /js/t.js reverse_proxy https://elvn.live { header_up Host elvn.live } } handle /stats/e { rewrite * /api/e reverse_proxy https://elvn.live { header_up Host elvn.live } } # ... reste du site}Vérifier que le proxy fonctionne
Section intitulée « Vérifier que le proxy fonctionne »# le script doit revenir en 200 avec un ETagcurl -sI https://www.exemple.fr/stats/t.js | head -5
# l'endpoint doit répondre 202 (même pour un payload vide : réponse silencieuse par design)curl -s -o /dev/null -w "%{http_code}\n" -X POST https://www.exemple.fr/stats/e --data '{}'Puis visiter le site : la page Settings → Tracking du dashboard passe au vert à la réception du premier événement.