Overview
The Branch Mobile SDK uses a RESTful API (v1/open) for deep linking and session attribution. The instructions below cover how to supply a payload of attribution properties to this API server-side. Every time the API is called, it will track an INSTALL
, REINSTALL
, or OPEN
event in Branch and return deep link data in the response if the session is attributed.
By bypassing the SDK, developers will be responsible for session management (when & where the v1/open API is called), handling poor or no connectivity, persisting data locally, retrieving values like IP address, tracking downstream conversions, creating shareable deep links, etc. To achieve feature parity with the SDK, one would need to duplicate the code in the SDK.
It is highly recommended that all apps use the Branch Mobile SDK when possible.
API Access is restricted
The ability to directly call the v1/open API is restricted to select enterprise accounts. Please contact your Branch Account Manager to confirm if your account is eligible for enablement.
Prerequisites
- App is setup in the Branch dashboard with default link redirects, your app.link domains, a URI scheme, Universal Links, and you have access to your API & Secret keys
- Account has been enabled to access the v1/open API
Dashboard & In-App setup required
Successful use of the v1/open API will require setup steps in the Branch dashboard and in your mobile app
API Setup
The network request to v1/open should occur when you are successfully notified the app was brought to the foreground. Branch defines an app lifecycle as a session of when your application is launched (cold start, or if it was present in the iOS or Android task manager), and comes to the device’s foreground.
Endpoint Specifications
- Endpoint:
https://api2.branch.io/v1/open
- Method: POST
- Payload Format: JSON
- Required Header: The device's public IP address must be set using
-H "X-IP-Override: xx.xx.xx.xx"
(it is critical this uses the device's IP, and not your server's IP) - Required Header:
-H 'content-type: application/json'
POST body parameters
Property | Data Type | Description | Example |
---|---|---|---|
branch_key | String | REQUIRED Your production API key, retrieved from Account Settings of your dashboard's Live environment | key_live_example |
branch_secret | String | REQUIRED Your production API Secret, retrieved from Account Settings of your dashboard's Live environment | secret_live_example |
server_to_server | Boolean | REQUIRED Always set to true | true |
app_version | String | REQUIRED Your app's version | "1.12.4" |
os | String | REQUIRED Only accepts Android oriOS | “Android” |
os_version | String | REQUIRED The version of the device's OS (e.g. “23” for Android or “9.1.2” for iOS respectively. Will accept any value, preferred default to “NA”. This cannot be blank.) | "13.2.2" |
user_agent | String | REQUIRED The user agent of the device | "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6 Build/MOB31E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537.36" |
hardware_id | String | REQUIRED In iOS, populate with the IDFA if it's available, otherwise fallback to IDFV. On Android, populate with the ANDROID_ID (hardware id). If no device ID is available, do not include in request. | iOS: "D5B89252-FCF8-4065-88FC-B70F49186988" Android: "fae098e4605e79c3" |
hardware_id_type | String | REQUIRED - iOS ONLY Value confirms whether the iOS ID in the hardware_id property is an "idfa" or "vendorid" (_do not include in request, if hardware_id is not populated) | "idfa" or "vendor_id" |
ios_vendor_id | String | REQUIRED - iOS ONLY The IDFV if it's available, otherwise do not include in request. | "0C381C08-B808-4C25-BE51-B00BC165B5F8" |
google_advertising_id | String | REQUIRED - ANDROID ONLY The Google Advertising ID if it's available, otherwise do not include in request | "ea31e5e0-1aa5-4181-91d7-0b56524e0274" |
advertising_ids | Object | ANDROID ONLY The set of Advertising IDs if it's available, otherwise do not include in request. Can include identifiers like OAID | "advertising_ids": { "oaid": "02ab41d3-7886-4f29-a606-fba4372e9fdc" } |
is_hardware_id_real | Boolean | REQUIRED Set to false if the hardware_id property cannot be populated, otherwise default to true | true |
ad_tracking_enabled | Boolean | REQUIRED A value used to determine whether the IDFA or GAID can be used for advertising purposes. If Limit Ad Tracking should be enabled, do not include in the request. | true |
local_ip | String | This is the device's local IP address, if one is available. This is incremental to the required IP header. An optional but highly recommended data metadata that improves attribution accuracy. | "192.168.1.153" |
screen_height | Int | Height of the device’s screen. An optional but useful data metadata that improves attribution accuracy. | 2208 |
screen_width | Int | Width of the device’s screen. An optional but useful data metadata that improves attribution accuracy. | 1242 |
link_identifier | String | a URI opens the app, check for a link_click_id query, and populate with that value (if missing, do not include in request)link_click_id may also be sourced by the Google Install Referrer | “823569794275788167” |
universal_link_url | String | Populate with a Branch or non-Branch web url that opened the app (if missing, do not include in request) | "https://branch.app.link/example?utm_medium=test" |
android_app_link_url | String | Populate with a Branch or non-Branch web url that opened the app (if missing, do not include in request) | "https://branch.app.link/example?utm_medium=test" |
facebook_app_link_checked | Boolean | Set to false to ensure we retrieve deep links from Facebook's deferred deep linking API (requires adding your Facebook App Secret to the [Branch dashboard](https://help.branch.io/using-branch/docs/facebook-app-install-ads#section-setup)) | true |
install_referrer_extras | String | ANDROID ONLY Populate it with the value of the full Android PlayStore Install Referrer URL. Only include in the app's first session, if it's available. | "utm_source=some_source&utm_medium=preload&utm_campaign=null&gclid=Cj0KCQiA7IDiBRCLARIsABIPohhqdEU00f-Obte_OIVTbjPo-iLDBjkhj8ov=" |
google_search_install_referrer | String | ANDROID ONLY The value of the google_search_install_referrer query parameter on the referrerUrl from the Google Install Referrer. Only include in the app's first session, if it's available. | "7AXhuEQs1U" |
clicked_referrer_ts | Long | ANDROID ONLY The referrer click timestamp collected from the Play Install Referrer library. Only include in the app's first session, if it's available. | 1573098834 |
install_begin_ts | Long | ANDROID ONLY The install begin timestamp collected from the Play Install Referrer library. Only include in the app's first session, if it's available. | 1573098843 |
apple_attribution_token | String | iOS ONLY Attribution Token used for Apple Search Ads . used to call the Apple Search Ads Attribution API. The token has a 24 hr TTL, so send to Branch within that time in order to use it for attribution. | "c7ya5fQsXrqhCiG0eQTvpS8+tNpBom1RwlDmWEXGNqIj1AOn/VDlqgKq9CaJzzFeR8G3dEeMQBJc60R4CxIx..." |
search_ad_encoded | String | ⚠ DEPRECATED ⚠ iOS ONLY Base64 encoded string of the entire response from the Apple Search Ads API. Only include in the app's first session, if it's available. | "eyJWZXJzaW9uMy4xIjp7ImlhZC1wdXJjaGFzZS1kYXRlIjoiMjAyMC0wNi0yOVQxODo1MDoxNloiLCJpYWQta2V5d29yZCI6IktleXdvcmQiLCJpYWQtYWRncm91cC..." |
first_session | Boolean | Identifies if this is the first time the user opened the app. If true , Branch will check if we saw the user download the app before, and mark the session as a reinstall if yes, and an install if no. If this value was set to false , Branch will count the session as an open. | true |
server_to_server_identity | Boolean | Setting to true enables the ability to set an randomized_bundle_token property in v1/open requests and returns a value in the response. Do not set this property in the request, if this feature will not be used. | false |
randomized_bundle_token | Boolean | If server_to_server_identity is true , Branch returns a new identity value in any request that does not set randomized_bundle_token . After the first request, this property must be hardcoded with the randomized_bundle_token received in the first network response. Failure to return this value in subsequent requests severely limits the ability to connect different events for that user. | "791040498773585647" |
identity | String | If server_to_server_identity is true , this property can be used to associate a custom user ID with Branch's anonymous identity. You should never use personal user information here, and all values should be encrypted before being passed to Branch. | "U1923847128356" |
tracking_disabled | Boolean | If set to true , Branch will not store any data from this app session. The network response can still return deep link data for processing, but no information will be stored afterwards. | false |
disable_ad_network_callouts | Boolean | If set to true , you can use the Branch dashboard to selectively remove sessions with this flag from being sent to ad networks | false |
local_url | String | (Optional, for NativeLink) Populate with a Branch web url that is present on the clipboard on the very first open (if missing, do not include in request) | "https://branch.app.link/example?utm_medium=test" |
referrer_gclid | String | ANDROID ONLY (Optional, for Google AdWord Campaigns) Extract the value of gclid from Android PlayStore Install Referrer URL. Utilized for tracking downstream events on Google Adwords when user opts out on Android 12+ devices (if missing, do not include in request) | "CjwKCAiA3L6PBhBvEiwAINlJ9Chixm216y8kYYJ1K94dm4FEkOgFfhIdKQdjWsYB7FqE7rf_zkGNEhoCuIEQAvD_BwE" |
gbraid | String | IOS ONLY (Optional, for Google AdWord Campaigns) Extract the value of gbraid from the referring url/uri for the app session. Utilized for tracking downstream events on Google Adwords when users are opted out of ATT (if missing, do not include in request) | "CjwKCAiA3L6PBhBvEiwAINlJ9Chixm216y8kYYJ1K94dm4FEkOgFfhIdKQdjWsYB7FqE7rf_zkGNEhoCuIEQAvD_BwE" |
custom_param_1 | String | A customized parameter attached to your OPEN, INSTALL, or Event metadata to be used for visualizing/analyzing Branch aggregate data in both the Branch Dashboard reports and exports. | "PARAMETER 1" |
custom_param_2 | String | A customized parameter attached to your OPEN, INSTALL, or Event metadata to be used for visualizing/analyzing Branch aggregate data in both the Branch Dashboard reports and exports. | "PARAMETER 2" |
custom_param_3 | String | A customized parameter attached to your OPEN, INSTALL, or Event metadata to be used for visualizing/analyzing Branch aggregate data in both the Branch Dashboard reports and exports. | "PARAMETER 3" |
Example Requests
iOS
curl -v -d '{
"branch_key": "TODO",
"branch_secret": "TODO",
"server_to_server": true,
"app_version": "1.12.4",
"os": "iOS",
"os_version": "10.0",
"model": "iPhone",
"screen_height": 2208,
"screen_width": 1242,
"facebook_app_link_checked": false,
"user_agent": "{FULL_USER_AGENT_HERE}",
"hardware_id": "D5B89252-FCF8-4065-88FC-B70F49186988",
"hardware_id_type": "idfa",
"ios_vendor_id": "0C381C08-B808-4C25-BE51-B00BC165B5F8",
"is_hardware_id_real": true,
"ad_tracking_enabled": true,
"custom_param_1": "Parameter 1",
"custom_param_2": "Parameter 2",
"custom_param_3": "Parameter 3"
}' "https://api2.branch.io/v1/open" -H "X-IP-Override: 1.2.3.4"
Android
curl -v -d '{
"branch_key": "TODO",
"branch_secret": "TODO",
"server_to_server": true,
"app_version": "1.12.4",
"os": "Android",
"os_version": 26,
"model": "SM-G960U1",
"screen_height": 2076,
"screen_width": 1080,
"facebook_app_link_checked": false,
"user_agent": "{FULL_USER_AGENT_HERE}",
"hardware_id": "fae098e4605e79c3",
"google_advertising_id": "ea31e5e0-1aa5-4181-91d7-0b56524e0274",
"advertising_ids": {
"oaid": "02ab41d3-7886-4f29-a606-fba4372e9fdc"
},
"google_search_install_referrer": "referrer_value_here",
"clicked_referrer_ts": 1574699946,
"install_begin_ts": 1574699955,
"is_hardware_id_real": true,
"ad_tracking_enabled": true,
"custom_param_1": "Parameter 1",
"custom_param_2": "Parameter 2",
"custom_param_3": "Parameter 3"
}' "https://api2.branch.io/v1/open" -H "X-IP-Override: 1.2.3.4"
Rate limits on non-referred OPENs
Branch by default will rate limit non-referred
OPEN
events (app sessions not sourced by a link) per IP address, to once every 4 hours (contact your Branch Account Manager to confirm the exact limit for your account). Rate limited sessions will still return deep link data in the network request, but their data will not appear in the dashboard nor in your exports.
Rate limits on high-frequency pings
Because the v1/open API is intended to measure a user's app session, we will return 429 responses if the app starts sending requests for the same user in rapid succession. Because normal user behavior is not to open & close an app in rapid succession, this scenario will likely only occur during testing. If you run into this, please wait a few minutes before resuming testing (or try changing the device metadata in your request).
NativeLink
In order to implement NativeLink (learn more) and benefit from a guaranteed mechanism for deep linking, you will need to check the pasteboard on the first install. If it contains a URL, then examine the contents of the pasteboard. If it contains a Branch link, please send the full URL in the request body for key
local_url
.For an example of checking the pasteboard on iOS, see this code snippet in our open-source iOS SDK.
Handling deep link data
When the v1/open request is made, the app session can be attributed to a deep link click. Regardless if the session is attributed, the API will always return a 200 response with some contextual data included in the JSON response payload. If the session was attributed to a Branch link, this payload will include the link's deep link data for your in-app logic to use to execute your deep link UX.
Samples responses are listed below, but a few key parameters to be aware:
Parameter | Description |
---|---|
randomized_bundle_token | If you set server_to_server_identity to TRUE in the v1/open request, you must ensure the value returned here is used in the randomized_bundle_token property of all v1/open requests moving forward for that device. |
+clicked_branch_link | This will tell you if the current app session was sourced via Branch deep link. This can be used as a conditional trigger that dictates if you use Branch-specific or other deep link routing logic. |
+non_branch_link | If a non-Branch deep link opened your app (i.e., a Universal Link), you can retrieve that link from this key. |
+is_first_session | This will be TRUE if Branch has never seen this user's device install the app before |
+match_guaranteed | This will be TRUE if Branch was able to match the app session to the browser click with 100% certainty. This can be used as a conditional trigger for use cases where you have zero risk threshold for a false positive (this should NOT be used in most instances)[Not applicable to SAN attributed Install]. |
$canonical_url | This will contain a web url that you can use for deep link routing. If your app was already setup to route off Universal Links or Android App Links, you can pass this value into that pre-existing routing logic. |
$deeplink_path | This will contain a URI relative path that you can use for deep link routing. If your app was already setup to route off URI schemes, you can pass this value into that pre-existing routing logic. |
Example organic response
{
"session_id": "xxxx",
"randomized_device_token": "xxxx",
"link": "https://bnc.lt/j/adsf",
"data": "{\"+clicked_branch_link\":false,\"+is_first_session\":false}"
}
Example organic response, with server_to_server_identity enabled
{
"session_id": "xxxx",
"randomized_bundle_token": "xxxx",
"identity": "xxxx",
"randomized_device_token": "xxxx",
"link": "https://bnc.lt/j/adsf",
"data": "{\"+clicked_branch_link\":false,\"+is_first_session\":false}"
}
Example response when session started by a non-Branch Deep Link
{
"session_id": "823602214081710808",
"data": "{\"+non_branch_link\":\"https://branch.io/\",\"+clicked_branch_link\":false,\"+is_first_session\":false}",
"randomized_device_token": "823601870295755491"
}
Example response when session started by a Branch Deep Link
{
"randomized_device_token": "823600311503935224",
"link": "https://example.app.link/X7OsnWv9TF",
"session_id": "429691081177874743",
"data": "{
"$canonical_url": "https://example.com/home?utm_campaign=test",
"$desktop_url": "http://example.com/home",
"$og_description": "My Content Description",
"$og_image_url": "http://lorempixel.com/200/200/",
"$og_title": "46D6D28E-0390-40E4-A856-BD74F34D24C8",
"+click_timestamp": 1503684563,
"+clicked_branch_link": true,
"+is_first_session": false,
"+match_guaranteed": true,
"custom": "blue",
"~campaign": "new launch",
"~channel": "facebook",
"~creation_source": 3,
"~feature": "sharing",
"~id": 429691043152332059,
"~referring_link": "https://example.app.link/X7OsnWv9TF",
"~stage": "new person",
"~tags": ["one","two"]
}"
}
In-App Setup
iOS
Configuration Updates
- Add your URI scheme to the info.plist
- Add your Branch app.link and alternate.app.link domains to the Associated Domains
App launch data needed for API request
- Retrieve the device ID (IDFA or IDFV) when available
- Retrieve the device’s public IP
- Retrieve the device’s User-Agent
- Examine the AppDelegate's openURL: function for a URI. If a URI containing a query parameter
link_click_id
is present, store the query parameter's value for use in the session's API network request (i.e., if the URIexample://open?link_click_id=1234
opens the app, you will retrieve the “1234” value) - Examine the AppDelegate's continueUserActivity: function for a webpageURL in the NSUserActivity parameter. If a URL is found (regardless if it's a Branch link), store the entire URL value for use in the session's API network request.
[OPTIONAL] To support Apple Search Ads
- For S2S integrations, you will need to retrieve the new token and send to Branch on the install as apple_attribution_token
Please refer to the new AdServices developer documentation on how to retrieve the token.
- Import AdServices.framework
- Request attribution token (see sample code). This should be available from Apple within 50ms.
- The token has a 24 hr TTL, so send to Branch within that time in order to use it for attribution.
See sample code for obtaining the Apple Attribution token:
func appleAttributionToken() -> String? {
if #available(iOS 14.3, *) {
return try? AAAttribution.attributionToken()
}
return nil
}
+ (NSString *)appleAttributionToken {
#if !TARGET_OS_TV
if (@available(iOS 14.3, *)) {
NSError *error;
NSString *appleAttributionToken = [AAAttribution attributionTokenWithError:&error];
if (!error) {
return appleAttributionToken;
}
}
#endif
return nil;
}
OLD FRAMEWORK: All steps below should only occur for the INSTALL session:
- Upon app launch, do not call v1/open, and first query the Apple Search Ads API. Apple's API is know to have high latency and operates at a race condition with its ad click (i.e., it must process the search click before it can respond to its attribution API), so give a 2 second buffer before calling Apple's Attribution API.
- Implement retry logic (Branch's SDK uses 2 second delays between retries) if your request times out after 5 seconds, or if the response returns as False or Error Code [0,2,3]
- If a successful response is received, base64 encode the entire API response, and add it to the
search_ad_encoded
property of the v1/open. Do not populate this in v1/open if apple did not attribute the session, and do not repeat this process during subsequent app sessions.
Android
Configuration Updates
- Add your URI scheme to the Android Manifest
- Add your Branch app.link and alternate.app.link domains to the Android Manifest
App launch data needed for API request
- Retrieve the device ID (GAID or Android_ID when available
- Retrieve the device’s public IP
- Retrieve the device’s User-Agent
- Examine the intent that opened your MainActivity for a URI. If a URI containing a query parameter
link_click_id
is present, store the query parameter's value for use in the session's API network request (i.e., if the URIexample://open?link_click_id=1234
opens the app, you will retrieve the “1234” value) - Examine the intent that opened your MainActivity for a web URL. If a URL is found (regardless if it's a Branch link), store the entire URL value for use in the session's API network request.
[OPTIONAL] To support Google Play Install Referrer
All steps below should only occur during the INSTALL session:
- Upon app launch, query the Google Play Install Referrer library for the referrer Url, click timestamp, and install timestamp
- Examine the referrer Url for a “link_click_id” query parameter, and if present, retrieve its value for use in the v1/open
link_identifier
property. This may appear in the referrer Url as&link_click_id=<value>
or&link_click_id-<value>
, but in either scenario you're only extracting the<value>
part. - Examine the referrer Url for a “google_search_install_referrer” query parameter, and if present, retrieve its value for use in the v1/open
google_search_install_referrer
property. This may appear in the referrer Url as&google_search_install_referrer=<value>
or&google_search_install_referrer-<value>
, but in either scenario you're only extracting the<value>
part.
Tracking Downstream Events
Every time the v1/open API is called it will track an INSTALL
, REINSTALL
, or OPEN
event in Branch. To track additional downstream conversion events (i.e., PURCHASE
), you will need to use the HTTP API instructions for our Commerce, Content, Lifecycle, and Custom events.
When tracking downstream conversion events, please address the following items:
- If the request is made from the device, we will automatically retrieve the IP address from the request. If the request is made from a server, the user's IP address must be set via the following header:
-H "X-IP-Override: xx.xx.xx.xx"
- Set the device’s user agent in the request body’s
user_data.user_agent
- For events occurring in app, populate a device ID with IDFA (and fallback to IDFV) in iOS, or GAID (fallback to android_id) in Android
- For events occurring on web, retrieve a Browser fingerprint via the Branch web SDK, to be included in the event call
- Populate the developer_identity property whenever a persistent user ID is available (Best Practices for user IDs)
Server-to-Server Integrations with the TUNE API
All clients scoping a net new integration, should only consider the Branch SDK or server-to-server integration, and should NOT integrate with the TUNE API server-to-server. Any apps that originally integrated TUNE server-to-server, before TUNE was acquired by Branch, can find the API specs below for troubleshooting purposes:
For existing TUNE server-to-server integrations, it is good to confirm the following metadata properties are accounted for, to ensure TUNE integrations can leverage Branch's latest attribution methodologies:
Key | Description |
---|---|
ios_ifa | REQUIRED - iOS The IDFA if it's available |
ios_ad_tracking_disabled | REQUIRED - iOS If the ios_ifa parameter is going to be used, then the ios_ad_tracking_disabled parameter must be specified to indicate whether the end user has enabled limited ad tracking (with 1 being enabled/limited). |
ios_ifv | REQUIRED - iOS Populate with the IDFV |
google_aid | REQUIRED - Android The Google Advertising ID if it's available. Formatted as uppercase with hyphens. AAAAAA-BBBB-CCCC-11111-2222222222222 |
google_ad_tracking_disabled | REQUIRED - Android If the google_aid parameter is going to be used, then the google_ad_tracking_disabled parameter must be specified to indicate whether the end user has enabled limited ad tracking (with 1 being enabled/limited). |
os_id | REQUIRED - Android Populate with the ANDROID_ID (hardware id), if google_aid cannot be populated |
device_id | REQUIRED - Windows The Windows Hardware ID |
windows_aid | REQUIRED - Windows The Windows advertising identifier (AID) is a unique, user and device-specific, and resettable ID for advertising represented as an alphanumeric string formatted as upper case without colons (for example, "AAAAAABBBBCCCC111122222222222"). When the advertising ID feature is disabled, this value is an empty string. |
referral_url | REQUIRED For Android and its first app open, include the Google Play install referrer. For all other opens on Android and iOS, include the URL that caused the open (deep link). |
device_ip | REQUIRED IP address of the user device recorded on conversion. This must be set via API query parameter, as the TUNE API cannot ingest an X-IP-Override Header |
device_brand | REQUIRED Brand or maker of the user device (such as "Apple" or "Samsung") |
device_model | REQUIRED Model of the user device recorded on conversion (such as "iPhone5,2" or "GT-i9300") |
user_agent | REQUIRED The device's user agent. This can also be set in a network request header. |
os_version | OPTIONAL Version of the operating system (such as iOS or Android) on the user device |
device_carrier | OPTIONAL Carrier of the device if supports cellular (such as AT&T) |
language | OPTIONAL Language of the device from local settings |
country_code | OPTIONAL The ISO ALPHA-2 or ISO ALPHA-3 value of the country |
app_version | OPTIONAL Version of the app on the user device (this parameter helps TUNE distinguish between new app installs and existing app updates) |
user_id | OPTIONAL The ID of the user defined by the advertiser |
local_ip is not supported on TUNE API calls
local_ip is leveraged for Branch's Predictive Modeling capabilities, but this cannot be set in TUNE API calls. This will not prevent attribution on the TUNE API endpoint.