In-app integration guidance for external content links

This document describes how to integrate the Play Billing Library APIs to offer external content links in eligible apps. This includes the ability to link users in the US outside your Play app to provide users with offers to in-app digital content and app downloads. To learn more about this program, see program requirements.

Play Billing Library setup

Add the Play Billing Library dependency to your Android app. To use the external links APIs you need to use version 8.2 or higher. If you need to migrate from an earlier version, follow the instructions in the migration guide before adding the external content links.

Initialize the billing client

To initialize the billing client follow the same steps as described in Initialize a BillingClient with the following modifications:

  • Don't enable the PurchasesUpdatedListener - this listener is not needed for external content links.
  • Call enableBillingProgram() with BillingProgram.EXTERNAL_CONTENT_LINK to indicate that your app uses the external content links.

The following example shows initializing a BillingClient with these modifications:

Kotlin

val billingClient = BillingClient.newBuilder(context)
  .enableBillingProgram(BillingProgram.EXTERNAL_CONTENT_LINK)
  .build()

Java

private BillingClient billingClient = BillingClient.newBuilder(context)
    .enableBillingProgram(BillingProgram.EXTERNAL_CONTENT_LINK)
    .build();

Connect to Google Play

After you initialize the BillingClient, connect to Google Play as described in Connect to Google Play.

Check user eligibility

After you connect to Google Play, you must check if the user is eligible for the external content links program by calling the isBillingProgramAvailableAsync() method. This method returns BillingResponseCode.OK if the user is eligible for external content links program. The following sample shows how to check the user eligibility for external content links:

Kotlin

billingClient.isBillingProgramAvailableAsync(
  BillingProgram.EXTERNAL_CONTENT_LINK,
  object : BillingProgramAvailabilityListener {
    override fun onBillingProgramAvailabilityResponse(
      billingProgram: Int, billingResult: BillingResult) {
        if (billingResult.responseCode !=  BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors,
            // handling external content links unavailable, etc.
            return
        }

        // External content links are available. Prepare an external
        // transaction token.
      }
    })

Java

billingClient.isBillingProgramAvailableAsync(
  BillingProgram.EXTERNAL_CONTENT_LINK,
  new BillingProgramAvailabilityListener() {
    @Override
    public void onBillingProgramAvailabilityResponse(
      int billingProgram, BillingResult billingResult) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors,
            // handling external content links unavailable, etc.
            return;
        }

        // External content links are available. Prepare an external
        // transaction token.
      }

    });

See the response handling section for details on how your app should respond to other response codes. If you're using Kotlin extensions, you can use Kotlin coroutines so you don't have to define a separate listener.

Prepare an external transaction token

Next, you must generate an external transaction token from the Play Billing Library. A new external transaction token must be generated each time the user visits an external website through the external links API. This can be done by calling the createBillingProgramReportingDetailsAsync API. The token should be generated immediately before the user is linked out.

Note: The external transaction token should never be cached and you should generate a new token each time the user is linked out.

Kotlin

val params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.EXTERNAL_CONTENT_LINK)
        .build();

billingClient.createBillingProgramReportingDetailsAsync(
  params,
  object : BillingProgramReportingDetailsListener {
    override fun onCreateBillingProgramReportingDetailsResponse(
      billingResult: BillingResult,
      billingProgramReportingDetails: BillingProgramReportingDetails?) {
        if (billingResult.responseCode !=  BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return
        }
        val externalTransactionToken =
            billingProgramReportingDetails?.externalTransactionToken
        // Persist the external transaction token locally. Pass it to the
        // external website when launchExternalLink is called.
    }
  })

Java

BillingProgramReportingDetailsParams params =
    BillingProgramReportingDetailsParams.newBuilder()
        .setBillingProgram(BillingProgram.EXTERNAL_CONTENT_LINK)
        .build();

billingClient.createBillingProgramReportingDetailsAsync(
  params,
  new BillingProgramReportingDetailsListener() {
    @Override
    public void onCreateBillingProgramReportingDetailsResponse(
      BillingResult billingResult,
      @Nullable BillingProgramReportingDetails
        billingProgramReportingDetails) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return;
        }

        String transactionToken =
          billingProgramReportingDetails.getExternalTransactionToken();

        // Persist the external transaction token locally. Pass it to the
        // external website when launchExternalLink is called.
      }
  });

If you're using Kotlin extensions, you can use Kotlin coroutines so you don't have to define a separate listener.

Launch the external link

