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:
- A user clicks your ad and lands on the offer through your tracking link.
- Your tracker generates a unique
click_id, logs the click (source, campaign, ad, sub IDs, geo, timestamp), and passes thatclick_idforward to the offer as a URL parameter. - The offer’s landing page, signup form, or deposit flow carries that
click_idthrough its own funnel — usually as a hidden field or a sub-ID the network already supports. - 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_idand a status. - Your tracker matches the
click_idto 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 Tracking | S2S Postback | |
|---|---|---|
| Depends on browser/cookies | Yes | No |
| Survives ad blockers | No | Yes |
| Works if the user closes the tab | No | Yes |
| Works across a redirect to the advertiser’s own domain | No | Yes |
| Accurate for delayed conversions (deposits days later) | Poor | Reliable |
| Fires on | Page load / client event | Confirmed server-side status change |
| Data ownership | Split across client scripts | Fully 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.
![]()
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}¤cy={currency}
Macro reference
Macro names vary between networks, but nearly all of them map onto the same underlying concepts:
| Macro (common form) | What it carries | Alternate 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¤cy=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
- Generate the postback URL in your tracker, including every macro the network actually supports — pulled from their documentation, not guessed from a template.
- 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.
- 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.
- Verify the match on your tracker’s side — confirm the
click_idthat came back matches a click you actually logged, not an orphaned or malformed request. - 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.
![]()
Debugging a Broken Postback Chain
When conversions aren’t showing up, work through the chain in order rather than guessing:
- 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.
- Confirm the
click_idsurvived 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. - 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.
- Check your tracker’s incoming request log for the raw postback hit. If it arrived but didn’t match a click, the
click_idvalue is likely malformed, truncated, or using the wrong macro name. - Confirm the status mapped to something your stream recognizes. A postback arriving with
status=ftdwhen your stream only mapsdepositlands as an unrecognized event — check for naming mismatches between what the network sends and what your status registry expects. - 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_idpassthrough. 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.