Server-side tracking
The measurement no ad blocker can touch, and the one rule that makes it accurate.
Server-side tracking is the only measurement no ad blocker can touch, because it never involves the visitor’s browser. It is also the only way to record things that happen after the user leaves — a payment confirmed by a webhook, a subscription renewed by a cron job.
One HTTP call
There is no library to install. Sending an event is a single POST, authenticated with a write-scoped API key — every language you might use has this built in.
curl -i -X POST https://causalit.fr/api/ev \n -H "Authorization: Bearer $CAUSALIT_WRITE_KEY" \n -H "Content-Type: text/plain" \n --data '{"d":"example.com","n":"purchase","u":"https://example.com/checkout/success","p":{"plan":"pro"},"ip":"203.0.113.7","ua":"Mozilla/5.0 (...)"}'The same call from Node, with nothing beyond the standard library:
await fetch('https://causalit.fr/api/ev', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CAUSALIT_WRITE_KEY}`,
'Content-Type': 'text/plain',
},
body: JSON.stringify({
d: 'example.com',
n: 'purchase',
u: 'https://example.com/checkout/success',
p: { plan: 'pro' },
ip: request.headers['x-forwarded-for'], // the visitor's, not your server's
ua: request.headers['user-agent'],
}),
});Pass the visitor’s IP and user agent
Both are used transiently to compute the same daily fingerprint the browser tag would have produced, and neither is stored. Read them from the request that reached your server. Omit them and every server-side event is attributed to your server — one visitor, all day.
Generating a client
The whole contract is published as an OpenAPI 3.1 document, so a typed client in your language is one generator run away — see the API reference for both.
Identified mode
You may attach an already-hashed user id to tie events to a known account. That is pseudonymised personal data of your users, so the legal basis becomes yours: it needs a per-site opt-in here and a line in your privacy policy. Send only irreversible hashes — never an email, never a raw id.