All articles
12 min read

S2S Postback Tracking: What It Is & How to Set It Up

S2S Postback Tracking: What It Is & How to Set It Up

A media buyer runs a nutra offer through a network that pays on FTD. Their tracker’s dashboard shows 340 clicks and 4 conversions for the day — a CR that would get any campaign paused. Except the network’s own stats page shows 19 conversions for the same traffic in the same window. Nothing is stolen and nobody is lying: the network fires its confirmation event from its own backend, days after the click, on a domain the buyer’s browser never touches again. If the tracker never got told about those 15 conversions, they don’t exist in its numbers — no matter how real the revenue is. Server-to-server (S2S) postback tracking exists specifically to close that gap, and getting it wrong is one of the most common ways media buyers silently underreport their own performance.

What an S2S Postback Actually Is

An S2S postback (sometimes called a server callback or IPN — instant payment notification, borrowed from payment processor terminology) is an HTTP request that the affiliate network’s or advertiser’s server sends directly to your tracker’s server the moment a conversion event happens. No browser, no JavaScript, no cookie, no dependency on the user’s device being online, unlocked, or even still owned by the same person who clicked the ad.

The flow, step by step:

  1. A user clicks your ad and lands on the offer through your tracking link.
  2. Your tracker generates a unique click_id, logs the click (source, campaign, ad, sub IDs, geo, timestamp), and passes that click_id forward to the offer as a URL parameter.
  3. The offer’s landing page, signup form, or deposit flow carries that click_id through its own funnel — usually as a hidden field or a sub-ID the network already supports.
  4. When the user converts — registers, deposits, completes KYC, whatever the offer defines as a paid event — the network’s server calls your postback URL with that same click_id and a status.
  5. Your tracker matches the click_id to the original click and records the conversion, server-side, independent of anything that happened in the user’s browser afterward.

Because the entire exchange happens server-to-server, it doesn’t care about iOS ITP, ad blockers, third-party cookie restrictions, a closed tab, or a slow page that never got the chance to fire a script. It also doesn’t care that the conversion happened three days later, on a domain you don’t control, using a device that isn’t the one that clicked the ad. That’s the whole point — it’s the only tracking layer built to survive the actual shape of an affiliate funnel.

Pixel vs. Postback: What Each Layer Actually Sees

Pixels aren’t useless — they’re cheap, fast, and fine for early-funnel signals like a landing page view. But treating a pixel as your source of truth for revenue events is how buyers end up optimizing against numbers that were never complete in the first place.

Pixel TrackingS2S Postback
Depends on browser/cookiesYesNo
Survives ad blockersNoYes
Works if the user closes the tabNoYes
Works across a redirect to the advertiser’s own domainNoYes
Accurate for delayed conversions (deposits days later)PoorReliable
Fires onPage load / client eventConfirmed server-side status change
Data ownershipSplit across client scriptsFully server-controlled

If you also run Facebook CAPI alongside postback, it’s worth understanding where each layer’s job starts and stops — see Pixel vs Conversions API vs S2S Postback for how the three actually divide the work instead of compete.

Two industrial machines linked by a single wire, one lit and immediate, the other in shadow and delayed

Anatomy of a Postback URL

A postback URL is an endpoint on your tracker, populated with macros the network’s system fills in dynamically at the moment it fires the callback. A typical structure:

https://track.yourdomain.com/postback?click_id={click_id}&status={status}&payout={payout}&currency={currency}

Macro reference

Macro names vary between networks, but nearly all of them map onto the same underlying concepts:

Macro (common form)What it carriesAlternate names you’ll see
{click_id}Unique ID tying the conversion to the original click{clickid}, {subid}, {aff_click_id}
{status}The conversion event type{event}, {action}, {goal}
{payout}Revenue/commission value{amount}, {revenue}, {sum}
{currency}Payout currency{cur}
{sub1}{sub5}Your custom sub-ID parameters for segmentation{s1}{s5}, {subid1}{subid5}
{transaction_id}The network’s own internal ID for the conversion (useful for dedup/dispute resolution){trans_id}, {conversion_id}

