Docs·Usage
Proxy guide
Ad blockers and privacy browsers stop requests to known analytics services, so some of your visitors
are never counted. A proxy on your own domain makes the script's requests look like requests to your
own site, which gets many of them through. This page explains what the api_host option moves and what
it does not, what a proxy costs you, two setups that work, and how to check yours.
Read What you give up before you build anything. For some sites the costs outweigh the visitors you gain.
Why visitors with blockers go missing
Blockers work from filter lists: lists of hostnames and address patterns that belong to ads and analytics. When a request matches, the browser cancels it before it leaves, so nothing reaches Spreelytics and, as far as your numbers are concerned, the visit never happened. How many visitors this affects depends on who your visitors are. Technical audiences tend to use blockers more.
What api_host moves, and what it does not
Spreelytics.init({
client_key: "YOUR_CLIENT_KEY",
api_host: "https://www.example.com/sp",
});
With api_host set, every request the script sends goes to that address instead of
https://sdk.spreelytics.com/1.0, with the same path on the end: https://www.example.com/sp/track/page,
https://www.example.com/sp/track/event and so on. That covers the cookieless check, the install
signal, pageviews, events, the end of each visit, pings and identify().
It does not move the script files. The loader comes from
https://cdn.spreelytics.com/cdn/sdk/spreelytics-loader.js, and the loader always fetches the main script
from that same host. That address is built into the loader, so serving the loader from your own
domain does not change it. A blocker that blocks that host stops the script before api_host can
help.
What you give up
Locations. Country, region, city, time zone and the position on the map all come from the network
address that connects to Spreelytics's edge. Behind a proxy, that is your proxy's address, so every
visitor appears to be wherever the proxy is. The location breakdowns, the map, the Realtime globe and
country filters all show the proxy, not your visitors. Sending an X-Forwarded-For header does not
help, because Spreelytics ignores it on purpose: anyone can write that header.
Data-center traffic is dropped. Requests from the IPv4 address ranges of AWS, Google Cloud, Oracle
Cloud, DigitalOcean and Linode are dropped as data-center traffic. Behind a proxy, every request comes
from the proxy, so a proxy running on one of these networks has all of its traffic dropped. That
includes a proxy on Vercel, which runs on AWS, and one on an EC2 instance, a Google Cloud virtual
machine, a DigitalOcean droplet or a Linode server. The requests still return 200, and nothing is
recorded. Providers that are not on the list, such as Hetzner, OVH, Azure or Cloudflare, pass the
check.
No cookieless tracking. On a cookieless audience, Spreelytics recognises visitors by a hash that includes their network address. Behind a proxy every visitor shares the proxy's address, so everyone on the same browser would count as one person. The cookieless dialog in Settings → Tracking script warns about this. Do not combine the two (see Cookieless tracking).
What keeps working: the device type, browser and operating system come from the User-Agent header, so
they stay right as long as the proxy passes it through. Pages, referrers, UTM tags, channels, events,
goals, revenue and identified people are all carried inside the requests, and are not affected.
What every proxy has to do
- Forward every request under your path to
https://sdk.spreelytics.com/1.0/, keeping the rest of the path and the query string, for every method the script uses:GET,POST,PUTandOPTIONS. - Connect to the upstream as
sdk.spreelytics.com, both in theHostheader and in the TLS handshake (SNI). - Pass the
User-Agentheader through unchanged. If the proxy sends its own instead, requests can be dropped as coming from a tool or library, and the browser, operating system and device are lost. - If the audience uses Allowed domains, pass the
OriginandRefererheaders through unchanged. Spreelytics reads the page's hostname from them. - Pass the request body through unchanged.
- Do not forward your site's cookies. When the proxy is on your own domain, the browser attaches your
site's cookies to the script's requests, login cookies included. Spreelytics does not need them, so
strip the
Cookieheader.
Pick a path that nothing else on your site uses, such as /sp. Avoid names with "analytics" or
"tracking" in them, which filter lists also look for.
nginx
On a server you run yourself, outside the networks listed above:
location /sp/ {
proxy_pass https://sdk.spreelytics.com/1.0/;
proxy_set_header Host sdk.spreelytics.com;
proxy_ssl_server_name on;
proxy_set_header Cookie "";
}
- The trailing slashes matter. They make nginx replace
/sp/with/1.0/, so/sp/track/pagegoes tohttps://sdk.spreelytics.com/1.0/track/page. proxy_ssl_server_name onmakes nginx send the hostname in the TLS handshake (SNI), whichsdk.spreelytics.comneeds. nginx leaves it out by default.proxy_set_header Cookie ""stops nginx from forwarding your site's cookies.- nginx passes
User-Agent,OriginandRefererthrough by default, so leave them alone.
Then set api_host: "https://www.example.com/sp", with your own domain.
Cloudflare Worker
Cloudflare's network is not on the data-center list, so requests from a Worker are kept. Locations then show Cloudflare's network rather than your visitors.
export default {
async fetch(request) {
const url = new URL(request.url);
const upstream = new URL(
url.pathname.replace(/^\/sp/, "/1.0") + url.search,
"https://sdk.spreelytics.com",
);
const proxied = new Request(upstream, request);
proxied.headers.delete("Cookie");
return fetch(proxied);
},
};
Give the Worker a route such as www.example.com/sp/*, so that only the script's requests reach it,
and set api_host: "https://www.example.com/sp". The Worker keeps the method, the body and the other
headers of each request, User-Agent, Origin and Referer included.
Other proxies and framework rewrites
Any reverse proxy, or a rewrite rule in your framework or hosting platform, works the same way as long as it does everything listed above. Check where it runs: a rewrite runs on your host's servers, and on a host that runs on AWS, Google Cloud, Oracle Cloud, DigitalOcean or Linode, Vercel included, every proxied request is dropped.
Checking that it works
- Deploy the proxy, set
api_host, and load a page of your site with the browser's Network tab open. - Filter by your path, for example
/sp/. You should seetrack/config,track/heartbeatandtrack/pagegoing to your own domain with status200, and no requests tosdk.spreelytics.com. The two script files still come fromcdn.spreelytics.com. - In Spreelytics, open or reload Settings → Tracking script. It should say "Last seen just now".
- Open Realtime. You should appear within a minute, placed where your proxy is rather than where you are. That is expected.
If the requests return 200 but "Last seen" does not move and Realtime stays empty, the proxy is
almost certainly on a data-center network: move it. A 401 means the key is wrong, the Origin and
Referer headers did not arrive, or your hostname is not in Allowed domains. A 400 means the proxy
changed the request. Any other error usually means the path, the Host header or the TLS hostname is
not set as described above.
Related
- Troubleshooting: read the requests and their status codes.
- Cookieless tracking: why a proxy and cookieless mode do not mix.
- JavaScript SDK:
api_hostand the other options. - Tracking script: Allowed domains and Content Security Policy.