Using deeplinks to display Screens

This section provides details on how to display Screens using deeplinks

About Purchasely deeplinks

Purchasely SDK is able to manage deeplinks.

This allows to create no-code deeplink automations and open a Purchasely Screen automatically at the app start by using a simple deeplink.

To enable deeplink management, you first need to complete the App Scheme for your App.

In the Purchasely Console, navigate to App Settings > Store Configuration

Then fill in the App Scheme for each App store.

Universal links (eg: https://purchasely.io instead of ply in the above example) can also be used.

What are Purchasely deeplinks used for?

Purchasely supports the use of Deeplinks to trigger different actions to improve conversion, retention and upsell. You can send a Push or an email with that deeplink and Purchasely will open the requested presentation or page for you.

Here are the actions Purchasely supports:

  • Display a paywall
  • Display a placement
  • Update credit card (deeplink to App Store or Play Store credit card information) - subscription apps only

Deeplinks are also used to preview Screens on your device (directly inside your app) by scanning a QR code displayed in the upper right corner of the Screen Composer inside the Console.

Only a certain type of deeplinks, matching a specific pattern are recognized and handled by Purchasely.

Deeplinks which do not match the pattern are just ignored

Deeplink implementation

To manage deeplinks you need to do up to 3 things:

  1. Pass the deeplink to the Purchasely SDK when it is received by the application (not required on Android — see below)
  2. Optionally control when Purchasely is allowed to display content over your interface
  3. Set a default presentation handler to get the result of what was done by the user on the paywall / screen

1. Passing the deeplink to Purchasely SDK

📘

Android handles deeplinks automatically

Since v6, the Android SDK intercepts Purchasely deeplinks on its own (it reads the foreground activity's intent on create and resume). You don't need to call handleDeeplink yourself. The manual call below is only useful as a fallback for activities using singleTask / singleTop launch modes that receive the deeplink in onNewIntent without calling setIntent(intent).

To enable the Purchasely SDK to analyze the deeplink, the app provides it using the following code:

// ---------------------------------------------------
// If you are **NOT** using SceneDelegate
// ---------------------------------------------------

// AppDelegate.swift

import Purchasely

func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
	// You can chain calls to multiple handler using a OR
	return Purchasely.handleDeeplink(url) 
}

// ---------------------------------------------------
// If you are using SceneDelegate
// ---------------------------------------------------

// SceneDelegate.swift

import Purchasely

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

	// …

	if let url = connectionOptions.urlContexts.first?.url {
		_ = Purchasely.handleDeeplink(url)
	}
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
	if let url = URLContexts.first?.url {
		_ = Purchasely.handleDeeplink(url)
	}
}
class MyActivity : FragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Optional on Android: the SDK already intercepts deeplinks automatically.
        // Keep this only as a fallback (e.g. singleTask/singleTop without setIntent()).
        val data = intent.data
        if (data != null) {
            // Purchasely SDK returns true if it handles the deeplink
            val isHandledByPurchasely = Purchasely.handleDeeplink(data)
        }
    }

}
Purchasely.handleDeeplink('app://ply/presentations/')
          .then((value) => console.log('Deeplink handled by Purchasely ? ' + value));
Purchasely.handleDeeplink('app://ply/presentations/')
          .then((value) => print('Deeplink handled by Purchasely ? $value'));
// If you grab the deeplink inside your Cordova code you can call
Purchasely.handleDeeplink("app://ply/presentations/", (handled) => {
	console.log("Was deeplink handled by Purchasely? " + handled);
});
private PurchaselyRuntime.Purchasely _purchasely;

_purchasely.HandleDeeplink("app://ply/presentations/");
📘

Passing the deeplink at start

When your app is launched from a deeplink (cold start), you can hand it to the SDK directly at initialization instead of waiting for the SDK to be ready:

// iOS
Purchasely.apiKey("YOUR_API_KEY").handleDeeplink(url).start { error in }
// Android
Purchasely.Builder(context).handleDeeplink(intent.data).build().start { error -> }

2. Forbidding the display

By default, Purchasely deeplinks are displayed immediately when they are received.

If your app has a launch routine that must complete before a screen can be shown (splash screen, onboarding, login, displaying an ad…), you can temporarily prevent Purchasely from displaying deeplinks, then re-enable it once you are ready:

// Prevent the display (e.g. while your onboarding is on screen)
Purchasely.allowDeeplink(false)

// Re-enable it once your app is ready — any queued deeplink displays immediately
Purchasely.allowDeeplink(true)
// Prevent the display (e.g. while your onboarding is on screen)
Purchasely.allowDeeplink = false

