Tutoriel

Branch Webhook Integration for Affiliate Tracking: The Setup Guide

Dev Team

Dev Team

Integration Engineering

  12 min

Branch came to attribution from deep linking, and it shows in the integration surface: attribution context rides on link analytics tags rather than free-form query macros, and conversions arrive as JSON POST webhooks with a nested payload instead of the flat GET postbacks AppsFlyer and Adjust send. Neither difference is hard to handle — but both break integrations that assume every MMP looks the same. This guide covers the Branch-specific work. For the tracker–MMP architecture generally, start with the mobile attribution guide.

How Branch Differs from Other MMPs

Three things set Branch apart for a network integration. First, the link itself is the product: a single Branch link deep-links into an installed app, routes to the correct app store otherwise, and falls back to web — which makes it unusually good for affiliate traffic that starts on web content. Second, attribution context travels in Branch's tilde-prefixed analytics tags (~campaign, ~channel, ~feature) plus Branch's own click ID, ~id, generated per click. Third, reporting is webhook-based: JSON POST requests with user, touch, and event data in separate nested objects.

Step 1 — Map the Link Analytics Tags

As with every MMP, the mapping between platform naming and your affiliate hierarchy is the core decision. The canonical Branch mapping:

Branch tagTracker macroMeaning
~id{click_id}Branch click ID — the round-trip key
~campaign{campaign_name}Campaign identity
~channel{affiliate_id}Publisher / affiliate ID
~feature{source}Traffic source
sub_aff_id (link data){sub_aff1}Sub-affiliate drill-down

Note the inversion relative to other MMPs: Branch's ~id is generated by Branch, not by you. Your tracker does not push a click ID into the link — it receives Branch's click ID in the webhook and joins on the campaign and channel context you set on the link. Populate ~channel with the publisher ID on every link so both systems can report source-level quality; attribution context on the deep-link parameters is required, not decorative.

Step 2 — Build the Branch Link

Branch links are minted via the dashboard, the link API, or per-click by your tracker. A production-shaped example of the resulting structure:

https://yourapp.app.link/abcDEF
   ?~campaign={campaign_name}
   &~channel={affiliate_id}
   &~feature=affiliate
   &sub_aff_id={sub_aff1}
   // ~id is generated by Branch at click time

Because the same link serves install, open, and web-fallback journeys, one affiliate link covers the full web-to-app funnel — the scenario where conventional app tracking links quietly lose attribution at the store boundary.

Step 3 — Configure the Webhooks

In the Branch dashboard, register your tracker's endpoint for the events you pay on: INSTALL at minimum, plus the commerce and custom events behind your CPA rules. Confirm the webhook template includes ~id — it is how each event reconnects to the click — and your identifiers from the link data. Unlike AppsFlyer and Adjust, where the URL template carries the macros, Branch's webhook body carries everything; the endpoint registration is just a destination plus event filters.

Step 4 — Parse the Nested Payload

A Branch webhook is a JSON document with three objects your pipeline reads from:

{
  "name": "INSTALL",                    // or PURCHASE, custom events
  "timestamp": 1752742800000,           // epoch milliseconds
  "user_data":  { "os": "ANDROID", "aaid": "...", "idfa": null,
                  "ip": "...", "model": "...", "country": "US" },
  "last_attributed_touch_data":
                { "~id": "1234...", "~campaign": "...",
                  "~channel": "aff_1042", "sub_aff_id": "..." },
  "event_data": { "revenue": 24.99, "currency": "USD" }
}

The joins that matter: click identity from last_attributed_touch_data.~id, publisher context from ~channel and your link data, device identity from user_data (note Android's advertising ID arrives as aaid, not gaid), and revenue from event_data for RevShare and CPA payouts. Treat INSTALL and FIRST_OPEN as the install class; everything else maps through your event rules.

Step 5 — Secure, Filter, Deduplicate

Branch signs webhooks with a shared secret as an HMAC-SHA256 over the raw body — verify with a constant-time comparison and reject mismatches before any parsing. Affclix does this automatically when the Branch Secret is configured on the integration, and flags unsigned integrations in logs. Then apply the standard payable-event filters: organic detection on Branch payloads means checking the attributed touch data — a ~channel of organic or an empty ~campaign is unattributed traffic and must not convert. Deduplicate on ~id + event name, since undelivered webhooks are retried, and run survivors through your normal fraud screening — Branch webhooks carry no fraud verdict field, so the tracker-side layers do all the work here.

No MMP fraud verdict on this path

AppsFlyer postbacks carry a fraud_reason field; Branch webhooks do not. Your tracker's own timing, device, and concentration analysis is the only fraud gate on Branch traffic — make sure it is on.

Reconciliation and Gotchas

  • Webhooks arrive without ~id — the webhook template omits it. Re-add the field in the dashboard template; events without it cannot be joined to clicks.
  • Timestamps look wrong by a factor of 1,000 — Branch sends epoch milliseconds where most MMPs send seconds. Parse accordingly or every event lands in 1970 or 57,000 AD.
  • Android device IDs missing — you are reading gaid; Branch's field is aaid inside user_data.
  • Installs counted twice — both INSTALL and FIRST_OPEN webhooks enabled and treated as separate conversions. Collapse them into one install class.
  • Numbers drift vs the Branch dashboard — reconcile against the daily export API rather than dashboard aggregates, and verify organic filtering matches on both sides.

Affclix's Branch integration handles all of the above out of the box — nested payload parsing, ~id mapping, millisecond timestamps, aaid normalisation, HMAC verification, organic and duplicate filtering, and daily export reconciliation. Alongside the AppsFlyer and Adjust guides, this covers the three MMPs you will meet most often — the series continues with Kochava, Singular, and Apptrove.

Connect Branch on Affclix

Questions fréquentes

How is a Branch webhook different from a normal MMP postback?

Most MMPs fire GET postbacks with your macros substituted into the query string. Branch sends JSON POST webhooks with a nested payload — user data, last attributed touch data, and event data as separate objects — so your tracker parses fields out of the structure instead of reading query parameters. The attribution logic is the same; the transport and parsing are not.

How do I pass my affiliate click ID through a Branch link?

Branch generates its own click ID (~id) for every link click, and you can attach your own identifiers as link data or analytics tags. The reliable pattern is to map Branch's ~id into your tracker's click ID parameter on the webhook, and carry your publisher and campaign IDs in the ~channel and ~campaign analytics tags so both systems can report at source level.

Can Branch track web-to-app affiliate journeys?

Yes — deep linking is Branch's core strength. A single Branch link routes users to the app store, the installed app, or a web fallback, and attribution survives the store redirect. For affiliate programs promoting apps through web content, this closes the gap where a web click would otherwise lose attribution at the install boundary.

Dev Team

Dev Team

Performance marketing practitioner at AffClix, writing about affiliate tracking, fraud prevention, publisher management, and network operations.

Related Articles

Tutoriel

AppsFlyer Postback Integration for Affiliate Tracking: The Setup Guide

Tutoriel

Adjust S2S Callback Integration: The Complete Setup Guide