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:
- 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.
- 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()
}
Updated 4 days ago