Server-side tracking without the jargon
It means your backend sends the event instead of the browser. That is all it means — and it is why the sale gets recorded even when the tag never ran.
server-side = the event is sent by your backend, not the visitor's browser
No tag to block, no storage to expire, no tab to close early. Your server already knows a purchase happened because it processed the payment — server-side tracking is just telling your analytics what your backend already knows.
It is not a privacy workaround. Respect consent first, then measure reliably within it.
“Server-side tracking” sounds like infrastructure. It is one sentence:
The event is sent by your backend instead of by the visitor’s browser.
Everything else about it follows from that one change.
Why it is more reliable
A browser event has to survive a lot to be recorded:
- The script has to load — not blocked by an extension, a browser feature, a DNS filter or a CSP rule.
- The JavaScript has to run — not broken by another script’s error.
- The user has to stay long enough for the request to leave.
- The network has to cooperate.
A server event has to survive: your server being up.
That is the whole argument, and it is why anything with money attached belongs on the server side.
What it looks like
Concretely, this is the entire idea:
# In your payment webhook — the moment money actually moved
def handle_payment_succeeded(event)
session = event.data.object
post_to_analytics(
anonymous_id: session.metadata["fsk_id"],
events: [{
source: "server",
category: "purchase",
name: "purchase",
email: session.customer_details.email,
value_cents: session.amount_total,
dedup_key: session.id
}]
)
end
No browser. No tag. No storage. Your backend already knew this happened — it processed the payment. Server-side tracking is telling your analytics what your application already knows.
What server-side is not
It is not server-side GTM. That is a container you host which receives events from the browser and forwards them onward. It helps with delivery and with keeping third-party scripts off the page, and the event still originates in a browser that can be blocked. Useful, different thing.
It is not a consent workaround. Consent governs what you may collect and why. The transport is irrelevant to that. If a user declined tracking, server-side collection of their behaviour is the same violation with a different network path.
It is not a replacement for client events. The browser knows things your server never will: which page, what they clicked, how long they hesitated, where they came from. Losing that is a real loss.
The join between the two
The one genuinely tricky part: your server needs to know which visitor this is.
The visitor id lives in a cookie. Your backend can read cookies, so for anything happening on your own domain this is easy. The hard cases are the ones that leave your domain:
| Situation | How the id gets there |
|---|---|
| Same-domain request | Read the cookie server-side. Done. |
| Stripe Checkout | Put the id in metadata when creating the session |
| Shopify checkout | Carry it as a cart attribute; read it off the order |
| Third-party form embed | Pass it as a query parameter into the iframe URL |
| Payment webhook | Read it back from whatever you attached above |
Every one of these is “put the id somewhere that comes back to you.” That is the entire integration problem, and it is worth five minutes of thought per checkout path.
The one rule that makes it safe
Once your backend also reports the purchase, you have two systems reporting the same fact. Without a shared key, they both count.
Give both events the same dedup_key — the order id — and they merge into one conversion marked confirmed by both sides. It also makes your webhook handling idempotent for free, which matters because payment providers retry.
Details in the de-duplication guide; the simulator shows what each configuration reports against a known truth.
Where to start
You do not need a project. You need one webhook.
- Find where your payment provider notifies you of a successful payment.
- Send one event from there, with the order id as the key.
- Compare a week of that against your platform-reported conversions.
That single event is the most valuable measurement work available to most companies, and it is an afternoon.
Frequently asked questions
Is server-side tracking the same as server-side GTM?
No. Server-side GTM is a container you host that receives browser events and forwards them. The event still originates in the browser, so it can still be blocked. True server-side events originate in your backend.
Does it get around ad blockers?
For the events your backend sends, yes — a blocker cannot block a request between two servers it never sees. That is reliability, not evasion: the user still declined third-party tracking, and you should still honour that in what you collect.
Is it a way around consent requirements?
No. Consent governs what you may collect and why, regardless of transport. Anyone selling server-side tracking as consent evasion is selling you a compliance problem.
What should I send server-side?
Anything with money or identity attached: purchases, signups, confirmed leads, subscription changes, CRM stages. Leave pageviews and clicks on the client where they are cheap.
Do I need to stop sending client events?
No — send both, with a shared de-duplication key. The client gives you context, the server gives you truth, and the key stops them double counting.
See why both sides are needed
Four configurations, one known truth. Watch client-only under-count and both-without-a-key double count.
Stop guessing which ad made the sale.
Flowsk Signals stitches the anonymous click to the email to the purchase — first-party, server-side, de-duplicated. One snippet, $29/mo, and every conversion comes with a receipt you can inspect.