Guides
GuidesLog In
Guides

Configure the App for the Flow

This guide describes how to configure the app for the Flow

Overview

After users successfully purchase a subscription on the web, they receive a link to download the app. This link directs them to the relevant app store, where they can install the app. Upon installation, the app should recognize the user as a premium subscriber. Apphud Flow supports two methods to enable premium access for these users:

  1. Deferred Deep Link Attribution This method enables the app to automatically grant premium access without requiring visible UI elements for the user. By leveraging deferred deep linking, the app retrieves the user's subscription status based on the MMP attribution data. This requires integration of MMP to track users and pass the relevant data from the flow.
  2. Restore by Email Mechanism Alternatively, developers can implement a "Restore" button in the app's interface, allowing users to manually restore their premium access. The user enters the same email address they used during the web purchase, and the app verifies their subscription status.

By supporting both methods, your app ensures a flexible and user-friendly way to restore premium access, accommodating different user scenarios effectively.

📘

Update to the latest SDKs

Apphud Flow requires latest SDKs: iOS v3.5.7 or higher, Android SDK v2.8.3 or higher, Flutter SDK v2.6.0 or higher.

Restore with Email

To restore premium access using the user’s email, follow these steps:

  • Capture the user's email address with your own interface.
  • Pass the email to the Apphud SDK using the following code:
Apphud.attributeFromWeb(data: ["email": userEmail]) { success, user in
   if (success && Apphud.hasPremiumAccess()) {
       print("Premium access successfully activated! Skip paywall here")
   } else {
     print("Not a web subscriber.")
   }
}
Apphud.attributeFromWeb(data = buildMap { put("email", "[email protected]") }) { result, _ ->
	if (result && Apphud.hasPremiumAccess()) {
		 Log.d("ApphudLogsDemo", "Premium access successfully activated! Skip paywall here")
	} else {
		Log.d("ApphudLogsDemo", "Not a web subscriber")
	}
}

Restore with Deferred Deep Link

Deferred deep linking enables the app to automatically match web visitors with app users, even if the app was not installed when the user visited the web page. This process ensures users who purchased subscriptions on the web automatically gain premium access in the app after installation.

When a user installs the app through a deferred deep link:

  • The app identifies the user as a web subscriber.
  • Premium access is granted seamlessly, developers at this point may skip the paywall and provide the user with premium content.

This approach simplifies the user experience and ensures smooth onboarding for web subscribers.

Supported Mobile Measurement Partners (MMPs)

Apphud Web SDK works with any mobile measurement partner (MMP) that supports deep link attribution. The SDK appends the apphud_user_id value to the provided deep link URL, making it compatible with any deep link provider.

Key Requirement: Ensure that the following method is called to attribute data correctly:

// attributionData is a deep link parameters payload
Apphud.attributeFromWeb(data: attributionData) { }

For your convenience, we have prepared integration guides for the following MMPs:

  • AppsFlyer
  • Branch
  • Adjust

Restore with AppsFlyer

To integrate AppsFlyer for deferred deep linking, start with their basic setup guides:

The main method for restoring premium access is:

Apphud.attributeFromWeb(data: attributionData) { success, user in
   if success && Apphud.hasPremiumAccess() {
        // Premium access restored successfully
    } else {
        // Not a web subscriber
    }
}
Apphud.attributeFromWeb(data = buildMap { put("email", "[email protected]") }) { result, _ ->
            if (result && Apphud.hasPremiumAccess()) {
                Log.d("ApphudLogsDemo", "Premium access successfully activated! Skip paywall here")
            } else {
                Log.d("ApphudLogsDemo", "Not a web subscriber")
            }
        }

This method accepts attribution payloads from Mobile Measurement Partners (MMPs) and passes them to Apphud. If the restoration is successful, the callback returns true.