Don’t assume a macro name is universal until you’ve checked the network’s postback documentation. A missing or mistyped macro is invisible right up until the first real conversion silently fails to match.

Worked example

Here’s what a live postback request looks like once the network actually fires it, with macros populated for a deposit event on a gambling offer:

https://track.yourdomain.com/postback?click_id=8f2a91c0d3&status=deposit&payout=45.00&currency=USD&sub1=fb_lookalike_3

Your tracker receives this, looks up click_id=8f2a91c0d3 against its click log, finds the original click (campaign, ad, geo, sub1), and records a deposit conversion worth $45.00 attached to that click’s full context — no manual reconciliation, no spreadsheet, no waiting on the network’s own dashboard to reflect reality.

Per-network quirks worth knowing

Postback setup looks identical in theory and behaves differently in practice depending on the network:

  • Macro naming inconsistency. One network’s {clickid} is another’s {subid} is another’s {aff_sub}. Paste the network’s actual macro syntax into your postback URL — don’t assume it matches the last network you configured.
  • Single vs. multi-status postbacks. Some networks fire one URL field per status (separate fields for “lead” and “sale”); others fire a single URL and expect you to read the {status} macro. Configuring for the wrong model means every event past the first one gets silently dropped.
  • Delayed and retried postbacks. Some networks queue and retry failed deliveries for hours or days; others fire once and never retry. Know which behavior you’re dealing with — it determines whether downtime costs you a few conversions or all of them.
  • IP allowlisting and HTTPS. A subset of networks require you to allowlist their outbound IPs, or reject plain-HTTP postback endpoints outright. Check both directions before assuming a setup is broken.

Setting Up and Routing Postbacks by Status

  1. Generate the postback URL in your tracker, including every macro the network actually supports — pulled from their documentation, not guessed from a template.
  2. Paste it into the network’s postback field. If they support per-status URLs, map each status you care about (registration, deposit, sale) individually — not just the first one you set up.
  3. Fire a test conversion if the network’s sandbox allows it, or check their postback delivery log after a real one to confirm the request actually left their server.
  4. Verify the match on your tracker’s side — confirm the click_id that came back matches a click you actually logged, not an orphaned or malformed request.
  5. Map every status you need, not just the first one that fires. A setup that only catches “registration” and drops “deposit” three days later looks fine right up until your revenue numbers stop moving.

Most trackers treat every postback as one flat event and expect you to bolt on status handling yourself. DarkCore treats conversion status as a first-class concept from the start: postback routing is configured inline on each stream, per status — registration, deposit, or any custom status your vertical needs.

Conversion statuses live as a per-workspace registry, not hardcoded categories. Add a new one — a KYC-verified milestone, a second-deposit threshold, whatever your funnel actually tracks — and it’s instantly available everywhere: postback routing, pixel firing, analytics metrics, and push audience filters, with zero engineering work. You’re not filing a ticket to get a new status recognized; you’re adding a row.

This is the part that quietly breaks in tools built around a single generic “conversion” event: registration postbacks land fine on day one, and deposit or sale postbacks — the ones actually carrying revenue — arrive days later and get dropped, misrouted, or lumped in with everything else because the system was never built to tell statuses apart. If you’re also running Facebook CAPI on top of postback data, this same registry drives event mapping there too — see how to track Facebook ad conversions for affiliate offers for how the two connect end to end.

A single relay baton passing hand to hand across a row of separate stone gates, each gate a different color of light

Debugging a Broken Postback Chain