After the external transaction token is ready, the user may be linked outside of the app to a digital content offer or app download by calling launchExternalLink method. Google Play might render additional information dialogs to the user depending on their user settings when you call this API.

When calling the launchExternalLink method, details of the external link must be provided through LaunchExternalLinkParams. This class contains the following parameters:

  • Link URI - The link to the external website where the digital content or app download is offered. For app downloads, this link must be registered and approved in the Play Developer Console.
  • Link Type - The type of content being offered to the user.
  • Launch Mode - Specifies how the link is launched. For app downloads, you must set this to LAUNCH_IN_EXTERNAL_BROWSER_OR_APP.
  • Billing Program - Set this to BillingProgram.EXTERNAL_CONTENT_LINK.

Kotlin

val params =
  LaunchExternalLinkParams.newBuilder()
    .setBillingProgram(BillingProgram.EXTERNAL_CONTENT_LINK)
    .setLinkUri(Uri.parse("https://www.myapprovedsite.com"))
    .setLinkType(LaunchExternalLinkParams.LinkType.LINK_TO_APP_DOWNLOAD)
    .setLaunchMode(
      LaunchExternalLinkParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
    .build()

val listener : LaunchExternalLinkResponseListener =
    object : LaunchExternalLinkResponseListener {
      override fun onLaunchExternalLinkResponse(
        billingResult: BillingResult) {
        if (billingResult.responseCode !=  BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return
        }

        // If Launch Mode was set to LAUNCH_IN_EXTERNAL_BROWSER_OR_APP, the
        // user was directed outside of the app by Play. This does not give
        // any information on the user's actions during the link out, such
        // as if a transaction was completed.

        // If Launch Mode was set to CALLER_WILL_LAUNCH_LINK, then your app
        // may proceed to direct the user to the external website.
    }
}

billingClient.launchExternalLink(activity, params, listener)

Java

LaunchExternalLinkParams params =
  LaunchExternalLinkParams.newBuilder()
    .setBillingProgram(BillingProgram.EXTERNAL_CONTENT_LINK)
    .setLinkUri(Uri.parse("https://www.myapprovedsite.com"))
    .setLinkType(LaunchExternalLinkParams.LinkType.LINK_TO_APP_DOWNLOAD)
    .setLaunchMode(
      LaunchExternalLinkParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
    .build()

LaunchExternalLinkResponseListener listener =
  new LaunchExternalLinkResponseListener() {
    @Override
    public void onLaunchExternalLinkResponse(BillingResult billingResult) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return;
        }

        // If Launch Mode was set to LAUNCH_IN_EXTERNAL_BROWSER_OR_APP, the
        // user was directed outside of the app by Play. This does not give
        // any information on the user's actions during the link out, such
        // as if a transaction was completed.

        // If Launch Mode was set to CALLER_WILL_LAUNCH_LINK, then your app
        // may proceed to direct the user to the external website.
    }
  }

billingClient.launchExternalLink(activity, params, listener);

Response handling

When an error occurs, the methods isBillingProgramAvailableAsync(), and createBillingProgramReportingDetailsAsync(), and onLaunchExternalLinkResponse() might provide a BillingResponseCode other than BillingResponseCode.OK. Consider handling these response codes as follows:

  • ERROR: This is an internal error. Don't proceed with the transaction or opening the external website. Retry by calling the API again or by calling launchExternalLink() the next time you attempt to direct the user outside the app.
  • FEATURE_NOT_SUPPORTED: The external content link APIs are not supported by the Play Store on the current device. Don't proceed with the transaction or opening the external website.
  • USER_CANCELED: Don't proceed with opening the external website. Call launchExternalLink() again the next time you attempt to direct the user outside of the app.
  • BILLING_UNAVAILABLE: The transaction is not eligible for external content links and therefore don't proceed under this program. This is either because the user is not in an eligible country for this program or your account has not been successfully enrolled in the program. If it's the latter, check your enrollment status in the Play Developer Console.
  • DEVELOPER_ERROR: There is an error with the request. Use the debug message to identify and correct the error before proceeding.
  • NETWORK_ERROR, SERVICE_DISCONNECTED, SERVICE_UNAVAILABLE: These are transient errors that should be handled with an appropriate retry policy. In the case of SERVICE_DISCONNECTED, re-establish a connection with Google Play before retrying.

Test external content links

License testers should be used to test your external offers integration. You won't be invoiced for transactions that have been initiated by license tester accounts. See Test in-app billing with application licensing for more information on configuring license testers.

Next steps

After you've finished in-app integration, you're ready to integrate your backend.