// Re-enable it once your app is ready — any queued deeplink displays immediately
Purchasely.allowDeeplink = true
Purchasely.allowDeeplink(false);
// later
Purchasely.allowDeeplink(true);
Purchasely.allowDeeplink(false);
// later
Purchasely.allowDeeplink(true);
Purchasely.allowDeeplink(false);
// later
Purchasely.allowDeeplink(true);
_purchasely.SetAllowDeeplink(false);
// later
_purchasely.SetAllowDeeplink(true);
📘

You only need this if you want to defer deeplinks. If you do nothing, deeplinks display as soon as they are received.

3. Forbidding campaigns

Campaigns follow the same principle through their own flag, allowCampaigns, which is true by default (campaigns display immediately). To gate campaigns behind a launch flow, set it to false and flip it back to true when ready — any campaign queued meanwhile displays immediately:

Purchasely.allowCampaigns(false)
// later
Purchasely.allowCampaigns(true)
Purchasely.allowCampaigns = false
// later
Purchasely.allowCampaigns = true

allowDeeplink and allowCampaigns are independent: gating one does not affect the other.

Supported deeplinks to create automations

Purchasely SDK supports the deeplink format with app_scheme://ply where app_scheme is the application scheme you have declared to open deeplinks.
On Android only, the SDK also supports universal links like https://www.myapp.com/ply

Presentation / Screen

You can open a product presentation directly to the user with the default presentation or a specific one used for a specific purpose / promotion.

⚠️ This kind of push requires users opt-in (see App Store Review Guidelines - 4.5.4).

Open a screen directly
app_scheme://ply/presentations/PRESENTATION_ID

Open your default screen
app_scheme://ply/presentations

Open a placement
app_scheme://ply/placements/PLACEMENT_ID

Open your default placement
app_scheme://ply/placements

Subscriptions

This deeplink will open the subscriptions view inside the app.

app_scheme://ply/subscriptions

Update billing

This deeplink will open the App Store / Play Store setttings for the user to updates its credit card after a payment error.

app_scheme://ply/update_billing

Be notified of purchase from a deeplink paywall

Usually when a paywall / screen is instantiated by the app, a closure is called back to inform the app of what has happened with the paywall . However, when a deeplink is called, as you don't instantiate the paywall yourself, no closure will be called.

You can retrieve the result of the user action in a paywall opened with a deeplink by setting a DefaultPresentationResultHandler. This only works in full mode. In observer mode, when your action interceptor returns a success result for a purchase or restore, the SDK automatically synchronizes the transaction — you no longer need to call Purchasely.synchronize() yourself in that path.

Purchasely.setDefaultPresentationDismissHandler { outcome in
    switch outcome.purchaseResult {
        case .purchased:
            break
        case .restored:
            break
        case .cancelled:
            break
        case .none:
            break
        @unknown default:
				    break
    }
}
Purchasely.setDefaultPresentationDismissHandler { outcome ->
    /* You can set a callback to know when your user purchased a product */
    when(outcome.purchaseResult) {
        PLYPurchaseResult.PURCHASED -> Log.d("Purchasely", "Purchased ${outcome.plan}")
        PLYPurchaseResult.CANCELLED ->  Log.d("Purchasely", "Cancelled purchase of ${outcome.plan}")
        PLYPurchaseResult.RESTORED -> Log.d("Purchasely", "Restored ${outcome.plan}")
        null -> {}
    }
}
Purchasely.setDefaultPresentationDismissHandler((outcome) => {
  console.log('Presentation View Result : ' + outcome.purchaseResult);

  if (outcome.plan != null) {
    console.log('Plan Vendor ID : ' + outcome.plan.vendorId);
    console.log('Plan Name : ' + outcome.plan.name);
  }
});
PLYPresentationBuilder.defaultSource()
    .onDismissed((outcome) {
      print('Presentation View Result : ${outcome.purchaseResult}');

      if (outcome.plan != null) {
        print('Plan : ${outcome.plan}');
      }
    })
    .build()
    .display();
Purchasely.setDefaultPresentationDismissHandler((result) => {
	console.log("Presentation View Result: " + result.result);

	if (result.plan != null) {
		console.log("Plan Vendor ID: " + result.plan.vendorId);
		console.log("Plan Name:  " + result.plan.name);
	}
});
_purchasely.SetDefaultPresentationResultHandler((result, plan) =>
{
    Log($"Presentation Result: {result}.");
});
📘

Keep in mind

The callback PLYProductViewControllerResult(iOS) / ProductViewResultListener(Android) is optional, you can set to null if you do not need it. You can override it when you display a presentation directly.

Override the display of deeplinks

You can display the Purchasely deeplink for a Screen or Placement yourself if you want to control it entirely from your application. This only works on native iOS and Android frameworks at the moment

Learn more