Proxying Flowsery Analytics with Nginx
Route Flowsery Analytics through Nginx to prevent adblocker interference and capture accurate visitor data. This guide applies to standalone Nginx and Nginx as a reverse proxy in front of an application server.
The setup has two essentials — a proxy_pass that makes events first-party (adblock-safe), and a proxy_set_header x-flowsery-real-ip that carries the real visitor IP through the proxy hop so Flowsery resolves geo from the visitor rather than from your server.
1. Core Nginx Configuration
Add these location blocks (typically in /etc/nginx/sites-available/your-site or /etc/nginx/conf.d/your-site.conf):
# Proxy the analytics script
location /js/main.js {
proxy_pass https://cdn.flowsery.com/main.js;
proxy_set_header Host cdn.flowsery.com;
# Cache the script for 1 year
proxy_cache_valid 200 1y;
add_header Cache-Control "public, max-age=31536000";
expires 1y;
}
# Proxy the event collection endpoint + forward real visitor IP
location /api/track {
proxy_pass https://analytics.flowsery.com/analytics/events;
proxy_set_header Host analytics.flowsery.com;
# CRITICAL: forwards the real visitor IP to the analytics backend.
# Without this, every visitor resolves to your server's location.
proxy_set_header x-flowsery-real-ip $remote_addr;
# Standard forwarding (kept for compatibility with other consumers)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
# Allow POST requests
proxy_pass_request_body on;
}If you run Nginx behind Cloudflare (or another edge), $remote_addr is the CDN edge IP, not the visitor. Use the CDN's real-IP header instead:
# Behind Cloudflare — the visitor IP is in $http_cf_connecting_ip
proxy_set_header x-flowsery-real-ip $http_cf_connecting_ip;
# Behind Vercel / Fly.io / a generic L7 proxy
# proxy_set_header x-flowsery-real-ip $http_x_real_ip;Note: If your server already serves /api/track, pick another path and tell the tracker with data-api="/flowsery-events".
2. Optional: Enable Caching for the Script
# At the top of your nginx.conf (http {} block)
proxy_cache_path /var/cache/nginx/flowsery_cache levels=1:2 keys_zone=flowsery_cache:10m max_size=10g inactive=60m use_temp_path=off;
# In your server {} block, augment the /js/main.js location
location /js/main.js {
proxy_cache flowsery_cache;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_valid 200 1y;
proxy_cache_bypass $http_pragma;
proxy_cache_revalidate on;
# ...rest of the config from step 1
}3. Modify the Script Tag
Replace the Flowsery Analytics snippet with the proxied version:
<script defer data-fl-website-id="flid_******" src="/js/main.js"></script>sudo nginx -t # validate config
sudo systemctl reload nginxConfirming It Works
- Open your site in a regular browser tab.
- DevTools → Network, filter for
/api/track. Confirm requests go to your own domain. - In your Flowsery dashboard, check that visitor countries reflect your audience, not your hosting region.
Troubleshooting
Every visitor appears from the same location
The proxy is forwarding events but not the real visitor IP. x-flowsery-real-ip is either missing or carrying your server's IP instead of the visitor's.
- Confirm the
proxy_set_header x-flowsery-real-ip <value>line is present on/api/trackand the value references the correct variable for your edge setup ($remote_addrfor direct traffic,$http_cf_connecting_ipfor Cloudflare,$http_x_real_ipfor a generic L7 edge). - If Nginx sits behind another proxy, don't use
$remote_addr— that's the upstream proxy, not the visitor. Use the header the upstream proxy injects.