See a full example below:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
	...
	AppsFlyerLib.shared().appsFlyerDevKey = "APPSFLYER_DEV_KEY"
	AppsFlyerLib.shared().appleAppID = "YOUR_APPLE_APP_ID"
	AppsFlyerLib.shared().delegate = self
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
		return AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
}
    
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
		AppsFlyerLib.shared().handleOpen(url, options: options)
		return true
}

var installAttributed: Bool = false
@MainActor
func tryWebAttribution(attributionData: [AnyHashable : Any]) {
  guard !installAttributed else { return }
  
  Apphud.attributeFromWeb(data: attributionData) { success, user in
   	if (success && Apphud.hasPremiumAccess()) {
      installAttributed = true
      print("Premium access successfully activated! Skip paywall here")
   	} else {
      installAttributed = false
   		print("Not a web-to-web subscriber")
   	}
	}
}

func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]!) {
	Apphud.addAttribution(data: conversionInfo, from: .appsFlyer, identifer: AppsFlyerLib.shared().getAppsFlyerUID()) { _ in }
	tryWebAttribution(attributionData: conversionInfo)
}

func onAppOpenAttribution(_ attributionData: [AnyHashable : Any]) {
  Apphud.addAttribution(data: attributionData, from: .appsFlyer, identifer: AppsFlyerLib.shared().getAppsFlyerUID()) { _ in }      
  tryWebAttribution(attributionData: attributionData)
}

func onConversionDataFail(_ error: Error) {
    Apphud.addAttribution(data: ["error" : error.localizedDescription], from: .appsFlyer, identifer: AppsFlyerLib.shared().getAppsFlyerUID()) { _ in }
}

// or you can handle using Unified Deep Linking (UDL)
extension AppDelegate: @preconcurrency DeepLinkDelegate {
    func didResolveDeepLink(_ result: DeepLinkResult) {
        guard let deepLinkObj: DeepLink = result.deepLink else {
            return
        }
        
        let value = deepLinkObj.deeplinkValue
        let subValue = deepLinkObj.clickEvent["deep_link_sub1"] as? String
        
        if let value, subValue == "apphud_user_id" {
            let attributionData = ["apphud_user_id": value]
            tryWebAttribution(attributionData: attributionData)
        }
    }
}

Restore with Branch

To integrate Branch for deferred deep linking, start with their basic setup guides:

The main method for restoring premium access is:

Apphud.attributeFromWeb(data: attributionData) { success, user in
    if success && Apphud.hasPremiumAccess() {
        // Premium access restored successfully
    } else {
        // Not a web subscriber
    }
}
Apphud.attributeFromWeb(data = buildMap { put("email", "[email protected]") }) { result, _ ->
            if (result && Apphud.hasPremiumAccess()) {
                Log.d("ApphudLogsDemo", "Premium access successfully activated! Skip paywall here")
            } else {
                Log.d("ApphudLogsDemo", "Not a web subscriber")
            }
        }

This method accepts attribution payloads from Mobile Measurement Partners (MMPs) and passes them to Apphud. If the restoration is successful, the callback returns true.

See a full example below:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
	...
	Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in
       if let data = data {
         Apphud.addAttribution(data: ["branch_data": data], from: .custom, callback: nil)
         self.tryWebAttribution(attributionData: data)
       }
	}
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
		return Branch.getInstance().continue(userActivity)
}
    
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
		return Branch.getInstance().application(app, open: url, options: options)
}

var installAttributed: Bool = false
@MainActor
func tryWebAttribution(attributionData: [AnyHashable : Any]) {
  guard !installAttributed else { return }
  
  // this is the key method
  Apphud.attributeFromWeb(data: attributionData) { success, user in
   	if (success && Apphud.hasPremiumAccess()) {
      installAttributed = true
      print("Premium access successfully activated! Skip paywall here")
   	} else {
      installAttributed = false
   		print("Not a web-to-web user.")
   	}
	}
}

Restore with Adjust

To integrate Adjust for deferred deep linking, start with their basic setup guides:

