Server-side Tracking
Method
Recording user behavior on the server that handled the request, rather than on the user's own device, and sending it to an analytics tool from there.
Why it exists
Behavioral records all used to be sent from the browser. Drop one script tag into a page and a button click flew off to the analytics tool, which cost almost no engineering time. Pagedeck instrumented its checkout completion exactly that way, and the whole setup took an afternoon.
The problem surfaced while reconciling quarterly revenue. The analytics tool showed 1,840 checkout completion events while the payments database showed 2,050 authorizations. Two hundred and ten were missing. Theo traced it to three causes: ad blockers blocking the analytics domain, requests cut off when the page navigated away right after payment, and mobile connections dropping for a moment.
If the 210 had gone missing evenly, the numbers could have been corrected with a ratio and left alone. But ad blocker use clusters in particular segments of users, so the missing share leaned one way too. Server-side tracking is the practice that settled into that gap. Move the point where the record gets written from the user's device to the company's own server, and neither a blocker nor a flaky connection can get in the way — and the values can't be edited by the person being measured.
How to run it
Start by choosing which events move to the server. Not all of them do. The procedure runs five steps.
- Pick the events to move. The test is money, permissions, and state changes you can't undo — payment authorization, refunds, plan changes, granting admin rights. Mark which side each event is sent from as a column in the tracking plan, the document that records what gets logged under what name.
- Choose where the logging call goes. It belongs at the point the thing actually finished. For a payment, that's after the card authorization comes back and the write to the database commits. Log it on the button click instead and failed payments get counted too — a card declined at the bank still fires the click.
- Send a user identifier along with it. The server doesn't know the value stored in the browser, so it uses the account number. To connect behavior from before signup, the anonymous identifier the client was using has to be passed into the request.
- Separate sending from the user's request. If the analytics tool takes three seconds to answer, the checkout screen must not freeze for three seconds, so records go onto a queue and get sent separately.
- Prevent duplicates. Add retries for failed sends and the same payment arrives twice. Attach a unique key to each event and drop anything that arrives with a key already seen.
Records instrumented with steps 3 and 5 skipped cost the most work later. Without the identifier the payment count is right but nobody can say whose payment it was, and without the duplicate check revenue reads higher than it is.
When it fits and when it doesn't
The right home for this method is anything involving money or permissions, plus anything only the server knows. Payment authorizations and refunds, subscription renewals and cancellations, permission grants sit in the first group. The second group is things that happen while the user isn't on screen at all. A subscription expired by a batch job overnight, or a recurring charge reported by an external payment provider over a webhook, has no device to be sent from.
There are three limits. The first is that nothing confined to the screen can be captured. Which pricing tier someone hovered over and moved past, how far into the signup form they got before quitting — none of that reaches the server. That share belongs to client-side tracking.
The second is the cost of instrumenting. On the client side a product manager can place a tag through a tag management tool; on the server side an engineer edits code and ships it. A number you want to see this week waits for the next release.
The third is that screen context doesn't attach by itself. Acquisition channel, referrer, viewport size, browser — the browser knows these and the server doesn't. To see checkout conversion by channel, the client has to pass those values into the request and the server has to attach them to the event. Most teams do this once at signup rather than on every event. Which is why nobody picks one side in practice. Money-bearing facts go from the server, screen-only behavior goes from the client, and a user identifier stitches the two streams together.
How it sounds at work
"Let's send checkout completion from the server. On the client, whatever gets blocked looks like missing revenue."
Events tied to money can't absorb loss, so the collection point should move.
"This is server-side, right? Then the acquisition channel won't be attached."
The server doesn't know that value, so splitting the number by channel takes extra work.
"Moving this to server-side means booking engineering time. It's not going in this sprint."
A product manager can't do it alone, so it lines up with other engineering work.
At Pagedeck the distinction gets written into a table whenever a new feature's logging is decided. Mia lists the events the feature should record and Theo fills in the column beside each one saying where it's sent from. Plan upgrade completed goes server-side; which cell someone clicked on the plan comparison screen goes client-side. Ravi needs the acquisition channel to report on ads, so the value the client holds at signup gets passed to the server and stored once on the account. Stored that way it can be used without going through an outside tool, which makes it first-party data.
What people get wrong
Many people read the move to the server as the end of data loss. The largest single cause does disappear, so the impression is fair. But the server side leaks in its own places: events dropped when the queue overflows, a release that forgot the logging call on a new code path, events written twice by a retry. Believe the problem is gone and you stop reconciling, and from then on there's no way to notice a mismatch. Pagedeck chose to compare the payments database count against the event count every week.
The other frequent conclusion is that since server-side is more accurate, everything should move there. Standardizing on the better option looks tidy. But move it all and the front of the funnel empties out. Checkout counts get precise while nobody can see how many people reached the checkout screen or where they quit, so when payments fall there's nowhere to look for the cause. The instrumentation that answers that question only exists on the client.
Easily confused with
| Term | Where it sends from | How it differs from server-side tracking |
|---|---|---|
| Client-side tracking | The user's browser or app | It captures on-screen behavior and is easy to instrument, but blockers and dropped connections cut into it. Server-side is the reverse, which is why teams split the work between them and join it with an identifier |
Where to go next
- Event tracking
see where this method sits in the whole sequence that produces one record
- Client-side tracking
the paired method, needed to decide what goes where
- First-party data
where records you collect yourself turn into an asset
Last updated 2026-09-16