When conversions aren’t showing up, work through the chain in order rather than guessing:

  1. Confirm the click was logged at all. Open your tracker’s click log and search for a click matching the timeframe and source you expect. If there’s no click, nothing downstream can match.
  2. Confirm the click_id survived the redirect to the offer. Many “broken” postback setups are actually a broken passthrough — the network’s landing page or signup form dropped the parameter before their conversion event ever fired.
  3. Check the network’s postback delivery log, if they expose one. This tells you whether the request left their server at all, and what it actually contained — often different from what their documentation describes.
  4. Check your tracker’s incoming request log for the raw postback hit. If it arrived but didn’t match a click, the click_id value is likely malformed, truncated, or using the wrong macro name.
  5. Confirm the status mapped to something your stream recognizes. A postback arriving with status=ftd when your stream only maps deposit lands as an unrecognized event — check for naming mismatches between what the network sends and what your status registry expects.
  6. Reconcile against the network’s own dashboard for a short, recent window once delayed events have had time to post. A small, permanent gap can be normal; a large or growing one means a step above is still broken.

Common Mistakes

  • Only mapping the first status that fires. Registration works, deposit doesn’t — because nobody configured routing for anything past the first event in the funnel.
  • Trusting the network’s macro documentation without testing. Docs go stale. The macro that used to be {subid} becomes {sub_id} after a platform migration, and nobody updates the page.
  • Not verifying the click_id passthrough. If the network’s landing page or signup form doesn’t reliably carry your click identifier into their own system, the postback that eventually fires has nothing to match against — a “successful” delivery that produces an unattributed conversion.
  • Assuming a delivery failure will be visible immediately. Some networks retry silently for days; others drop a failed delivery with no alert. If your endpoint had any downtime, check the network’s delivery log rather than assuming everything came through.
  • Treating one flat “conversion” event as good enough. Registrations, deposits, and rebills are different signals with different value. Collapsing them into one status makes downstream automation — auto-rules acting on real deposits, analytics, push segmentation — blind to the difference between a $0 lead and a $200 FTD.

FAQ

Is S2S postback tracking difficult to set up compared to a pixel?

The initial setup takes a bit more coordination — you need the network’s cooperation to carry your click_id through their funnel and fire the callback — but the configuration itself is a single URL with macros, no more complex than pasting a pixel snippet. The payoff is durability: once wired correctly, it keeps working regardless of browser changes, ad blockers, or how many days pass between click and conversion.

Can I use both a pixel and S2S postback at the same time?

Yes, and for most affiliate funnels you should — a pixel for cheap, early-funnel signals like page views, and postback for the downstream events that actually carry revenue. They’re not competing for the same job; postback exists specifically to catch what a pixel structurally cannot.

What happens if the affiliate network doesn’t support postback URLs at all?

You’re limited to whatever tracking they do expose — usually a manual export or their own dashboard, both lagging real-time and requiring reconciliation by hand. If a network can’t fire a server-side callback on conversion, there’s no way to get real-time, attributed revenue data out of them; that’s a real constraint on offer selection worth weighing against payout.

Why does my tracker show fewer conversions than the network’s own dashboard?

Almost always one of: the click_id isn’t surviving the redirect into the network’s funnel, the postback URL is missing a status mapping for events past the first one, or the network is retrying a failed delivery silently instead of alerting you. Work through the chain from the click log outward rather than assuming the gap is unfixable.

Getting It Right the First Time

None of this is exotic — it’s a URL, a handful of macros, and a status your tracker actually knows how to route. What trips people up is treating postback as a one-time setup task instead of a chain with several places it can quietly fail: a dropped click_id, an unmapped status, a retry policy nobody checked. DarkCore handles the parts that usually get bolted on as afterthoughts — per-status routing configured directly on the stream, a status registry that extends to pixels and analytics with no extra setup, and a tracker built around the assumption that the conversion you care about often happens well after the click. If your current numbers don’t match what your network is actually paying you for, it’s worth tracing the chain before you trace the budget — talk to us on Telegram.

  • s2s postback
  • server-to-server tracking
  • affiliate tracking
  • postback url