Apphud.attributeFromWeb(data: attributionData) { success, user in
    if success && Apphud.hasPremiumAccess() {
        // Premium access restored successfully
    } else {
        // Not a web subscriber
    }
}
Apphud.attributeFromWeb(data = buildMap { put("email", "[email protected]") }) { result, _ ->
            if (result && Apphud.hasPremiumAccess()) {
                Log.d("ApphudLogsDemo", "Premium access successfully activated! Skip paywall here")
            } else {
                Log.d("ApphudLogsDemo", "Not a web subscriber")
            }
        }

This method accepts attribution payloads from Mobile Measurement Partners (MMPs) and passes them to Apphud. If the restoration is successful, the callback returns true.

See a full example below:

func queryParams(from url: URL?) -> [String: String] {
    guard let url = url,
          let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
          let queryItems = components.queryItems else {
        return [:]
    }
  
    var queryParams: [String: String] = [:]
    for item in queryItems {
        queryParams[item.name] = item.value
    }
    return queryParams
}

func adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool {
    let params = queryParams(from: deeplink)
    self.tryWebAttribution(attributionData: params)
    
    return true
}

var installAttributed: Bool = false
@MainActor
func tryWebAttribution(attributionData: [AnyHashable : Any]) {
  guard !installAttributed else { return }
  
  // this is the key method
  Apphud.attributeFromWeb(data: attributionData) { success, user in
   	if (success && Apphud.hasPremiumAccess()) {
      installAttributed = true
      print("Premium access successfully activated! Skip paywall here")
   	} else {
      installAttributed = false
   		print("Not a web-to-web user.")
   	}
	}
}
fun configAdjust() {
  ....
  
  Config.setOnDeferredDeeplinkResponseListener { deeplink ->
	    // Extract query parameters as a Map 
  	  val queryParams = getQueryParams(deeplink)
    	tryWebAttribiton(data = queryParams)
      
    	return true
	}
}

fun getQueryParams(deeplink: URL?): Map<String, String> {
        return deeplink?.toURI()?.let { uri ->
            val query = uri.query ?: return emptyMap()
            query.split("&").associate { param ->
                val (key, value) = param.split("=", limit = 2)
                key to value
            }
        } ?: emptyMap()
}

fun tryWebAttribiton(data: Map <String, String>) {
        Apphud.attributeFromWeb(data = data) { result, user ->
            if (result && Apphud.hasPremiumAccess()) {
                Log.d("ApphudLogsDemo", "Premium access successfully activated! Skip paywall here")
            } else {
                Log.d("ApphudLogsDemo", "Not a web subscriber")
            }
        }
    }

Observer Mode

When your Apphud SDK is in observer mode, you can still utilize Flows and deferred deep linking to link web subscribers with app users. Follow these steps:

  • Implement Code for Observer Mode. Use the same implementation as you would in full mode. Flag the user as premium based on the callback from the Apphud.attributeFromWeb() method. See the examples below:
Apphud.attributeFromWeb(data: attributionData) { success, user in
    if success && Apphud.hasPremiumAccess() {
        // Premium access restored successfully, grant premium access if this flag is true.
	      self.isPremium = true
      
	      // Optionally update your own user with User ID from the callback
      	let premiumUserId = user?.userId    	
    } else {
        // Not a web subscriber
    }
}
Apphud.attributeFromWeb(data = buildMap { put("email", "[email protected]") }) { result, _ ->
            if (result && Apphud.hasPremiumAccess()) {
                Log.d("ApphudLogsDemo", "Premium access successfully activated! Skip paywall here")
            } else {
                Log.d("ApphudLogsDemo", "Not a web subscriber")
            }
        }
  • Validate Premium Status. Whenever you need to verify if a user still has premium access, additionally check the Apphud.hasPremiumAccess() method provided by the SDK:
func isPremium() -> Bool {
   	return Apphud.hasPremiumAccess() || YourOwnClass.shared.isPremium()
}