How to set up S2S postback tracking for affiliate campaigns: complete guide 2026
In 2026, the average affiliate running pixel-only tracking is invisibly missing somewhere between 20 and 40 percent of real conversions. Not because the campaigns aren’t working — because ad blockers, iOS ATT opt-outs, and cookie restrictions stop the pixel from firing before it can report anything. The conversions happened. The tracker just never heard about them. Postback tracking — server-to-server, or S2S — closes that gap: one server calls another directly, nothing runs in the user’s browser, nothing gets blocked.
I’ve set up this kind of tracking for a few hundred campaigns by now, and the same handful of mistakes keep showing up, in my own early setups included. If you’ve never configured S2S, or you copied a setup from a Telegram group without knowing what the macros in it actually do, this is the guide I wish someone had handed me back when I was making those exact mistakes. New to S2S terminology? Jump to the glossary at the bottom.
Why the pixel is dying
A pixel is a tracking script that fires in the user's browser, usually on your “thank you” or confirmation page. It was built for a web that doesn't really exist anymore. Three things did it in.
Since iOS 14.5, apps have had to ask permission before touching the IDFA (Identifier for Advertisers). Adjust’s mid-2025 data puts the global opt-in rate at around 35%. So roughly two-thirds of iOS users are invisible to anything that depends on a device identifier or a script running client-side. If a real share of your traffic is iOS, your pixel is quietly missing most of what actually converted.
About 29.5% of internet users worldwide run one. In the US it’s higher, around 32.5%, and it skews toward desktop. Every one of those users has something sitting between your landing page and your conversion event that stops the pixel from firing. The conversion happened. Your tracker never heard about it.
Safari and Firefox have blocked third-party cookies by default for years through ITP and ETP. EU consent banners compound this: Didomi’s 2026 benchmark puts average cookie opt-in across Europe at 56–68%, with another 22–27% of visitors leaving banners untouched — no valid cookie either way. Stack ad blockers, ATT opt-outs, and cookie rejection together and a third of your funnel or more never gets attributed by a pixel at all.
Postback sidesteps all three problems because it doesn’t run in the user’s browser. No JavaScript, no cookie, no device ID. One server calling another server. That’s genuinely most of what you need to understand — everything below is just the mechanics of building that call correctly and not shooting yourself in the foot on the way.
Pixel vs S2S: what actually breaks
The gap between “pixel installed” and “pixel actually firing” is where budgets quietly leak.
| Factor | Pixel (client-side) | S2S postback (server-side) |
|---|---|---|
| Fires from | User’s browser | Advertiser’s server |
| Blocked by ad blockers | Yes, routinely | No |
| Affected by iOS ATT opt-out | Yes | No |
| Depends on cookies | Yes | No |
| Works in in-app browsers / webviews | Inconsistent | Yes |
| Survives redirect chains | Often breaks | Survives |
| Setup complexity | Low — copy-paste a script | Medium — needs click ID passthrough |
| Attribution accuracy in 2026 | Degraded, often 60–80% of real conversions | Near 1:1 with advertiser’s own numbers |
| Who can tamper with it | End user, via dev tools or extensions | Nobody, without your postback key |
If your tracker shows 100 conversions and the advertiser’s own dashboard shows 140, you’re probably not being shorted. Your pixel is just missing 40 real conversions. That gap feeds straight into your ROI math, your bid decisions, which creatives you scale and which you kill. Left unfixed, you end up optimizing toward whatever converts on non-blocked, cookie-accepting, Android or desktop-Chrome traffic — and slowly starving everything else, including segments that were actually profitable.
How S2S postback tracking works
Strip out the acronyms and it’s a simple relay.
The one thing this entire chain depends on is that click ID surviving the trip from step 1 to step 4 intact. Get it dropped, truncated, or overwritten anywhere along the way and nothing downstream matches. Nearly every postback failure I’ve ever debugged traces back to that one parameter getting lost somewhere in the middle.
SubID structure: how to build it right
A SubID is a custom parameter you attach to your tracking link to carry context alongside the click ID (the unique identifier your tracker generates per click): traffic source, campaign, ad set, creative — whatever you’ll want to segment by later. Your tracker stores these against the click, and once a conversion comes back through postback, you can report on them.
Most trackers give you four or five slots (sub1 through sub5). Treat them as fixed fields decided before launch, not a dumping ground. Redefine what sub3 means halfway through a campaign and your reporting is unusable by week two.
This is the URL you put inside your tracker as the offer destination — the landing page address you get from the affiliate network, with your SubIDs and a click ID macro appended to it. The placeholder in curly braces — {clickid} — is a macro: a token your tracker replaces with the actual click ID value at the moment the link fires. Keitaro uses {subid} for this:
https://network-offer-lp.com/lp?click_id={clickid}&sub1=fb&sub2=campaign_name&sub3=adset_id&sub4=creative_id
In Keitaro: open your campaign → Streams → edit the stream → paste this into the Offer URL field. Replace network-offer-lp.com/lp with the actual landing page URL from your affiliate network, and replace {clickid} with Keitaro’s macro {subid}. Fill in real values for sub1–sub4 or use dynamic macros if your traffic source supports them.
How I structure sub1 through sub4 by traffic source:
| Traffic source | sub1 | sub2 | sub3 | sub4 |
|---|---|---|---|---|
| Facebook / Meta Ads | Source tag (fb) |
Campaign name/ID | Ad set ID | Ad/creative ID |
| Google Ads | Source tag (gads) |
Campaign ID | Ad group ID | Keyword or placement |
| Push notifications | Source tag (push) |
Campaign ID | Zone/site ID | Creative or ad ID |
| Native (Taboola, MGID) | Source tag (native) |
Campaign ID | Widget/section ID | Creative ID |
Step-by-step: setting up postback in Keitaro
Keitaro has two different postback mechanisms that move data in opposite directions. Settings → Postback URL is inbound: this is the endpoint that receives conversion notifications from your affiliate network. This is the URL you hand to the network. Campaign → S2S Postbacks is outbound: this is Keitaro sending conversion data somewhere else — a traffic source for auto-optimization, an ad platform, a webhook. Most affiliates starting out don’t need the outbound one at all. Getting these backwards means you spend an hour handing the network the wrong URL and wondering why nothing shows up.
Campaigns → Add Campaign. Name it to match your convention (source + offer + date is a reasonable default if you don’t have one). Set the campaign type to match your funnel; most affiliate setups run a standard landing-page-to-offer flow.
Traffic Sources → Add Traffic Source. Pick your network from the list (Facebook, Google Ads, TikTok, a push network) or use “Custom” if it isn’t there. Keitaro ships templates for the major sources that already map the right click ID parameter and SubID fields — use the template rather than building the mapping from scratch when one exists.
Go to Settings → Postback URL and copy what’s there. It’ll look something like:
https://YOUR-DOMAIN.COM/postback?subid={subid}&status={status}&payout={payout}&key=YOUR_POSTBACK_KEY
That key parameter is a unique token Keitaro generates for your account. Don’t strip it out when you hand this URL to the network, and don’t publish it anywhere public. Anyone who has this exact URL, key included, can fire fake conversions into your account and quietly wreck your data. Anyone who has it without the key can’t — the request just gets rejected. That’s the entire point of the key existing.
In Campaign → Streams → Edit, set the offer URL to carry the click ID macro: &subid={subid} or &click_id={subid}, matching whatever parameter name the network expects on their end. Check their documentation for the exact name. This single mismatch — your macro versus their expected parameter — is the most common reason postback setups fail silently.
If you want Keitaro to push conversion data onward to a traffic source or ad platform for auto-optimization, that’s under Campaign → S2S Postbacks → Add a postback. Set the destination URL and pick GET or POST. Skip this step entirely if you just need conversions attributed in Keitaro — it’s not required for that.
After setup, go to Maintenance → Logs → S2S Postbacks to confirm requests are actually landing rather than silently failing. This log is the first place to look when something doesn’t show up in reporting.
Step-by-step: setting up postback on the affiliate network side
The tracker side is half the job. The network has to know where to send the ping.
Log into your affiliate network’s dashboard and find the postback or S2S settings — usually under the offer or campaign, sometimes under a global tracking settings page tied to your affiliate ID.
Start from your Keitaro postback URL (key included). Replace only what’s inside the curly braces on the right side of each = — those are the network’s macro names for their own data fields. Keep Keitaro’s parameter names (left side of =) unchanged. Example for Everflow below. Notice status is hardcoded to sale — Everflow doesn’t have a dynamic status macro; you configure a separate postback per event type instead.
https://YOUR-DOMAIN.COM/postback?subid={subid}&status={status}&payout={payout}&key=YOUR_POSTBACK_KEY
https://YOUR-DOMAIN.COM/postback?subid={transaction_id}&status=sale&payout={sale_amount}&key=YOUR_POSTBACK_KEY
| Platform | Click ID macro | Status macro | Payout macro |
|---|---|---|---|
| Keitaro (your tracker) | {subid} |
{status} |
{payout} |
| Everflow | {transaction_id} |
Set per postback event | {sale_amount} |
| TUNE / HasOffers | {transaction_id} |
Set per postback event | Fixed or dynamic value |
| Affise | {clickid} or {click_id} |
{status} (1=Approved, 2=Pending, 3=Declined) |
{sum} |
The parameter name you used to send the click ID out to the network has to match what their postback fires back with. Sent click_id=abc123? Confirm their outgoing postback macro reads that same field, not a differently-named one. This mapping is what silently breaks more setups than anything else on this list.
Most networks fire separate postbacks for lead, sale, rejected, and chargeback. Map each to the matching status in Keitaro so your reporting tells a real sale apart from a lead that got rejected two days later.
Attribution window by vertical: know before you panic
This one isn’t optional knowledge — it’s the difference between correctly diagnosing a broken postback and wasting an afternoon “fixing” something that was never broken.
| Vertical | Typical conversion delay | When to expect postback | When to start debugging |
|---|---|---|---|
| Sweepstakes / COD | Minutes | Under 5 min | After 15 min |
| Gambling (deposit) | Minutes to 1 hour | Under 60 min | After 2 hours |
| E-commerce (after shipping) | Hours | Same day to 72h | After 3 days |
| App install (CPI) | Minutes | Under 10 min | After 30 min |
| Finance / crypto leads | Days to weeks | 1–21 days after lead | After 21 days |
Use redirect postback as the first fallback — the network routes the user through a tracking URL carrying the click ID on the way. A hybrid setup (pixel + S2S) catches conversions from older integrations while you push for proper postback support. And honestly, just ask: most networks that don’t advertise S2S still support it — it’s often a setting an affiliate manager flips on request.
Common postback setup mistakes
| Mistake | Why it happens | Fix |
|---|---|---|
| Click ID never reaches the landing page | Offer URL macro name doesn’t match what the network expects (click_id vs clickid vs subid) |
Check the network’s macro docs and match the parameter name exactly, case-sensitive |
| Duplicate conversions | Network fires the postback more than once for the same event — retry logic, or a redirect pixel and S2S both firing | Deduplicate in your tracker by click ID plus status; ask the network whether they retry failed postbacks |
| Postback URL missing the security key | Copied the URL structure from a guide instead of generating it fresh from your own tracker | Always pull the postback URL directly from Settings → Postback URL in your own account, key intact |
| Wrong macro syntax | Postback URL copy-pasted from a different tracker or an outdated guide | Generate the URL fresh from your current tracker’s settings, never from memory or an old doc |
| Postback doesn’t fire through a redirect chain | Click ID gets dropped or overwritten at an intermediate hop — a cloaker, page builder, or shortener | Walk the full chain manually and confirm the click ID survives every redirect; log the final URL |
Timing and testing mistakes
| Mistake | Why it happens | Fix |
|---|---|---|
| Assuming a broken postback after 10 minutes | Didn’t account for the offer’s attribution window — finance and crypto leads can take days | Check the vertical’s typical conversion delay before troubleshooting; see the table above |
| Testing without a real click | Calling the postback URL by hand with a made-up click ID that was never logged | Run one real test click through your actual funnel first, then convert, so a matching click ID exists |
| SubIDs get truncated or stripped | Network strips parameters it doesn’t recognize, or hits a URL length limit | Shorten values, avoid special characters, confirm supported custom parameters in the network’s macro docs |
How to test that your postback is working
Don’t launch real spend against an unverified postback. Run through this before you do:
If you’re comfortable in a terminal, there’s a faster way to isolate whether the tracker side works before you even touch the network: grab a real click ID from your tracker’s click log and hit your own postback URL directly with curl:
curl "https://YOUR-DOMAIN.COM/postback?subid=REAL_CLICK_ID&status=sale&payout=25&key=YOUR_POSTBACK_KEY"
If the tracker responds to a request with the key missing or wrong, your postback URL isn’t actually protected — and that’s worth fixing before it’s worth anything else on this list. A tracker that accepts any call regardless of key is open to conversion fraud.
Beyond basic setup: advanced SubID strategies
Once postback is reliably working, SubIDs stop being plumbing and start being your actual reporting layer.
Push a unique sub4 value per ad creative and you get conversion rate and payout broken out per creative, not just per campaign — the only real way to know if creative A is outperforming creative B, rather than just getting more impressions and looking busier.
If you’re running the same offer across multiple placements or ad accounts, a consistent sub1/sub2 scheme lets you filter one master campaign down to exactly the slice you want, instead of building a separate campaign per source purely for reporting reasons.
And because payout comes back through the postback tagged with the full SubID chain, you can build a report showing cost (pulled from the ad platform) against revenue from the postback at the individual ad ID level. That’s the resolution you actually need for kill/scale decisions — eyeballing campaign-level totals just tells you something is dragging the average down, not what.
Which tracker should you use
All four options below support S2S postback. The differences are in hosting model, price, and who they’re actually built for.
| Tracker | Hosting | S2S support | Best for | My take |
|---|---|---|---|---|
| Keitaro | Self-hosted or cloud | Strong | Solo affiliates, most setups | Default pick — what I use for most of what’s above. Large community, good docs, no surprises. |
| Binom | Self-hosted only | Strong | Technical affiliates wanting raw speed | Fastest click processing of the four. Minimal UI. Good if you’re technical and want speed over hand-holding. |
| Voluum | Cloud only | Strong | Agencies, teams, polished reporting | Nicest UI. Worth the premium for teams; overkill for a solo affiliate under $10k/mo spend. |
| RedTrack | Cloud only | Strong | Facebook / Google cost-data integration | Solid mid-tier option with the best native cost-pulling integrations for paid social. |
Real example: what changed when I fixed my postback
One account I reviewed was running push traffic to a sweepstakes offer on a pixel-only setup carried over from an old campaign template. The tracker showed 340 conversions for the month. The network’s dashboard showed 436 — a 22% gap, almost entirely from in-app browsers and ad-blocked sessions where the pixel simply never fired.
Switched it to S2S: click ID passthrough on the offer URL, postback URL configured on the network’s side, tested end-to-end. The following month the same traffic mix showed an 8% discrepancy — turned out the network’s retry logic was firing the same postback twice for a chunk of conversions whenever their first attempt timed out. Added deduplication by click ID plus status, and the month after that it settled at 3%, which is within the normal range you’d expect from timing differences alone.
Going from 22% down to 3% wasn’t money that showed up out of nowhere. It was money that had already been spent and simply wasn’t being counted, which means every optimization decision made off the old numbers — every creative killed or scaled — had been working from data that was wrong by roughly a fifth.
Glossary
A unique identifier your tracker generates per click, used to match a later conversion back to that specific click. The entire S2S chain depends on this value surviving intact from click to conversion.
A placeholder in a URL, like {subid} or {clickid}, that your tracker or network fills in with real data when the URL fires. Different platforms use different macro names for the same value.
The endpoint that receives a server-to-server notification when a conversion happens, carrying the click ID and conversion details. You hand this URL to the affiliate network.
A unique authentication token embedded in your postback URL that stops anyone else from firing fake conversions into your account. Never strip it out or share it publicly.
A fallback where conversion data passes via a redirect through a tracking URL, rather than a direct server call. Less reliable than true S2S but a real step up from a bare pixel.
Two servers exchanging data directly, with no involvement from the user’s browser. No JavaScript, no cookie, no device ID required.
A custom parameter on a tracking link that carries extra context (source, campaign, creative) through to conversion reporting. Treat each slot as a fixed field decided before launch.
Frequently asked questions
Does postback work with all affiliate networks?
Most established networks support it today; it's close to standard now. Smaller or newer ones sometimes only offer a redirect postback or a bare pixel. Check the network's tracking docs, or just ask your affiliate manager — support is often available on request even when there's no self-serve toggle in the dashboard.
What if my affiliate network doesn't support S2S?
Use redirect postback if it exists, or run pixel and S2S together as a hybrid. Ask your affiliate manager directly — support for S2S tracking is often available on request even when it's not surfaced in the dashboard. Smaller networks that only offer a pixel are worth pushing on this.
Can I use postback without a tracker?
Technically, yes — if the network lets you point a raw postback URL at your own server or a webhook. But you lose click-level matching, SubID reporting, and a dashboard. Past a handful of test clicks, a tracker like Keitaro earns back the setup time quickly. Without click-level data, you can't segment by source, creative, or placement.
Is my postback URL actually secure once it's set up?
Only if the postback key is intact in the URL you handed the network. Without it, anyone who gets hold of that URL can fire fabricated conversions into your account. Test this directly: hit your postback URL with the key missing or wrong and confirm the request gets rejected, not accepted.
How do I debug a broken postback?
Work backward: confirm the click ID shows up at the landing page URL, confirm it survives to the network's conversion event, check the network's outgoing postback log if they expose one, then check your tracker's incoming S2S log. It's almost always one specific hop where the click ID gets dropped or overwritten, and checking each step in order finds it fast.
How often should I check my postback logs?
For active campaigns, check Maintenance → Logs → S2S Postbacks once a day for the first week after setup, then once a week once it’s stable. If you see a sudden drop in logged postbacks without a corresponding drop in traffic, that’s your signal something broke — usually a macro mismatch caused by a network updating their postback format on their end without warning.
Once postback is running and giving you clean conversion data, the actual work is in building offers and traffic that convert — not debugging a broken attribution layer. I cover tracker setup in the Keitaro review in more detail, and if you’re still picking which network to run with, the affiliate catalog is the fastest way to filter for ones that document S2S support upfront.
Share
SUBSCRIBE TO OUR PRIVATE CASES AND USEFUL TIPS
Subscribe to our newsletter, get only exclusive content and weekly digests, no any spam!
By providing my email, I accept the Privacy Policy.