flowsk.com
How it actually works

Client-side vs server-side events (and why you need both)

They are not redundant. One knows what the person did, the other knows what actually happened. Send both on purpose, and give them a shared key so they collapse into one record.

Jul 26, 2026· 3 min read ·How it actually works
Quick answer

client = context, blockable · server = truth, unblockable · key = one record

Client events are cheap, detailed and expendable. Server events are authoritative, unblockable and carry the cause of what happened. Anything with money or identity attached should exist on both sides, joined by a de-duplication key.

Without the key, running both is worse than running either alone — you double count everything that got through.

The usual framing is “client-side tracking is dying, move to server-side.” That framing costs you something real, because the two are not substitutes.

What each one actually knows

The client knows the path.

Which page. What referrer. Which UTM parameters were on the landing URL. Which button, with what text, in which section. How long they hesitated. The whole sequence of behaviour that led to the moment.

None of that exists on your server. Your backend sees POST /checkout and has no idea it was preceded by four product pages and a comparison table.

The server knows what happened.

That the payment actually succeeded rather than being attempted. The exact amount captured, after discounts and tax. The internal customer id. Whether this is a first order or a fifth.

And the most under-used one: the cause. When an email arrives, your backend knows whether that was a newsletter subscription, a gated download, an account creation or a demo request. A browser-side identify(email) call cannot know that, and the difference between those causes is most of the signal.

The failure modes of picking one

Setup What you get What goes wrong
Client only Rich behavioural detail Missing every blocked session — 20–30% of paid traffic, systematically
Server only Accurate counts No idea what produced them. You know how many, never why
Both, no key Everything, twice Inflated revenue, impossible CPA, nothing reconciles
Both, shared key Accuracy and context Nothing — this is the answer

The third row deserves emphasis because it is the most common outcome of “we added server-side tracking.” Adding a Conversions API or a webhook alongside an existing pixel, with no shared key, is a regression dressed as an upgrade.

The shape of a correct pair

// browser — fires immediately, knows the context, might not arrive
{
  "source": "client",
  "category": "purchase",
  "name": "purchase",
  "value_cents": 12900,
  "dedup_key": "order_10482",
  "properties": { "path": "/checkout/success", "referrer": "https://…" }
}

// backend — fires from the payment webhook, always arrives
{
  "source": "server",
  "category": "purchase",
  "name": "purchase",
  "email": "hello@example.com",
  "value_cents": 12900,
  "dedup_key": "order_10482"
}

Same key, so they merge into one conversion. The record ends up marked source: both, with the server’s amount and the client’s context.

Reading the confidence afterwards

Because the merge is recorded rather than discarded, every conversion carries a confidence level:

  • both — two independent systems agree. Highest confidence.
  • server — the browser event was blocked or never sent. The money is real; the path is partial.
  • client — only the browser reported it. Nothing has confirmed the money.

That last one is a useful alarm. A run of client-only conversions usually means your server-side integration broke, and you would otherwise not notice until a monthly reconciliation.

The split, as a rule

Client-side: pageview, click, scroll, form interaction, tool usage, add-to-cart, checkout started.

Server-side: purchase, refund, signup, confirmed lead, trial started, subscription changed, CRM stage.

Both, with a key: everything in the server list that the browser also observes.

Where to start if you have neither

Send the purchase from your payment webhook. One event, one endpoint, an afternoon.

You will immediately see the size of the gap against your platform-reported conversions, and that number is usually persuasive enough to fund the rest of the work.

Frequently asked questions

Which events should be client-only?

Pageviews, clicks, scroll, form focus, tool usage. High volume, low stakes, cheap to lose. Losing 25% of them costs you nothing important.

Which events must be server-side?

Purchases, refunds, signups, confirmed leads, subscription changes and CRM stage transitions. Anything a decision or an invoice depends on.

What does the server know that the client doesn't?

The authoritative amount charged, the internal customer id, whether the payment actually succeeded, and — most usefully — which action caused an identification. A browser calling identify() cannot tell you whether that was a newsletter signup or a demo request.

What does the client know that the server doesn't?

The referrer, the UTM parameters on the landing URL, which element was clicked, the sequence and timing of behaviour within a page. The path, essentially.

How do the two events find each other?

A shared dedup_key that both sides can derive independently — usually the order id. Same string, both sides, one record marked confirmed by both.

Watch the four configurations diverge

Set the true number of orders and see what client-only, server-only, both-without-a-key and both-with-a-key each report.

Open the simulator

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.

Keep reading