server-track-labby Marc Stevens

Server-side vs browser pixel tracking for B2B SaaS

By Marc Stevens · October 13, 2026

If you run paid social or search for a B2B SaaS product, your ad platform is only as smart as the conversions you feed it. Most teams start with a browser pixel: a snippet of JavaScript that fires when someone signs up or books a demo. It works, until it quietly doesn't. This guide explains where browser pixels lose data, what server-side tracking (Meta's Conversions API, Google's Enhanced Conversions) actually changes, and how to run both without double counting.

How a browser pixel works, and where it loses data

A browser pixel runs in your visitor's browser. When the "thanks for booking" page loads, the script reads a cookie, packages the event, and sends it to the ad platform. Every step depends on the browser cooperating. Several common things get in the way:

What server-side tracking does

Server-side tracking sends the same conversion from your backend directly to the ad platform's API. For Meta that is the Conversions API (CAPI). For Google Ads it is Enhanced Conversions, including uploads from your own systems (see Google's Enhanced Conversions overview).

Because your server makes the request, browser extensions can't block it and cookie expiry doesn't decide whether it gets sent. Your server already knows the facts that matter: the user signed up, the demo is booked, the deal is worth a certain amount. You send the event with identifiers the platform can match against its users, such as a hashed email address, and the platform attributes it to the ad that drove it when it can.

Server-side is not magic. The platform still has to match the person. If you send a weak identifier, or none, the event may arrive but not be attributed. Match quality depends on what you send.

Why you should run both, with event_id dedup

It's tempting to rip out the pixel once the server path works. Don't. The browser pixel captures signals your server often doesn't have, such as the click ID cookies and browser context. The server catches the events the browser drops. Running both gives you the best coverage.

The catch is double counting. If the pixel and the server both report the same demo booking, you don't want two conversions. Meta solves this with deduplication: when a browser event and a server event share the same event_name and the same event ID (eventID in the pixel, event_id in CAPI), Meta keeps one. The rules, including timing windows, are in Meta's deduplication documentation.

In practice: generate one ID when the conversion happens (for example demo_8f3a2c71), pass it to the pixel on the confirmation page, and send the same ID from your server. server-track-lab also dedups on event_id per workspace for 72 hours, so retries from your own code don't double send or double bill.

B2B events worth sending

Ad platforms optimize toward what you report. For B2B SaaS, page views and button clicks are weak signals. Send the moments that predict revenue:

Keep timing in mind. Meta only accepts events whose event_time is within the last 7 days (see the server event parameters). If deals take months to close, send the earlier funnel stages promptly. Check the platform's offline conversion options for late-stage events.

Hashing and PII basics

You never send a raw email address to Meta's Conversions API. Customer information such as email, phone, and name must be normalized (trimmed, lowercased, phone reduced to digits with country code) and hashed with SHA-256 before it is sent. Meta lists which fields need hashing in its customer information parameters reference. Some fields, like IP address and user agent, are sent unhashed because they're used for matching as-is.

A few practical rules:

Google Enhanced Conversions, briefly

Google's equivalent idea is Enhanced Conversions: you supplement a conversion with hashed first-party data (email, phone) so Google can match it to a signed-in user, and you can include click IDs like gclid when you have them. Google uses its own normalization rules, so treat it as a separate mapping from Meta's. server-track-lab builds the Google payload today and shows it as a preview; live Google delivery is still in progress.

When not to bother

Server-side tracking is plumbing. It's worth it when you spend meaningfully on paid ads and the platform's optimization depends on conversion signals. You can probably skip it if:

A short example

Here is a demo booking sent from your backend to server-track-lab, which hashes the identifiers, maps demo_booked to Meta's Schedule, and forwards it:

curl https://server-track-lab.pages.dev/api/v1/track \
  -H "Authorization: Bearer $SST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "demo_booked",
    "event_id": "demo_8f3a2c71",
    "timestamp": "2026-10-13T14:03:22-04:00",
    "user": {
      "email": "jane.doe@acme.example",
      "ip": "203.0.113.7",
      "user_agent": "Mozilla/5.0"
    },
    "event_source_url": "https://acme.example/book-a-demo"
  }'

Use the same event_id as the eventID on your browser pixel. Send the same request twice and the second returns "status": "deduplicated".

Try it

Want to see the exact hashed payload before you wire anything up? Paste an event into the playground. No signup, nothing stored. When you're ready, get a free API key. The first 1,000 events each month are free, then CA$2 per 1,000 events.

Coming from Stape or Cometly? See the comparison and migration guide.