First-party proxy
A first-party proxy lets your website load PureStats from your own domain instead of loading the script directly from purestats.io.
Use this when you want the browser Network panel, CSP and deployment checks to use your own origin, for example:
<script
defer
src="https://example.com/pf.min.js"
data-domain="example.com"
data-api="https://example.com/api/event"
></script>
Keep data-domain set to the canonical domain in PureStats. The data-api attribute tells the tracker to send events to your proxy. PureStats automatically derives the config endpoint from it and requests /api/tracker-config on the same origin.
Proxy paths
Proxy these paths from your website to PureStats:
| Your path | Upstream | Cache |
|---|---|---|
/pf.min.js | https://purestats.io/pf.min.js | Yes, about 1 hour |
/api/event | https://purestats.io/api/event | No |
/api/tracker-config | https://purestats.io/api/tracker-config | No, or very short |
Do not cache /api/event. It receives pageviews and custom events.
Nginx
Add the cache zone in the http block:
proxy_cache_path /var/cache/nginx/purestats levels=1:2 keys_zone=purestats_tracker:10m max_size=50m inactive=24h use_temp_path=off;
Add the locations to your site server block:
location = /pf.min.js {
proxy_pass https://purestats.io/pf.min.js;
proxy_ssl_server_name on;
proxy_set_header Host purestats.io;
proxy_cache purestats_tracker;
proxy_cache_valid 200 1h;
add_header Cache-Control "public, max-age=3600" always;
}
location = /api/event {
proxy_pass https://purestats.io/api/event;
proxy_ssl_server_name on;
proxy_set_header Host purestats.io;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /api/tracker-config {
proxy_pass https://purestats.io/api/tracker-config;
proxy_ssl_server_name on;
proxy_set_header Host purestats.io;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Apache
Enable mod_proxy, mod_proxy_http, mod_ssl and mod_headers, then add:
SSLProxyEngine On
ProxyPreserveHost Off
ProxyPass "/pf.min.js" "https://purestats.io/pf.min.js" retry=0
ProxyPassReverse "/pf.min.js" "https://purestats.io/pf.min.js"
ProxyPass "/api/event" "https://purestats.io/api/event" retry=0
ProxyPassReverse "/api/event" "https://purestats.io/api/event"
ProxyPass "/api/tracker-config" "https://purestats.io/api/tracker-config" retry=0
ProxyPassReverse "/api/tracker-config" "https://purestats.io/api/tracker-config"
<IfModule mod_headers.c>
<Location "/pf.min.js">
Header set Cache-Control "public, max-age=3600"
</Location>
</IfModule>
Cloudflare Worker
Create a Worker and route it to your domain for /pf.min.js, /api/event and /api/tracker-config.
export default {
async fetch(request) {
const url = new URL(request.url);
const allowed = ['/pf.min.js', '/api/event', '/api/tracker-config'];
if (!allowed.includes(url.pathname)) {
return fetch(request);
}
const upstreamUrl = new URL(url.pathname + url.search, 'https://purestats.io');
const upstreamRequest = new Request(upstreamUrl.toString(), request);
if (url.pathname === '/pf.min.js' && request.method === 'GET') {
const cache = caches.default;
const cached = await cache.match(request);
if (cached) return cached;
const response = await fetch(upstreamRequest);
const cachedResponse = new Response(response.body, response);
cachedResponse.headers.set('Cache-Control', 'public, max-age=3600');
await cache.put(request, cachedResponse.clone());
return cachedResponse;
}
return fetch(upstreamRequest);
}
};
Content Security Policy
If all PureStats requests go through your domain, a strict CSP can allow only your own origin:
script-src 'self';
connect-src 'self';
img-src 'self' data:;
If you keep the normal direct script and only proxy events, also allow https://purestats.io in script-src.
Verify
- Open
https://example.com/pf.min.jsand confirm it returns JavaScript. - Install the first-party script snippet.
- Open your site and check the browser Network panel.
- Confirm
/pf.min.js,/api/tracker-configand/api/eventare requested on your own domain. - Open PureStats Site Health and verify the first hit.
Troubleshooting
- If the script loads but no pageviews appear, check that
/api/eventforwards POST bodies. - If settings do not apply, check that
/api/tracker-config?domain=example.comreaches PureStats. - If CSP blocks requests, allow your own origin in
script-srcandconnect-src. - If the proxy returns 404, make sure the route is configured before your app fallback route.
- If the proxy returns 405, make sure POST is allowed for
/api/event. - If the dashboard shows a domain mismatch, keep
data-domainset to the canonical PureStats site domain and add every real hostname in Site Settings.