iOS Advanced Features
Create Content Reference
- The Branch Universal Object encapsulates the thing you want to share.
- Uses Universal Object properties
let buo = BranchUniversalObject.init(canonicalIdentifier: "content/12345")
buo.title = "My Content Title"
buo.contentDescription = "My Content Description"
buo.imageUrl = "https://lorempixel.com/400/400"
buo.publiclyIndex = true
buo.locallyIndex = true
buo.contentMetadata.customMetadata["key1"] = "value1"
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"content/12345"];
buo.title = @"My Content Title";
buo.contentDescription = @"My Content Description";
buo.imageUrl = @"https://lorempixel.com/400/400";
buo.publiclyIndex = YES;
buo.locallyIndex = YES;
buo.contentMetadata.customMetadata[@"key1"] = @"value1";
Creating dynamic links without the share sheet
If you've built your own share sheet and you want to just create a Branch link for an individual share message or have another use case, you can create deep links directly with the following call:
[branchUniversalObject getShortUrlWithLinkProperties:linkProperties andCallback:^(NSString *url, NSError *error) {
if (!error) {
NSLog(@"got my Branch invite link to share: %@", url);
}
}];
branchUniversalObject.getShortUrl(with: linkProperties) { (url, error) in
if (error == nil) {
print("Got my Branch link to share: (url)")
} else {
print(String(format: "Branch error : %@", error! as CVarArg))
}
}
You can find examples of linkProperties
above. You would next use the returned link and help the user post it to (in this example) Facebook.
Specifying a shared email subjects
The majority of share options only include one string of text, except email, which has a subject and a body. The share text will fill in the body and you can specify the email subject in the link properties as shown below.
BranchLinkProperties *linkProperties = [[BranchLinkProperties alloc] init];
linkProperties.feature = @"share";
linkProperties.channel = @"facebook";
[linkProperties addControlParam:@"$email_subject" withValue:@"Your Awesome Deal"];
let linkProperties: BranchLinkProperties = BranchLinkProperties()
linkProperties.feature = "share"
linkProperties.channel = "facebook"
linkProperties.addControlParam("$email_subject", withValue: "Your Awesome Deal")
Create Link Reference
- Generates the analytical properties for the deep link
- Used for Create deep link and Share deep link
- Uses Configure link data and custom data
let lp: BranchLinkProperties = BranchLinkProperties()
lp.channel = "facebook"
lp.feature = "sharing"
lp.campaign = "content 123 launch"
lp.stage = "new user"
lp.tags = ["one", "two", "three"]
lp.addControlParam("$desktop_url", withValue: "http://example.com/desktop")
lp.addControlParam("$ios_url", withValue: "http://example.com/ios")
lp.addControlParam("$ipad_url", withValue: "http://example.com/ios")
lp.addControlParam("$android_url", withValue: "http://example.com/android")
lp.addControlParam("$match_duration", withValue: "2000")
lp.addControlParam("custom_data", withValue: "yes")
lp.addControlParam("look_at", withValue: "this")
lp.addControlParam("nav_to", withValue: "over here")
lp.addControlParam("random", withValue: UUID.init().uuidString)
BranchLinkProperties *lp = [[BranchLinkProperties alloc] init];
lp.feature = @"facebook";
lp.channel = @"sharing";
lp.campaign = @"content 123 launch";
lp.stage = @"new user";
lp.tags = @[@"one", @"two", @"three"];
[lp addControlParam:@"$desktop_url" withValue: @"http://example.com/desktop"];
[lp addControlParam:@"$ios_url" withValue: @"http://example.com/ios"];
[lp addControlParam:@"$ipad_url" withValue: @"http://example.com/ios"];
[lp addControlParam:@"$android_url" withValue: @"http://example.com/android"];
[lp addControlParam:@"$match_duration" withValue: @"2000"];
[lp addControlParam:@"custom_data" withValue: @"yes"];
[lp addControlParam:@"look_at" withValue: @"this"];
[lp addControlParam:@"nav_to" withValue: @"over here"];
[lp addControlParam:@"random" withValue: [[NSUUID UUID] UUIDString]];
Create Deep Link
- Generates a deep link within your app
- Needs a Create content reference
- Needs a Create link reference
- Validate with the Branch Dashboard
buo.getShortUrl(with: lp) { url, error in
print(url ?? "")
}
[buo getShortUrlWithLinkProperties:lp andCallback:^(NSString* url, NSError* error) {
if (!error) {
NSLog(@"@", url);
}
}];
Share Deep Link
- Will generate a Branch deep link and tag it with the channel the user selects
- Needs a Create content reference
- Needs a Create link reference
- Uses Deep Link Properties
let message = "Check out this link"
buo.showShareSheet(with: lp, andShareText: message, from: self) { (activityType, completed) in
print(activityType ?? "")
}
buo showShareSheetWithLinkProperties:lp andShareText:@"Super amazing thing I want to share!" fromViewController:self completion:^(NSString* activityType, BOOL completed) {
NSLog(@"finished presenting");
}];
Share with LPLinkMetadata
- Create a BranchShareLink instance with a BranchUniversalObject and LinkProperties.
- Set the BranchShareLink's LPLinkMetadata by using the addLPLinkMetadata() function.
- Present the BranchShareLink's Share Sheet.
//Initialize a BranchShareLink with a BranchUniversalObject and BranchLinkProperties.
//Then set the BranchShareLink's LPLinkMetadata with a preview title and icon.
let bsl = BranchShareLink(universalObject: buo, linkProperties: lp)
bsl.addLPLinkMetadata("LPLinkMetaData Link Title", icon: iconImg)
bsl.presentActivityViewController(from: self, anchor: nil)
//Initialize a BranchShareLink with a BranchUniversalObject and BranchLinkProperties.
//Then set the BranchShareLink's LPLinkMetadata with a preview title and icon.
BranchShareLink *bsl = [[BranchShareLink alloc] initWithUniversalObject:buo linkProperties:lp];
[bsl addLPLinkMetadata:@"LPLinkMetadata Link Title" icon:iconImg];
[bsl presentActivityViewControllerFromViewController:self anchor:nil];
Read Deep Link
- Retrieve Branch data from a deep link
- Best practice to receive data from the
listener
(to prevent a race condition) - Returns deep link properties
// listener (within AppDelegate didFinishLaunchingWithOptions)
Branch.getInstance().initSession(launchOptions: launchOptions) { params, error in
print(params as? [String: AnyObject] ?? {})
}
// latest
let sessionParams = Branch.getInstance().getLatestReferringParams()
// first
let installParams = Branch.getInstance().getFirstReferringParams()
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions
andRegisterDeepLinkHandler:^(NSDictionary * _Nullable params,
NSError * _Nullable error) {
if (!error) {
//Referring params
NSLog(@"Referring link params %@",params);
}
}];
// latest
NSDictionary *sessionParams = [[Branch getInstance] getLatestReferringParams];
// first
NSDictionary *installParams = [[Branch getInstance] getFirstReferringParams];
NativeLink™ Deferred Deep Linking
- Use iOS pasteboard to enable deferred deep linking via Branch NativeLink™
Prerequisite
Minimum SDK Version: v1.39.4
To use this feature you must:
or
- Manually configure your Branch Link to use
$ios_nativelink
Options for Implementation
- To enable this feature, call the
checkPasteboardOnInstall()
method in the AppDelegate file prior to Branch initialization.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
Branch.getInstance().checkPasteboardOnInstall()
// listener for Branch Deep Link data
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// do stuff with deep link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
}
return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// enable pasteboard check
[[Branch getInstance] checkPasteboardOnInstall];
// listener for Branch Deep Link data
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// do stuff with deep link data (nav to page, display content, etc)
NSLog(@"%@", params);
}];
return YES;
}
- If you only want to enable this feature on iOS 15+, include an iOS version check before calling
checkPasteboardOnInstall()
.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// NativeLink
if #available(iOS 16.0, *) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if #available(iOS 15.0, *) {
branch.checkPasteboardOnInstall()
}
// listener for Branch Deep Link data
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// do stuff with deep link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
}
return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// NativeLink
if (@available(iOS 16.0, *)) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if (@available(iOS 15.0, *)) {
[[Branch getInstance] checkPasteboardOnInstall];
}
// listener for Branch Deep Link data
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// do stuff with deep link data (nav to page, display content, etc)
NSLog(@"%@", params);
}];
return YES;
}
- You can also check whether the pasteboard toast will show or not by using the
willShowPasteboardToast()
method.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// NativeLink
if #available(iOS 16.0, *) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if #available(iOS 15.0, *) {
branch.checkPasteboardOnInstall()
}
// check if pasteboard toast will show
if Branch.getInstance().willShowPasteboardToast(){
// devlopers can notify the user of what just occurred here if they choose
}
// listener for Branch Deep Link data
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// do stuff with deep link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
}
return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// NativeLink
if (@available(iOS 16.0, *)) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if (@available(iOS 15.0, *)) {
[[Branch getInstance] checkPasteboardOnInstall];
}
// check if pasteboard toast will show
if ([[Branch getInstance] willShowPasteboardToast]) {
// developers can notify the user of what just occurrred here if they choose
}
// listener for Branch Deep Link data
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// do stuff with deep link data (nav to page, display content, etc)
NSLog(@"%@", params);
}];
return YES;
}
iOS 16 UIPasteControl Support
With iOS 16, Apple introduced an automatic modal prompt to request permissions from the user whenever the pasteboard is accessed for an item. UIPasteControl is an alternative for you to create your own prompt requesting access to the pasteboard.
This approach does not interfere with the Branch initialization and Branch will treat the paste action as if it was an in-app deep link.
Backwards Compatibility
Do not call both
checkPasteboardOnInstall
andpassPasteItemProviders
or useBranchPasteControl
without properly version checking, ascheckPasteboardOnInstall
will be called on iOS 16+ as well.
- If you are using UIPasteControl, its target (which also conforms to protocol UIPasteConfigurationSupporting) will receive the pasted information when the button is tapped. Pass the list of objects to Branch SDK using passPasteItemProviders API within paste(itemProviders:)
override func paste(itemProviders: [NSItemProvider]) {
if #available(iOS 16.0, *) {
Branch.getInstance().passPaste(itemProviders)
} else {
// Fallback on earlier versions
}
if (@available(iOS 16.0, *)) {
[[Branch getInstance] passPasteItemProviders:itemProviders]
}
- Alternatively, you can use the wrapper class
BranchPasteControl
to automatically conform to the UIPasteConfigurationSupporting protocol
// Setup UIPasteControl Configuration
let pcConfig = UIPasteControl.Configuration()
pcConfig.baseBackgroundColor = UIColor.blue
pcConfig.displayMode = UIPasteControl.DisplayMode.iconOnly
// Create Frame and button
let frameDimension = CGRect(x: 0, y: 0, width: 40, height: 40)
let bc = BranchPasteControl(frame: frameDimension, configuration: pcConfig)
// Add BranchPasteControl button to superview
view.addSubview(bc)
// Setup UIPasteControlConfiguration
UIPasteControlConfiguration *pcConfig = [[UIPasteControlConfiguration alloc] init];
pcConfig.baseBackgroundColor = UIColor.blueColor;
pcConfig.displayMode = UIPasteControlDisplayModeIconOnly;
// Create Frame and button
CGRect frameDimension = CGRectMake(0, 0, 120.0, 30.0);
BranchPasteControl *bc = [[BranchPasteControl alloc] initWithFrame:frameDimension AndConfiguration:pcConfig];
// Add BranchPasteControl button to superview
[view addSubview:bc];
BranchPasteControl & UIPasteControl Tips
BranchPasteControl.frame & UIPasteControl.frame
Based on our testing there are undeclared restrictions as to the width and height for UIPasteControl corresponding to the declared DisplayMode. We found the minimum height for all display modes is 40, while the minimum width are as followed:
- .iconOnly: 40
- .labelOnly: 60
- .iconAndLabel: 80
The BranchPasteControl only accepts UTType.url as an acceptable type identifier for its UIPasteConfiguration, if the main purpose is to support NativeLink, we strongly suggest to do the same.
If utilizing your own UIPasteControl, we recommend to clear the pasteboard after accessing it.
When there is not an acceptable type copied to the Pasteboard, the BranchPasteControl and UIPasteControl UI will be greyed out.
Create QR Code
- Create a BranchQRCode object and set the properties
- Create a BranchUniversalObject and BranchLinkProperties
- Use getQRCodeAsImage() or getQRCodeAsData() to create a QR code
- Use showShareSheetWithQRCodeFromViewController() to create a QR code and share it via the Share Sheet.
let qrCode = BranchQRCode()
qrCode.codeColor = UIColor.white
qrCode.backgroundColor = UIColor.blue
qrCode.centerLogo = "https://cdn.branch.io/branch-assets/1598575682753-og_image.png"
qrCode.width = 1024
qrCode.margin = 1
qrCode.imageFormat = .JPEG
let buo = BranchUniversalObject()
let lp = BranchLinkProperties()
qrCode.getAsImage(buo, linkProperties: lp) { qrCodeImage, error in
//Do something with your QR code here...
}
//Or display the QR code directly in a share sheet
qrCode.showShareSheetWithQRCode(from: self, anchor: nil, universalObject: buo, linkProperties: lp) { error in
//Showing a share sheet with the QR code
}
BranchQRCode *qrCode = [BranchQRCode new];
qrCode.codeColor = [[UIColor new] initWithRed:0.1 green:0.8392 blue:0.8667 alpha:1.0];
qrCode.backgroundColor = [UIColor whiteColor];
qrCode.width = @700;
qrCode.margin = @1;
qrCode.centerLogo = @"https://cdn.branch.io/branch-assets/1598575682753-og_image.png";
qrCode.imageFormat = BranchQRCodeImageFormatPNG;
BranchUniversalObject *buo = [BranchUniversalObject new];
BranchLinkProperties *lp = [BranchLinkProperties new];
[qrCode getQRCodeAsImage:buo linkProperties:lp completion:^(UIImage * _Nonnull qrCode, NSError * _Nonnull error) {
//Do something with the QR code here...
}];
//Or display the QR code directly in a share sheet
[qrCode showShareSheetWithQRCodeFromViewController:self anchor:nil universalObject:buo linkProperties:lp completion:^(NSError * _Nullable error) {
//Showing a share sheet with the QR code
}];
Navigate to Content
- Handled within
Branch.initSession()
// within AppDelegate application.didFinishLaunchingWithOptions
Branch.getInstance().initSession(launchOptions: launchOptions) { params , error in
// Option 1: read deep link data
guard let data = params as? [String: AnyObject] else { return }
// Option 2: save deep link data to global model
SomeCustomClass.sharedInstance.branchData = data
// Option 3: display data
let alert = UIAlertController(title: "Deep link data", message: "\(data)", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
// Option 4: navigate to view controller
guard let options = data["nav_to"] as? String else { return }
switch options {
case "landing_page": self.window?.rootViewController?.present( SecondViewController(), animated: true, completion: nil)
case "tutorial": self.window?.rootViewController?.present( SecondViewController(), animated: true, completion: nil)
case "content": self.window?.rootViewController?.present( SecondViewController(), animated: true, completion: nil)
default: break
}
}
// within AppDelegate application.didFinishLaunchingWithOptions
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// Option 1: read deep link data
NSLog(@"%@", params);
// Option 2: save deep link data to global model
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:params.description forKey:@"BranchData"];
[defaults synchronize];
// Option 3: display data
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Title" message:params.description preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *button = [UIAlertAction actionWithTitle:@"Deep Link Data" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:button];
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
// Option 4: navigate to view controller
if ([params objectForKey:@"navHere"]) {
ViewController *anotherViewController = [[ViewController alloc] initWithNibName:@"anotherViewController" bundle:nil];
[self.window.rootViewController presentViewController:anotherViewController animated:YES completion:nil];
}
}];
Display
- List content on iOS Spotlight
- Needs a Create content reference
buo.locallyIndex = true
buo.locallyIndex = YES;
Track ATT Opt-In and Opt-Out
- Track when the responds to sharing their device data through Apple's AppTrackingTransparency framework
- Implement from inside
requestTrackingAuthorization(completionHandler:)
if #available(iOS 14.0, *) {
if ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
ATTrackingManager.requestTrackingAuthorization { (status) in
Branch.getInstance().handleATTAuthorizationStatus(status.rawValue)
}
}
}
if (@available(iOS 14.0, *)) {
if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusNotDetermined) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
[[Branch getInstance] handleATTAuthorizationStatus:status];
}];
}
}
Second install
- After we see user opt-in via ATT, we are tracking an additional analytics event we call a “second install” for ad-driven installs, which will be deduped from "first install" on our Dashboard.
- All conversion events will be attributed to that "second install".
- More information
Track content
- Track how many times a piece of content is viewed
- Needs a Create content reference
- Validate with the Branch Dashboard
BranchEvent.standardEvent(.viewItem, withContentItem: buo).logEvent()
[[BranchEvent standardEvent:BranchStandardEventViewItem withContentItem:buo] logEvent];
Track Events
- All events related to a customer purchasing are bucketed into a "Commerce" class of data items
- All events related to users interacting with your in-app content are bucketed to a "Content" class of data items.
- All events related to users progressing in your app are bucketed to a "Lifecycle" class of data items.
- To track custom events - not found in the table below - please see Track Custom Events
- Validate with the Branch Dashboard
Use the table below to quickly find the event you want to track.
Event Name | Event Category | iOS |
---|---|---|
Add To Cart | Commerce Event | BranchStandardEventAddToCart |
Add To Wishlist | Commerce Event | BranchStandardEventAddToWishlist |
View Cart | Commerce Event | BranchStandardEventViewCart |
Initiate Purchase | Commerce Event | BranchStandardEventInitiatePurchase |
Add Payment Info | Commerce Event | BranchStandardEventAddPaymentInfo |
Purchase | Commerce Event | BranchStandardEventPurchase |
Spend Credits | Commerce Event | BranchStandardEventSpendCredits |
Search | Content Event | BranchStandardEventSearch |
View Item | Content Event | BranchStandardEventViewItem |
View Items | Content Event | BranchStandardEventViewItems |
Rate | Content Event | BranchStandardEventRate |
Share | Content Event | BranchStandardEventShare |
Complete Registration | Lifecycle Event | BranchStandardEventCompleteRegistration |
Complete Tutorial | Lifecycle Event | BranchStandardEventCompleteTutorial |
Achieve Level | Lifecycle Event | BranchStandardEventAchieveLevel |
Unlock Achievement | Lifecycle Event | BranchStandardEventUnlockAchievement |
Handle Branch Links when using Branch & Firebase SDK
There is a known issue with Firebase where it will call the following Instance Methods:
To account for this, you must check the link first to determine if it should be handled by the Branch SDK:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
//check for link_click_id
if url.absoluteString.contains("link_click_id") == true{
return Branch.getInstance().application(app, open: url, options: options)
}
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
//check for app.link or appropriate Branch custom domain
if userActivity.webpageURL?.absoluteString.contains("app.link"){
return Branch.getInstance().continue(userActivity)
}
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
if ([url.absoluteString containsString:@"link_click_id"]) {
return [[Branch getInstance] application:app openURL:url options:options];
}
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
if ([userActivity.webpageURL.absoluteString containsString:@"app.link"]) {
return [[Branch getInstance] continueUserActivity:userActivity];
}
}
Handle Push Notifications
- Allows you to track Branch deep links in your push notifications
- Include the Branch push notification handler in Initialize Branch
- Add a Branch deep link in your push notification
payload
- Replace
https://example.app.link/u3fzDwyyjF
with your deep link
- Replace
{
"aps": {
"alert": "Push notification with a Branch deep link",
"badge": "1"
},
"branch": "https://example.app.link/u3fzDwyyjF"
}
- Read deep link data from
initSession
Read Deep Link
Handle Links in Your Own App
- Allows you to deep link into your own from your app itself
Branch.getInstance().handleDeepLink(withNewSession: URL(string: "https://example.app.link/u3fzDwyyjF"))
[[Branch getInstance] handleDeepLinkWithNewSession:[NSURL URLWithString:@"https://example.app.link/u3fzDwyyjF"]];
Handling a new deep link in your app
Handling a new deep link in your app will clear the current session data and a new referred "open" will be attributed.
Delay Branch Initialization
Delay the Branch initialization on Installs in order to request tracking permission from the user.
- Create a boolean flag to represent an Install session and set it to true (e.g. firstOpen)
- Before the Branch init in didFinishLaunchingWithOptions
a. if false continue with Branch SDK init
b. if true:
i. Persist launchOptions throughout onboarding flow or store locally when firstOpen is true
ii. Continue with onboarding flow - After determining User's tracking preference
a. Set tracking in Branch SDK per User's preference
b. Initilialize the Branch SDK utilizing the persisted launchOptions - Set Install boolean (firstOpen) to false
Enable 100% Matching
To enable 100% Matching on iOS through Installs, please utilize our NativeLink™ feature.
Enable / Disable User Tracking
If you need to comply with a user's request to not be tracked for GDPR purposes, or otherwise determine that a user should not be tracked, utilize this field to prevent Branch from sending network requests. This setting can also be enabled across all users for a particular link, or across your Branch links.
Branch.setTrackingDisabled(true)
[Branch setTrackingDisabled:YES];
You can choose to call this throughout the lifecycle of the app. Once called, network requests will not be sent from the SDKs. Link generation will continue to work, but will not contain identifying information about the user. In addition, deep linking will continue to work, but will not track analytics for the user.
Share to Email Options
- Change the way your deep links behave when shared to email
- Needs a Share deep link
lp.addControlParam("$email_subject", withValue: "Your Awesome Deal")
lp.addControlParam("$email_html_header", withValue: "<style>your awesome CSS</style>\nOr Dear Friend,")
lp.addControlParam("$email_html_footer", withValue: "Thanks!")
lp.addControlParam("$email_html_link_text", withValue: "Tap here")
[lp addControlParam:@"$email_subject" withValue:@"This one weird trick."];
[lp addControlParam:@"$email_html_header" withValue:@"<style>your awesome CSS</style>\nOr Dear Friend,"];
[lp addControlParam:@"$email_html_footer" withValue:@"Thanks!"];
[lp addControlParam:@"$email_html_link_text" withValue:@"Tap here"];
Share Message Dynamically
- Change the message you share based on the source the users chooses
- Needs a Share deep link
// import delegate
class ViewController: UITableViewController, BranchShareLinkDelegate
func branchShareLinkWillShare(_ shareLink: BranchShareLink) {
// choose shareSheet.activityType
shareLink.shareText = "\(shareLink.linkProperties.channel)"
}
// import delegate
@interface ViewController () <BranchShareLinkDelegate>
- (void) branchShareLinkWillShare:(BranchShareLink*)shareLink {
// choose shareSheet.activityType
shareLink.shareText = [NSString stringWithFormat:@"@%", shareLink.linkProperties.channel];
}
Return YES to continueUserActivity
When users enter your app via a Universal Link, we check to see to see if the link URL contains app.link
. If so, Branch.getInstance().continue(userActivity)
will return YES
. If not, Branch.getInstance().continue(userActivity)
will return NO
. This allows us to explicitly confirm the incoming link is from Branch without making a server call.
For most implementations this will never be an issue, since your deep links will be routed correctly either way. However, if you use a custom link domain and you rely on Branch.getInstance().continue(userActivity)
to return YES
for every incoming Branch-generated Universal Link, you can inform the Branch SDK by following these steps:
- In your Info.plist file, create a new key called
branch_universal_link_domains
. - Add your custom domain(s) as a string.
- Save the file.
Multiple custom domains
If you have an unusual situation with multiple custom link domains, you may also configure
branch_universal_link_domains
as an array of strings.
Handle links for web-only content
Universal Email Only
If you have links to content that exists only on the web and not in the app (for example, a temporary marketing webpage that isn't in the app), then this code snippet will ensure all links that have not had the deep linking script applied will open in a browser.
You should add this code snippet inside the deep link handler code block.
Note
This uses query parameter
$web_only=true
. This should match the query parameter on the web URL you enter in the email.
branch.initSession(launchOptions: launchOptions, andRegisterDeepLinkHandler: { (params, error) in
if (params?["$3p"] != nil && params?["$web_only"] != nil) {
if let urlString = params?["$original_url"] as? String {
if let url = URL(string: urlString) {
application.openURL(url)
}
}
} else {
self.handleBranchDeeplink(params)
}
})
[branch initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {
// params are the deep linked params associated with the link that the user clicked before showing up.
if (params[@"$3p"] && params[@"$web_only"]) {
NSURL *url = [NSURL URLWithString:params[@"$original_url"]];
if (url) {
[application openURL:url]; // check to make sure your existing deep linking logic, if any, is not executed, perhaps by returning early
}
} else {
// it is a deep link
GDLog(@"branch deep link: %@", [params description]);
[self handleBranchDeeplink:params];
}
}];
Universal Links with Web-Only Content
Web-only Branch links that redirect to a site that hosts its own AASA file where Universal Links (UL) is enabled will cause unexpected behavior. Since Branch does not have a way to bypass UL (via JavaScript, delays, etc.), you must add a query param exclusion in the AASA file to persist web-only behavior when redirecting to a website. This only applies if you are trying to redirect via $web_only=true
to their own website.
Add the following filter to the AASA File:
{
"/": "*",
"?": { "$web_only": "true" },
"exclude": true,
"comment": "Matches any URL which has a query item with name '$web_only' and a value of exactly true"
}
Now if $web_only=true
is appended to the final fallback URL / redirect, iOS will not attempt to launch the App even if it is installed. ex. https://myhomepage.com/?$web_only=true
This link with the query parameter can now be used as the fallback of a web-only Branch link and persist the behavior all the way to myhomepage.com.
Set Initialization Metadata
Data Integration Only
If you are using a 3rd Party Data Integration Partner that requires setting certain identifiers before initializing the Branch SDK, you should add this code snippet:
//Inside *didFinishLaunchingWithOptions*
Branch.getInstance().setRequestMetadataKey("KEY", "VALUE")
//Inside *didFinishLaunchingWithOptions*
[[Branch getInstance] setRequestMetadataKey:@"{ANALYTICS_ID}" value: @"{VALUE}"];
Replace {ANALYTICS_ID}
with your Data Integration Partner's key.
App Clips
App Clip Analytics
We will automatically attribute App Clip touches (like a QR Code scan) and sessions.
Touch:
- Event Name: Click
- last_attributed_touch_data_tilde_customer_placement: APP_CLIP
- last_attributed_touch_data_tilde_creative_name: Set as
$app_clip_id
value if it is present in the App Clip link.Session:
- Event Name: Install/Open
- user_data_environment: APP_CLIP
- last_attributed_touch_data_tilde_creative_name: Set as
$app_clip_id
value if it is present.
An App Clip is a lightweight version of your app that offers users some of its functionality when and where they need it.
Follow Apple's developer documentation on creating an App Clip with Xcode
Important to note
- The Associated Domains entitlement has a new
appclips
type, which is required if you’re implementing app clips.
- The AASA file must be updated to support app clips; via a Branch database update.
- Please Submit a Ticket to make this request. Make sure to include your App Clip bundle ID and team ID in your request.
The Branch iOS SDK must be integrated into an App Clip in the same way as the Full App; with the following caveats:
- You do not need the
applinks
setting in the App Clip's Associated Domains entitlement. - Cocoapods does not install the Branch SDK into your App Clip.
How to Persist App Clip Install Data to Subsequent Full App Install
- Add an App Groups entitlement.
- Choose a group will be used to share data between the App Clip and subsequent Full App install.
- In both your Full App and App Clip, inform the Branch SDK of the App Group name prior to calling
initSession
. See Apple's developer doc for more information.
[[Branch getInstance] setAppClipAppGroup:@"group.io.branch"];
Branch.getInstance().setAppClipAppGroup("group.io.branch")
Branch Links as App Clip Invocation URLs
You can configure Branch links to be associated with App Clips. When creating a link, you specify which App Clip the Branch link should open. You do this via a Branch link parameter called $app_clip_id
.
For example, let's say you have two App Clips, one for Stores and one for Products.
On the iTunesConnect Dashboard, you'd register the following two as advanced App Clip Experiences:
- your.app.link/ac/s/* -- for Store links
- your.app.link/ac/p/* -- for Product links
Then when creating a Branch link, you set $app_clip_id
: s
, as seen below:

Then Branch will automatically create a link with the App Clip ID as part of the path: https://your.app.link/ac/s/QfJ2H7c7jcb
.
Additionally, you can specify an alias for these links. If you set $app_clip_url = s
and alias to 12345
, you'll get the following link: https://your.app.link/ac/s/12345
. This would be a great way to create a link to Store with ID 12345!
Note
https://your.app.link/ac/s/12345
returns the same payload ashttps://your.app.link/12345
. The path elements are only to ease registering App Clip experiences.
App Clip Code invocation URLs have a short character length limit
Unlike most App Clips, App Clip Code has a short URL limit. The length limit varies, but is about 35 characters. It is possible your Branch Link will be too long to be used in this situation. Use the shortest placement identifier possible to increase the odds your generated link will be short enough. We recommend specifying a short $app_clip_id and a short alias.
https://developer.apple.com/documentation/app_clips/creating_app_clip_codes
Invoking App Clips on iOS Channels
Once you have registered your Branch App Clip with Apple, Apple allows you to invoke App Clips on a few channels. Here's an example: https://branchster.app.link/6ZfIMUrDzbb#appclip
iMessage

Branch Links will automatically register and display your App Clip CTA on iMessage by default if they are registered as App Clip Invocation URLs.
Safari Banner

You can also display an App Clip banner on your website yourself. In order to do this, you need to add the standard Apple meta tag to your website:
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-clip-bundle-id=appClipBundleID>
If you want to display the banner on a Branch Deepview, add it to the HTML code in the Branch dashboard Deepview Manager.
For more information, please refer to Apple's documentation.
Include Apple's ATTrackingManager
Requires the inclusion of
AdSupport
FrameworkIn order for the
ATTrackingManager
to function, you must also ensure you've added theAdSupport
framework in your iOS SDK implementation.
By default, the Branch SDK does not include the ATTrackingManager
which is required by Apple if you want to collect the IDFA for attribution purposes.
Learn more about Apple's App Transparency Tracking Manager.
If you wish to use the IDFA, you will need to display the ATTrackingManager prompt at an appropriate time in your app flow. This sample code demonstrates displaying the prompt and logging the IDFA.
func requestIDFAPermission() {
if #available(iOS 14, *) {
DispatchQueue.main.async {
ATTrackingManager.requestTrackingAuthorization { (status) in
if (status == .authorized) {
let idfa = ASIdentifierManager.shared().advertisingIdentifier
print("IDFA: " + idfa.uuidString)
} else {
print("Failed to get IDFA")
}
}
}
}
}
- (void)requestIDFAPermission {
if (@available(iOS 14.0, *)) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_main_queue(), ^{
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
NSUUID *idfa = [[ASIdentifierManager sharedManager] advertisingIdentifier];
NSLog(@"IDFA: %@", idfa);
} else {
NSLog(@"Failed to get IDFA permission");
}
dispatch_semaphore_signal(semaphore);
}];
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
}
Starting from Branch iOS SDK 1.39.1, the SDK will see the authorization status if it is granted by the end-user. There is no additional work on your end to inform the Branch SDK.
On older versions of the SDK, the server infers the authorization status by the presence of the IDFA. Again there is no additional work on your end to inform the Branch SDK.
Set Hashed Information for Facebook Advanced Matching
You can pass additional hashed information to the SDK before initSession()
for Facebook Advanced Matching.
...
//set hash parameters for Facebook Advanced Matching
Branch.getInstance().addFacebookPartnerParameter(withName: "em", value: "11234e56af071e9c79927651156bd7a10bca8ac34672aba121056e2698ee7088")
...
//initialize Branch session
Branch.getInstance().initSession(...)
Updated 8 days ago