The release of iOS 14.5 is on the horizon, and with it will come some major disruptions to mobile marketing on iOS. In this blog post, we are going to show you how these changes will be reflected in your Branch data, and explain a few updates you may want to make to your Branch app configuration.
If you prefer, we also have a video walkthrough of this material.
Let’s begin by clarifying the overall impact of what we’re discussing today:
On the left, we have an example of your Branch attribution data up until now: a single, combined dataset, with conversion credit deduplicated across all channels. Like any attribution system, there will always be a bucket of “unknown” conversions. This bucket is also sometimes called “organic” or “unattributed”, but all of these terms mean the same thing: conversions the system did not attribute back to a marketing campaign.
On the right, we show what your Branch data will look like after Apple’s new iOS 14 privacy policy is enforced: in that single combined report you’re used to seeing, all of the conversions previously attributed to the Ads channel will now appear as “unknown”. And there will be a separate pool of attribution data for your ads, provided via Apple’s new SKAdNetwork framework.
Due to the way Apple designed SKAdNetwork, this ads data is only available for some of the common ad campaign types currently used today. It is not device-level data, which means it’s far less granular than you’re used to, and it cannot be deduplicated against any other marketing channel.
Fortunately, there is a way to win back some of that granular, device-level ads data within the combined, de-duplicated report: you can get your users to opt in via Apple’s new AppTrackingTransparency framework:
It’s worth getting something clear right up front: there is no silver bullet solution that will make things continue working the way they always did in the past. Everyone in the ecosystem — from MMPs to ad networks to publishers to advertisers like you — has to figure out how to deal with Apple’s changes.
Ad attribution on iOS will be far more complex after the release of iOS 14.5. The Branch product improvements we cover in this post are designed to help with this, but it is impossible to keep things the way they were.
How will your Branch data change?
Let’s start with a simple flowchart that explains which Branch customers will experience these changes:
If you are using Branch for ads attribution and you’re planning to show the ATT prompt to your users, these product changes affect you.
Why does Branch need to make these updates? The core issue is that the ATT opt-in process causes a chronology problem. Here is a typical user conversion journey: click an ad, download the app from the App Store, and open the app. Easy so far.
The problem is what happens next: once the app opens for the first time, the Branch SDK fires and install attribution needs to happen…however, you have not yet had a chance to show the ATT modal to the user:
This is the chronology problem: until you get permission via the modal (likely sometime later, after the initial app open), you don’t get the IDFA nor will you have permission to attribute the ad conversion at the device level.
The analytics product changes that Branch is making are designed to help recover ad attribution for installs in this flow. The solution we’ve built needed to reflect a few important requirements, which are worth explaining:
- The new behavior must fully comply with Apple’s ATT policy. We’ve heard that some other MMPs are planning to “cheat” behind the scenes with probabilistic matching, even without securing user opt-ins via the ATT prompt. We believe Apple intends to crack down on this sort of behavior, and we’re serious about protecting our customers from being banned from the App Store for policy violations.
- Branch must not “rewrite history” by changing events that have already been reported. Retroactive data updates would cause problems and make your workflows far more complex.
- The Branch SDK still needs to fire on initial app open. This is necessary for deep linking and attribution of owned and organic channels, both of which are unaffected by Apple’s ATT policy.
You might be looking at all those new complications and thinking “is trying to get my users to opt-in with the ATT modal even worth it?”
Branch’s advice is yes, in most cases it is worth it. The changes that Apple is making will decrease the level of insight you have into your ads attribution. That is unavoidable, and an unpleasant reality that every single advertiser in the mobile ecosystem needs to deal with.
However, the choice you can still make is between having some data, or no data at all. And even a limited amount of device-level insight will still allow you to make better decisions about things like campaign optimization and LTV.
Examples of the new data flow
Here are the changes we’re making in a nutshell.
First, what we ARE doing:
- We are tracking an additional analytics event we call a “second install.” These second install events are processed the same way as a normal install, and come with data parameters to allow deduplication. Second installs will be triggered for ad-driven installs, after we see user opt-in via ATT. This change will happen automatically for all Branch iOS SDK versions, and no SDK update is necessary.
- Also, while not required, you may update to iOS SDK v1.39.2+ to capture ATT opt-ins and opt-outs as new, dedicated events, and report ATT status on all events.
Now, what we are NOT doing:
- We are not doing any form of device-level attribution for ad-driven installs if the user does not opt in via ATT. Again, this is to make sure that we adhere to Apple’s policy and protect you.
- We are also not re-writing any log-level data on the initial install event after the user opts in. This is to provide simplicity and predictability for your data workflows.
- Finally, we are not triggering “second installs” for opt-ins from non-paid sources, because in those cases we are already able to attribute at a device level without ATT opt-in.
The best way to understand how all of this works is with some hands-on examples that demonstrate what your Branch data will look like for users on iOS 14.5 and above.
Immediate opt-in
The first example flow is the simplest one: when a user clicks an ad link, installs your app, and opts in via ATT immediately after installing.
This flow assumes that the user has already opted in to ATT in the publisher app, which is necessary to make the IDFA available on the first side of the transaction:
Because the user previously opted in, their ad clicks in the publisher app will include IDFAs:
Next, the user installs your app. This install event cannot be credited to the ad click, because the user has not opted in via ATT, which means the attribution data will be ‘incomplete’, and reported as unattributed:
In this scenario, the user opts in to ATT immediately after the install happens, before any other in-app activity. The opt-in triggers the ‘second install’ that can be credited back to the ad click:
When the user then performs a down-funnel conversion event, such as a purchase, that conversion can also be attributed back to the ad click:
Now, let’s imagine the user subsequently clicks another Branch link, such as an email link. It’s worth pointing out that in this case, even though the user has already opted in via the ATT prompt, it’s technically not necessary under Apple’s policy because your emails are an owned channel:
As expected, any conversion events that occur after this email click will be attributed to the email campaign instead of the ad click. This is unchanged from pre-iOS 14 behavior:
To summarize, in this scenario the initial install event will be reported as unattributed or organic. The “second install”, triggered when the user opts in via ATT, will be correctly attributed to the ad click.
Conversion events like purchases will be attributed to the ad click, up until another qualifying link click occurs, after which they will be attributed to that subsequent event as expected:
Delayed opt-in
Now, let’s look at a slightly more complex example. In this scenario, the user clicks an ad, installs, but does not opt in via ATT until some time has passed after the install. This could happen if you decide to delay presenting the ATT prompt until after you’ve had a chance to demonstrate value to the user, in order to increase the chance that they will accept.
As before, this flow assumes that the user has already opted in to ATT in the publisher app, making the IDFA available on the first side of the transaction:
Because the user previously opted in, their ad clicks in the publisher app will include IDFAs:
However, in this scenario, the user does not opt in via ATT right away. This means that the user’s early down-funnel conversion events will also be reported as unattributed:
When the user eventually does opt in, the ‘second install’ is triggered and will be credited back to the ad click:
After opt-in, subsequent conversion events will also be correctly attributed back to the ad click:
To summarize, in this scenario the initial install event will be reported as unattributed. And until the user opts in via ATT, conversion events will ALSO be unattributed.
Once the user opts in, a second install will be triggered and correctly attributed to the ad click. Later conversion events will also be correctly attributed to the ad click.
Branch product changes
Now that we’ve looked at some example user flows, let’s go through how we’re updating various parts of the Branch platform to reflect this raw data.
The changes we’re making fall into two broad categories:
Pre-aggregated reports Because this data is generated at the time of view or request, Branch can dynamically “fix” the data as users gradually opt in after install. These products include:
- The Branch dashboard.
- Query API.
Raw data products. These provide log-level event data, which Branch will not retroactively rewrite. However, depending on your use case, you can choose to perform your own deduplication process. We’ll describe the logic to do that later in this post. Our raw data products include:
- Webhooks.
- Ad network postbacks.
- Custom export API.
- Data Integrations.
The Branch dashboard and Query API “just work”
The good news is if you, like many of our customers, primarily rely on the Branch dashboard and our Query API, those will both “just work” without any additional steps from you.
This means we’ll automatically deduplicate the first and second install events, so that the final numbers you see stay accurate as users opt in:
We automatically deduplicate Second Install events that occur up to 7 days after initial Install. Second installs that occur beyond this window are not deduplicated.
As a reminder, if a paid ads-driven user never opts in, then they will not have a Second Install. As such, we will not be able to remove them from the unattributed data.
The “organic checkbox”
There is one other feature of the Branch dashboard that deserves a special mention: the “organic checkbox.”
By default, most reports on the Branch dashboard show only attributed data. This makes sense, because if you’re looking at a report for something such as ad campaign performance, you usually want to see only conversions attributed to ad campaigns.
In the past, when the Organic checkbox was checked, the report would show a separate segment for unattributed (or ‘organic’) conversions:
This won’t work as expected after iOS 14.5, because that unattributed segment will also include paid ad conversions that have not yet been completed by the user opting in to ATT:
This means the Organic checkbox simply won’t be useful in as many reports, so we are removing it from some dashboard pages to avoid confusion.
Locations where the Organic checkbox will be removed include:
- Summary page
- Journeys tab
- Quick Links tab
- Universal Email tab
- Journeys → Activity tab
- Email → Activity tab
Locations where the Organic checkbox will still be available include:
- Summary page
- All Data tab
- Universal Ads tab
- Ads Analytics → Activity tab
Most customers used the Organic checkbox as a way to compare their campaign performance against a non-campaign baseline.
As an alternative, we’ll be adding a new checkbox to dashboard reports called “Show Total App Traffic”. This will display an additional segment in the report for all traffic (both attributed and unattributed), which will provide a similar baseline for performance comparisons.
Raw data products
With these changes, there are a few data schema updates to be aware of:
First and Second Install events are both reported as installs, and there are two new fields on each event: user_data_opted_in, and days_from_install_to_opt_in.
The user_data_opted_in field reflects the user’s ATT opt-in status, which means it is false for the first install and true for the second. The days_from_install_to_opt_in field gives you the number of days between the first and second Install events.
The timestamp field reflects the time each event occurred (for the first install, this is when the install itself arrived in our system, and for the second install, this is when the user’s opt in arrived). Additionally, on the second install, the event_timestamp field reflects the date that the corresponding first install originally happened.
This table shows the expected behavior for an ad-driven install, broken down by Branch product:
What do you need to DO?
If you only use the Branch dashboard, things are pretty simple: you don’t need to do anything except be aware that your report data may change slightly day-to-day as more users opt in to tracking inside your app
If you use the Query API to pull pre-aggregated data, you should recognize that your report may reflect incomplete attribution data if users have not yet opted in at the time you make the query. To solve for this, you should re-pull data from previous days if users might have opted in after your initial request.
For example: if it’s April 15 and you call the Query API for April 1 through 14, but your app might show the ATT prompt to users up to 6 days after installing, we suggest pulling the data again on April 21 so have you “final” numbers.
If you use the custom export API, you’ll need to be aware that if we return a record for a Second Install, there will already be an incomplete (meaning, unattributed or “organic”) initial Install for that same user somewhere in your data. You can use the deduplication logic discussed below to accommodate this.
You should also continue to pull data within seven days of install. This is because Branch hashes device identifiers in raw data after 7 days.
If you use webhooks, we recommend including the IDFV field in your webhook body, because IDFAs will not always be available. Optionally, you can also implement the deduplication logic discussed below.
For ad partner postbacks and data integrations, no changes are needed if configured to send only attributed events. If configured to send all events, you’ll want to work with the partner to determine the preferred path forward.
If you want to capture ATT opt-ins and opt-outs as separate analytics events, update your Branch iOS SDK integration to v1.4 or above. If you don’t want to measure these dedicated analytics events and only need “second install” tracking, no SDK update is required at this time.
How to deduplicate first and second installs
The Branch dashboard and Query API will continue to provide accurate reporting by automatically de-duplicating these events, however, you may want to make updates to your systems if you use any of our raw data products (including webhooks, Data Integrations, the Custom Export API, or ad network postbacks configured to send all events instead of just attributed installs).
To do so, you should reference the IDFV in your API pull or webhook body which you can use to overwrite the unattributed Install with the corresponding Second Install.
Optionally, you can also use the IDFV to reassign any down-funnel events that occurred between the initial Install and Second Install.
Summary
We recognize there is a lot to process when it comes to iOS 14 and Apple’s new privacy policies. The Branch team is here to help — please reach out to your Branch contact or our support team with any questions!