Self-host le tracker (anti-blocage)
Chrome 121+, uBlock Origin, Brave Shields, AdGuard et la plupart des bloqueurs publicitaires bloquent par défaut les requêtes vers tout domaine tiers étiqueté « analytics », même quand le service ne fait aucun tracking publicitaire (c'est notre cas).
Sans rien faire, vous perdez aujourd'hui 5 à 20 % des sessions, et la part montera à 30-50 % d'ici 12 à 24 mois quand Chrome appliquera la _Tracking Protection_ à toutes les sessions normales (pas seulement la navigation privée).
La solution : servir le tracker et l'API depuis votre propre domaine. Le navigateur voit alors une requête « 1st-party » indistinguable d'un appel à une image ou une feuille de style. Aucun bloqueur ne bloque ça.
Cette page documente comment le faire avec des configurations 1st-party compatibles avec une approche d'infrastructure européenne. Choisissez l'hébergeur et la région d'exécution selon vos besoins de conformité, de performance et de support.
Comment ça marche, schéma général
┌──────────────────────────────────────────────────────────────────────────┐
│ │
│ AVANT (3rd-party, bloqué) │
│ ────────────────────── │
│ │
│ navigateur ──► <script src="https://snorklee.com/w.js"> │
│ ❌ ERR_BLOCKED_BY_CLIENT │
│ │
│ navigateur ──► POST https://snorklee.com/api/event │
│ ❌ ERR_BLOCKED_BY_CLIENT │
│ │
└──────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────┐
│ │
│ APRÈS (1st-party via votre proxy, jamais bloqué) │
│ ──────────────────────────────────────────── │
│ │
│ navigateur ──► <script src="/js/flow.js"> sur monsite.com │
│ ✅ servi par votre proxy depuis snorklee.com │
│ │
│ navigateur ──► POST monsite.com/api/event │
│ ✅ relayé par votre proxy vers snorklee.com │
│ │
└──────────────────────────────────────────────────────────────────────────┘
Vous proxifiez le script et 4 endpoints API depuis votre domaine vers snorklee.com :
| Chemin sur votre domaine | Cible chez snorklee | Rôle |
|---|---|---|
/js/flow.js | snorklee.com/w.js | Script du tracker |
/api/event | snorklee.com/api/event | Pageviews + événements custom |
/api/ping | snorklee.com/api/ping | Heartbeat « live » toutes 30 s |
/api/zone | snorklee.com/api/zone | Zones de scroll (lecture) |
/api/click | snorklee.com/api/click | Heatmap de clics agrégée |
Le snippet à coller dans votre <head> devient :
<script defer src="/js/flow.js" data-site="monsite.com"></script>
Tous les chemins sont en 1st-party, aucun ne sort vers un domaine tiers depuis le navigateur. Côté serveur, votre proxy fait le pont avec snorklee.com de manière transparente.
Important — préservation de l'IP visiteur : votre proxy doit transmettre l'header X-Forwarded-For correctement, sinon la géolocalisation côté snorklee tombe sur l'IP de votre proxy au lieu de celle du visiteur. Chaque recette ci-dessous l'inclut explicitement.
Recette 1 — Nginx (la plus universelle)
Fonctionne sur : tout VPS Linux (OVH, Scaleway, Hetzner, Clever Cloud avec runtime Nginx, IONOS, Infomaniak, etc.).
Souveraineté : neutre (dépend de votre hébergeur ; choisissez UE).
Ajoutez ce bloc dans votre fichier de configuration Nginx, à l'intérieur du server { ... } qui sert votre site (typiquement /etc/nginx/sites-available/monsite.conf) :
# snorklee — proxy 1st-party (anti-blocage)
location = /js/flow.js {
proxy_pass https://snorklee.com/w.js;
proxy_set_header Host snorklee.com;
proxy_ssl_server_name on;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept-Language $http_accept_language;
proxy_hide_header Set-Cookie;
proxy_read_timeout 10s;
}
location ~ ^/api/(event|ping|zone|click)$ {
proxy_pass https://snorklee.com$request_uri;
proxy_set_header Host snorklee.com;
proxy_ssl_server_name on;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept-Language $http_accept_language;
proxy_set_header Origin $http_origin;
proxy_hide_header Set-Cookie;
proxy_read_timeout 10s;
}
Puis testez et rechargez :
sudo nginx -t && sudo systemctl reload nginx
Vérification : depuis votre navigateur, ouvrez https://monsite.com/js/flow.js — vous devez voir le code du tracker minifié. Si erreur 502, vérifiez que proxy_ssl_server_name on; est bien présent (obligatoire pour le SNI vers snorklee.com).
Recette 2 — Caddy (la plus simple)
Fonctionne sur : tout serveur où Caddy tourne (auto-TLS inclus).
Souveraineté : neutre (dépend de votre hébergeur).
Dans votre Caddyfile, à l'intérieur du bloc de votre site :
monsite.com {
# ... votre config existante ...
# snorklee — proxy 1st-party (anti-blocage)
@snorkleeApi path /api/event /api/ping /api/zone /api/click
handle_path /js/flow.js {
rewrite * /w.js
reverse_proxy https://snorklee.com {
header_up Host snorklee.com
header_down -Set-Cookie
}
}
handle @snorkleeApi {
reverse_proxy https://snorklee.com {
header_up Host snorklee.com
header_down -Set-Cookie
}
}
}
Puis :
caddy reload --config /etc/caddy/Caddyfile
Syntaxe Caddy 2.6+ : on utilise un matcher nommé (@snorkleeApi path …) pour appliquerhandleà plusieurs chemins. La formehandle /a /b /c { … }n'est pas acceptée par le parser et fait échouercaddy validate.
Caddy injecteX-Forwarded-ForetX-Real-IPautomatiquement, c'est pourquoi on n'a pas besoin de les déclarer explicitement comme avec Nginx.
Recette 3 — Apache (mod_proxy)
Fonctionne sur : hébergement mutualisé OVH, Infomaniak, IONOS, et tout serveur Apache avec mod_proxy activé. Utile pour les sites WordPress sur cPanel sans accès root.
Souveraineté : neutre.
Dans votre .htaccess (à la racine du site) ou <VirtualHost> :
# snorklee — proxy 1st-party (anti-blocage)
SSLProxyEngine On
# Le script
RewriteEngine On
RewriteRule ^js/flow\.js$ https://snorklee.com/w.js [P,L]
# L'API
RewriteRule ^api/(event|ping|zone|click)$ https://snorklee.com/api/$1 [P,L]
# Préserver l'IP visiteur (setifempty pour ne pas écraser un XFF amont
# si vous êtes derrière un autre LB/reverse-proxy qui en pose déjà un)
ProxyPreserveHost Off
RequestHeader setifempty X-Forwarded-For "%{REMOTE_ADDR}s"
RequestHeader setifempty X-Real-IP "%{REMOTE_ADDR}s"
# Ne jamais transmettre de cookie de session côté visiteur
Header always unset Set-Cookie
Modules à activer sur le serveur (typiquement déjà actifs sur les hébergeurs FR sérieux) : mod_proxy, mod_proxy_http, mod_ssl, mod_rewrite, mod_headers.
Sur OVH mutualisé, demandez l'activation à votre support si nécessaire — c'est gratuit et standard.
Recette 4 — Bunny.net Edge Scripting
Pour qui : sites à fort trafic qui veulent un CDN edge plus proche du visiteur (gain de latence + offload du serveur d'origine).
Implantation européenne : Bunny.net est édité par BunnyWay d.o.o. en Slovénie. Si vous voulez garder le routage au plus près de l'Europe, limitez les zones de pricing à Europe lors de la configuration.
Pricing : ~0,01 €/million de requêtes Edge Script + ~0,005 €/GB de bande passante CDN. Pour 1M pageviews/mois, comptez ~5 € total. Pas d'abonnement minimum, paiement à l'usage.
Étapes :
- Créer un compte sur bunny.net (carte bancaire, ~5 € de crédit initial gratuit).
- Créer une « Pull Zone » :
- Onglet _CDN_ → bouton _Add Pull Zone_
- Name :
monsite-snorklee(libre) - Origin URL :
https://snorklee.com - Pricing tier : Standard
- Pricing zones : vous pouvez ne garder que Europe si vous voulez limiter le routage et les coûts à cette zone
- Connecter votre domaine en CNAME :
- Onglet _Hostnames_ → _Add Hostname_ →
flow.monsite.com - Chez votre registrar DNS (Gandi, OVH, etc.) : créer un enregistrement
CNAME flow.monsite.com → monsite-snorklee.b-cdn.net - Attendez 5 min, retournez sur Bunny → cliquez _Generate Free SSL Certificate_ (Let's Encrypt automatique)
- Mapper le chemin :
- Onglet _Edge Rules_ → _Add Edge Rule_
- Action : _Override URL_
- Match :
Request URL contains "/js/flow.js" - Override URL :
https://snorklee.com/w.js - Sauvegardez
- Snippet final :
<script defer src="https://flow.monsite.com/js/flow.js" data-site="monsite.com"></script>
Tous les /api/* passent automatiquement vers snorklee.com/api/* via la Pull Zone.
Note IP visiteur : Bunny ajoute par défaut X-Forwarded-For correctement. Vérifiez dans le dashboard snorklee, onglet Analytics (section Audience, carte Pays), que les pays remontent bien après 1-2 heures.
Recette 5 — Next.js / Nuxt rewrites
Pour qui : sites en stack moderne JavaScript dont l'hébergeur supporte les rewrites ou routes serveur.
Hébergement : vérifiez que votre plateforme conserve les headers utiles (X-Forwarded-For, méthode HTTP, User-Agent, Accept-Language) et que la région d'exécution choisie correspond à vos besoins de confidentialité et de performance.
Exemples possibles : hébergement Node/SSR classique, serverless avec région explicite, container Docker ou plateforme frontend qui expose des rewrites côté serveur.
Next.js — dans next.config.js :
module.exports = {
async rewrites() {
return [
{
source: '/js/flow.js',
destination: 'https://snorklee.com/w.js',
},
{
source: '/api/event',
destination: 'https://snorklee.com/api/event',
},
{
source: '/api/ping',
destination: 'https://snorklee.com/api/ping',
},
{
source: '/api/zone',
destination: 'https://snorklee.com/api/zone',
},
{
source: '/api/click',
destination: 'https://snorklee.com/api/click',
},
];
},
};
Nuxt 3 — dans nuxt.config.ts :
export default defineNuxtConfig({
routeRules: {
'/js/flow.js': { proxy: 'https://snorklee.com/w.js' },
'/api/event': { proxy: 'https://snorklee.com/api/event' },
'/api/ping': { proxy: 'https://snorklee.com/api/ping' },
'/api/zone': { proxy: 'https://snorklee.com/api/zone' },
'/api/click': { proxy: 'https://snorklee.com/api/click' },
},
});
Les rewrites Next/Nuxt préservent automatiquement X-Forwarded-For et la méthode HTTP. Les events POST passent correctement.
Choisir son hébergeur
Le proxy 1st-party fonctionne avec beaucoup d'hébergeurs. Avant de choisir une plateforme, vérifiez surtout :
- la région d'exécution réellement utilisée par le proxy ;
- la durée de conservation des logs côté hébergeur ;
- la transmission correcte de
X-Forwarded-For; - la possibilité de retirer les cookies ou headers inutiles ;
- les engagements contractuels dont vous avez besoin pour votre propre politique privacy.
Vérifier que ça marche
- Le script se charge — ouvrez
https://monsite.com/js/flow.jsdans votre navigateur, vous devez voir le code minifié du tracker (commence par!function()...). - Les events partent — ouvrez DevTools (F12) → onglet _Network_, cliquez sur une page de votre site. Vous devez voir une requête
POST /api/eventqui répond204 No Content. - La géolocalisation marche — connectez-vous au dashboard snorklee, attendez 1-2 minutes, et vérifiez la carte _Pays_ de l'onglet _Analytics_ (section Audience). Si tous les visiteurs remontent depuis le pays de votre serveur proxy au lieu de leur vrai pays, c'est que
X-Forwarded-Forn'est pas transmis. Revoir la conf du proxy. - Le tracker dans l'onglet Intégration du dashboard — la sonde HTTP « Tester l'installation » détecte automatiquement le mode self-host et indique _« Proxy 1st-party détecté »_ dans le résultat.
Foire aux questions
Le proxy ralentit-il mon site ? Non, ou marginalement. Le tracker flow.js pèse ≈ 2 KB gzip et reste en cache navigateur. Les events /api/* partent en sendBeacon non-bloquant, donc invisible pour le visiteur même si le proxy ajoute 50 ms de latence.
Et si mon proxy tombe en panne ? Les events sont perdus pendant la panne (pas de queue offline, par doctrine §25 TDDDG / RGPD minimisation). Le site continue de fonctionner normalement, c'est juste la mesure d'audience qui s'arrête. Comme tout autre service tiers en panne (Google Analytics, Plausible, etc.).
Puis-je proxifier seulement le script et pas l'API ? Oui, avec l'attribut data-api :
<script defer src="/js/flow.js" data-site="monsite.com" data-api="https://snorklee.com"></script>
Le script est servi en 1st-party (passe les bloqueurs basés sur le nom de fichier), mais les events partent vers snorklee.com directement (re-bloqués par les bloqueurs basés sur le domaine). C'est moins efficace que la recette complète et nous ne le recommandons pas — c'est documenté ici pour des cas particuliers.
Et si je veux changer de fournisseur d'analytics plus tard ? La doc proxy reste la même structure, vous changez juste les domaines cibles. Le snippet <script src="/js/flow.js" data-site="..."> est universel.
Besoin d'aide ?
- 🛠️ Onglet _Intégration_ du dashboard → bouton _Tester l'installation_ (sonde HTTP automatique)
- 📧 Contact protection des données/support : voir l'onglet _Conformité_ du dashboard
- 📚 Documentation complète : /docs