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 faire avec des outils strictement souverains UE. Aucune des recettes ci-dessous ne dépend d'un fournisseur soumis au _Cloud Act_ américain.
Comment ça marche, schéma général
┌──────────────────────────────────────────────────────────────────────────┐
│ │
│ AVANT (3rd-party, bloqué) │
│ ────────────────────── │
│ │
│ navigateur ──► <script src="https://wheremyflow.com/w.js"> │
│ ❌ ERR_BLOCKED_BY_CLIENT │
│ │
│ navigateur ──► POST https://wheremyflow.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 wheremyflow.com │
│ │
│ navigateur ──► POST monsite.com/api/event │
│ ✅ relayé par votre proxy vers wheremyflow.com │
│ │
└──────────────────────────────────────────────────────────────────────────┘
Vous proxifiez 3 endpoints depuis votre domaine vers wheremyflow.com :
| Chemin sur votre domaine | Cible chez wheremyflow | Rôle | | ------------------------ | --------------------------- | ------------------------------ | | /js/flow.js | wheremyflow.com/w.js | Script du tracker | | /api/event | wheremyflow.com/api/event | Pageviews + événements custom | | /api/ping | wheremyflow.com/api/ping | Heartbeat « live » toutes 30 s | | /api/zone | wheremyflow.com/api/zone | Zones de scroll (lecture) |
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 wheremyflow.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é wheremyflow 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) :
# wheremyflow — proxy 1st-party (anti-blocage)
location = /js/flow.js {
proxy_pass https://wheremyflow.com/w.js;
proxy_set_header Host wheremyflow.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)$ {
proxy_pass https://wheremyflow.com$request_uri;
proxy_set_header Host wheremyflow.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 wheremyflow.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 ...
# wheremyflow — proxy 1st-party (anti-blocage)
@wmfApi path /api/event /api/ping /api/zone
handle_path /js/flow.js {
rewrite * /w.js
reverse_proxy https://wheremyflow.com {
header_up Host wheremyflow.com
header_down -Set-Cookie
}
}
handle @wmfApi {
reverse_proxy https://wheremyflow.com {
header_up Host wheremyflow.com
header_down -Set-Cookie
}
}
}
Puis :
caddy reload --config /etc/caddy/Caddyfile
Syntaxe Caddy 2.6+ : on utilise un matcher nommé (@wmfApi 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> :
# wheremyflow — proxy 1st-party (anti-blocage)
SSLProxyEngine On
# Le script
RewriteEngine On
RewriteRule ^js/flow\.js$ https://wheremyflow.com/w.js [P,L]
# L'API
RewriteRule ^api/(event|ping|zone)$ https://wheremyflow.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 🇸🇮 (CDN souverain UE)
Pour qui : sites à fort trafic qui veulent un CDN edge plus proche du visiteur (gain de latence + offload du serveur d'origine).
Souveraineté : 🇸🇮 Slovénie / Union européenne. Bunny.net (entreprise BunnyWay d.o.o., siège Maribor) est soumis au RGPD européen. Pas de Cloud Act US. Édité par une équipe slovène, opéré sur 119+ PoPs dont 30+ en UE.
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-wmf(libre) - Origin URL :
https://wheremyflow.com - Pricing tier : Standard
- Pricing zones : décocher Asie + Amériques + Océanie, ne garder que Europe (souveraineté + coût réduit)
- 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-wmf.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://wheremyflow.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 wheremyflow.com/api/* via la Pull Zone.
Note IP visiteur : Bunny ajoute par défaut X-Forwarded-For correctement. Vérifiez dans le dashboard wheremyflow > Audience > Géo que les pays remontent bien après 1-2 heures.
Recette 5 — Next.js / Nuxt rewrites
Pour qui : sites en stack moderne JavaScript déployés sur un hébergeur européen.
⚠️ Hébergement : ne déployez pas sur Vercel, Netlify, AWS, ou Fastly (entreprises américaines, soumises au Cloud Act). Préférez :
- Clever Cloud 🇫🇷 (Paris)
- Scaleway Serverless Functions 🇫🇷 (Paris/Amsterdam)
- OVHcloud 🇫🇷
- Render.com — région Frankfurt 🇩🇪 (à confirmer selon vos besoins légaux ; siège US donc moins safe que les précédents)
- Auto-hébergement Docker sur un VPS UE
Next.js — dans next.config.js :
module.exports = {
async rewrites() {
return [
{
source: '/js/flow.js',
destination: 'https://wheremyflow.com/w.js',
},
{
source: '/api/event',
destination: 'https://wheremyflow.com/api/event',
},
{
source: '/api/ping',
destination: 'https://wheremyflow.com/api/ping',
},
{
source: '/api/zone',
destination: 'https://wheremyflow.com/api/zone',
},
];
},
};
Nuxt 3 — dans nuxt.config.ts :
export default defineNuxtConfig({
routeRules: {
'/js/flow.js': { proxy: 'https://wheremyflow.com/w.js' },
'/api/event': { proxy: 'https://wheremyflow.com/api/event' },
'/api/ping': { proxy: 'https://wheremyflow.com/api/ping' },
'/api/zone': { proxy: 'https://wheremyflow.com/api/zone' },
},
});
Les rewrites Next/Nuxt préservent automatiquement X-Forwarded-For et la méthode HTTP. Les events POST passent correctement.
Hébergeurs et services explicitement déconseillés
Pour rester cohérent avec notre engagement souverain, n'utilisez pas :
| Service | Pays / siège | Pourquoi non | | ---------------------- | ---------------- | ---------------------------------------------------------------- | | Cloudflare Workers | 🇺🇸 San Francisco | Cloud Act US, obligation de coopérer avec gouvernement américain | | Vercel | 🇺🇸 San Francisco | Idem, infra principalement AWS US | | Netlify | 🇺🇸 San Francisco | Idem | | AWS CloudFront | 🇺🇸 Seattle | Cloud Act, FISA 702 | | Fastly | 🇺🇸 San Francisco | Idem | | Akamai | 🇺🇸 Cambridge MA | Idem |
Ces services peuvent être contraints par décision judiciaire américaine de transmettre les données proxifiées à l'administration US, même quand le serveur physique est situé en Europe (jurisprudence post-Schrems II / invalidation du Privacy Shield, juillet 2020). Pour un produit qui se vend comme « strictement souverain UE », cela ferait perdre votre argument commercial.
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 wheremyflow, attendez 1-2 minutes, et vérifiez l'onglet _Audience_ > _Géo_. 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.21 KB gzip (1.96 KB brotli) 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://wheremyflow.com"></script>
Le script est servi en 1st-party (passe les bloqueurs basés sur le nom de fichier), mais les events partent vers wheremyflow.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 DPO/support : voir l'onglet _Conformité_ du dashboard
- 📚 Documentation complète : /docs