lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Add subscription-specific features

Subscriptions are configured using the Android Play Console. Once you have a subscription configured, you can add Google Play Billing to your app to enable a purchase flow for the subscription. Subscriptions have many characteristics mentioned in the Google Play Billing Overview, such as billing period, grace period, free trial, and so on. You should be familiar with these concepts before reading this section.

Also, before reading the rest of this page, you should also have real-time developer notifications enabled. Real-time Developer Notifications allow you to react proactively to state changes, to increase your engagement, and to reduce user turnover. To enable these notifications, see Real-time Developer Notifications.

There are several subscriptions use cases you should try to accommodate in your overall Google Play Billing solution. These use cases are:

  • Handle subscription-related states changes using Real-time Developer Notifications.
  • Allow a user to upgrade or downgrade a subscription, such as upgrading from an individual plan to a family plan.
  • Allow a user to manually re-subscribe when a subscription has been cancelled, but before the subscription period ends.
  • Refund the cost of a subscription.
  • Revoke a subscription.
  • Cancel a subscription.
  • Defer billing for the user such that the subscription is free for a certain period of time.
  • Win back a customer.

You use combinations of the Google Play Billing Library, Google Play Developer API and Real-time Developer Notifications to address these use cases. The Google Play Billing Library and Google Play Developer API were introduced in Implement Google Play Billing.

Handle subscription-related states with Real-time Developer Notifications

Real-time developer notifications are server push notifications that give you the capability to monitor state changes, such as SUBSCRIPTION_PURCHASED or SUBSCRIPTION_RECOVERED, for subscriptions. Real-time Developer Notifications allow you to react proactively to state changes, to increase your engagement, and to reduce user turnover. To enable these notifications, see Real-time Developer Notifications.

If you have Real-time Developer Notifications enabled, your secure backend server receives notifications alerting you only of subscription state changes. You must call the developer API after receiving a Real-time Developer Notifications to get the complete status and update your own backend state. These notifications tell you only that the subscription state changed; it does not give you complete information of the subscription status.

When checking the developer API, you should always do the following:

  • If expiryTimeMillis is in the future, always grant entitlement.
  • If autoRenewing = false, try to get the user to resignup because the subscription will end at expiry time.
  • If paymentState = 0,send the user to the subscriptions center using the subscriptions center deep-link to fix his/her payment issue.

In the future we may add additional state changes that impact a user’s entitlement, such as pausing a subscription or reactivating a subscription after it’s expired. So that your integration is ready for these features, be sure to handle any undefined notifications by calling the developer API and taking action as described above.

User is in a grace period - SUBSCRIPTION_IN_GRACE_PERIOD

The grace period lasts for a certain amount of time based on your in-app product setting in the Google Play Console. Google Play tries to renew the subscription during the grace period. To alert the user about the payment issue, provide a message in your app that tells users how to fix their payment method. Otherwise, the user will lose access to subscription. For example, "To prevent disruptions to your account, navigate to the Google Play subscription settings to fix your payment on Google Play." This message would link to the Google Play subscription settings so that the user can fix their payment method.

To determine how much time the user has in the grace period, call the Google Play Developer API. Google Play dynamically extends the expiryTimeMillis value until the grace period has expired. During this time period, you should check whether the user's subscription been cancelled, renewed, or placed on hold. You should check the user's current subscription status after expiryTimeMillis has passed to get the latest status of the subscription.

The contents of the JSON response vary depending on the state of the subscription, as shown in the following snippets. For example, if you query for a subscription during the grace period (form of payment is bad), the expiryTimeMillis is dynamically updated to a future timestamp and paymentState is set to 0:

{
  "kind": "androidpublisher#subscriptionPurchase",
  ...
  "expiryTimeMillis": timestamp_in_future,
  "autoRenewing": true,
  ...
  "paymentState": 0  # Payment pending
}

If you query for a subscription after the subscription was successfully renewed (form of payment was updated), the expiryTimeMillis is set to a timestamp in the future and paymentState is 1:

{
  "kind": "androidpublisher#subscriptionPurchase",
  ...
  "expiryTimeMillis": timestamp_in_future,
  "autoRenewing": true,
  ...
  "paymentState": 1  # Payment received
}

If you query the subscription after the grace period has lapsed, you will either find the subscription is on hold (if you enable Account Hold in the Google Play Console) or is cancelled (if you don't enable Account Hold in the Google Play Console). For sample JSON responses for SUBSCRIPTION_ON_HOLD and SUBSCRIPTION_CANCELLED, refer to the Account Hold - SUBSCRIPTION_ON_HOLD section.

Account Hold - SUBSCRIPTION_ON_HOLD

The account hold period lasts 30 days. During account hold, you should check if the user's subscription has been cancelled, restored, or repurchased. During account hold, inform your user why access to the subscription was suspendend. To inform the user, provide a message in your app with instructions on how to fix their payment method and regain access to the subscription. For example, "There is a problem with your subscription. Navigate to the Google Play subscription settings to fix your payment on Google Play." This message would link to the Google Play subscription settings so that they can fix their payment method. You should also take some other actions, such as:

  • If the user updates their form of payment and the subscription is recovered, your app should restore access to the subscribed content. For more information, refer to Subscription recovered - SUBSCRIPTION_RECOVERED. However, if the subscription isn’t recovered during this hold period, the subscription is cancelled, and the user must purchase a new subscription.
  • If your users expect your app to access the subscirption outside of the app, you might want to send a push notification or an email to the user to let them know that their subscription is no longer active. If your subscription are only accessible when the user opens your app, you might only need to tell them about the subscription disruption the next time the user opens the app.

To verify that an account is still on hold, you should check the user's current subscription status whenever that user attempts to access the subscribed content in your app.

Subscription recovered - SUBSCRIPTION_RECOVERED

After recovering a subscription, typically the purchase token is identical to what it was before the user's account hold started. It's possible, however, that the user regained access to the subscribed content by repurchasing the subscription during the hold period. In this case, a new purchase token value is returned to represent the new instance of the subscription.

After registering the new subscription data in your server, you can display a message in your app informing users that their subscription was restored. For example, "Your updated form of payment was recorded and your subscription has been recovered."

Subscription cancellation - SUBSCRIPTION_CANCELLED

A user can voluntarily cancel a subscription from the Play Store or have their subscription automatically cancelled if they don’t recover after being on hold. When your secure backend server receives a SUBSCRIPTION_CANCELLED Real-time Developer Notification:

  • Display a message in your app informing the user that their subscription was cancelled, such as "Your subscription will expire on **some_date**. Navigate to the Google Play subscription settings to restore your subscription." This meessage should link to the Google Play subscription settings so that the user can renew their subscription.
  • You should offer the ability to permanently dismiss this message.

When you receive the new purchase token, follow the steps in Verify a purchase token.

Note:Cancellation messages might frustrate users, especially users who manually cancelled a subscription (as opposed to cancellations resulting from an outdated form of payment). You might choose not to inform users who manually cancelled a subscription.

If your app supports subscriptions, include a link on a settings or preferences screen that allows users to manage their subscriptions. An example of this link appears in Figure 1. In this link's click handler, add logic to determine whether the user has any non-expired subscriptions for your app (where expiryTimeMillis is in the future or autoRenewing is set to true):

  • If a user doesn't have any such subscriptions within your app, direct them to the page showing all of their other subscriptions, as shown in Figure 2, using the following URL:

    http://play.google.com/store/account/subscriptions
    
  • If, on the other hand, a user does have a non-expired subscription, you can navigate them directly to their subscription, as shown in Figure 3, using the following URL:

    https://play.google.com/store/account/subscriptions?sku=your-sub-product-id&package=your-app-package
    

Each subscription's SKU matches the product ID that you assigned to it when creating it in the Play Console. To determine the SKU for an existing subscription programmatically, query your app's backend for the list of subscriptions associated with a particular user. For an example of the necessary server-side logic, see the queryCurrentSubscriptions() method within the ClassyTaxi sample app.

A Settings screen that includes a button called
           'Google Play Subscriptions'
Figure 1. The Google Play Subscriptions button in this image provides an example of a "manage subscriptions" link.
A subscription details screen that shows a user's
           subscriptions across all apps
Figure 2. Screen showing all of a user's subscriptions that they've bought outside of the app that sent them to this screen.
A subscription details screen that shows a specific
           subscription that the user has purchased in a particular app
Figure 3. Screen showing details for a specific subscription that the user has bought from the app that sent them to this screen.

Allow subscription upgrade or downgrade

You can offer users different subscription tiers, such as a base tier and a premium tier. Figure 4 shows a screen that offers two subscription tiers:

Figure 4. Subscription tiers.

Users should be able to access a similar screen to upgrade or downgrade a subscription by purchasing a different tier subscription. Your app should handle this case using the same in-app product purchase flow used to purchase the original subscription in Enable the purchase of an in-app product. However, when upgrading or downgrading, you pass the product IDs for the current subscription and the future (upgraded or downgraded) subscription to the BillingFlowParams object using the addOldSku() method. For example:

Kotlin

val flowParams = BillingFlowParams.newBuilder()
       .addOldSku(currentId)
       .setSku(newId)
       .setType(BillingClient.SkuType.SUBS)
       .build()
val responseCode = billingClient.launchBillingFlow(activity, flowParams)

Java

BillingFlowParams flowParams = BillingFlowParams.newBuilder()
       .addOldSku(currentId)
       .setSku(newId)
       .setType(SkuType.SUBS)
       .build();
int responseCode = mBillingClient.launchBillingFlow(flowParams);

When you receive the purchase token, follow the same verification process used for a new purchase token. For more information, refer to Verify a purchase. The Google Play Developer API will return a linkedPurchaseToken in the subscription resource. Be sure to invalidate the token provided in the linkedPurchaseToken to ensure that the old token is not used to get access to your services.

When a user upgrades or downgrades, a SUBSCRIPTION_PURCHASED state is sent to your secure backend server. To handle the SUBSCRIPTION_PURCHASED, refer to Handle SUBSCRIPTION_PURCHASED.

Set proratation mode

When upgrading/downgrading, you can set replaceSkusProrationMode in the BillingFlowParams class to provide further details regarding to what kind of proration will be applied when upgrading/downgrading user’s existing subscription.

Kotlin

val flowParams = BillingFlowParams.newBuilder()
       .setSku(skuId)
       .setType(billingType)
       .setOldSkus(oldSkus)
       .setRepleaceSkusProrationMode(repleaceSkusProrationMode)
       .build()
val responseCode = billingClient.launchBillingFlow(activity, flowParams)

Java

BillingFlowParams.newBuilder()
    .setSku(skuId)
    .setType(billingType)
    .setOldSkus(oldSkus)
    .setRepleaceSkusProrationMode(repleaceSkusProrationMode)
    .build();

The following table lists all of the proration modes.

IMMEDIATE_WITH_TIME_PRORATION Replacement takes effect immediately, and the new expiration time will be prorated and credited or charged to the user. This is the current default behavior.
IMMEDIATE_AND_CHARGE_PRORATED_PRICE Replacement takes effect immediately, and the billing cycle remains the same. The price for the remaining period will be charged.

Note: This option is only available for subscription upgrade.

IMMEDIATE_WITHOUT_PRORATION Replacement takes effect immediately, and the new price will be charged on next recurrence time. The billing cycle stays the same.

To understand how each mode works, consider the following scenario:

Samwise has a subscription to online content from the Country Gardener app. He currently has a monthly subscription to the Tier 1 version of the content, which has text-only content. This subscription costs him $2/month, and renews on the first of the month.

On April 15, Samwise chooses to upgrade to the Tier 2 subscription, which includes video updates, and costs $3/month.

When upgrading the subscription, the developer selects a proration mode. The following list identifies how each proration mode affects Samewise's subscription.

  • IMMEDIATE_WITH_TIME_PRORATION - Using this mode, Samwise's Tier 1 subscription is immediately ended. Since he paid for a full month (April 1-30), but only used half of that duration, half of a month's subscription ($1) is applied to his new subscription. However, since that new subscription costs $3/month, the $1 credit balance only pays for ten days. So Samwise's credit pays for his subscription from April 15-25. On April 26, he is charged $3 for his new subscription, and another $3 on the 26th of each month following.
  • IMMEDIATE_AND_CHARGE_PRORATED_PRICE - Using this mode, Samwise's Tier 1 subscription is immediately ended. Since he paid for a full month (April 1-30), but only used half of it, half of a month's subscription ($1) is applied to his new subscription. However, since that new subscription costs $3/month, the remaining 15 days costs $1.50. So he is charged the difference of $0.50 for his new subscription, and another $3 on the first of each month following.
  • IMMEDIATE_WITHOUT_PRORATION - Using this mode, Samwise's Tier 1 subscription is immediately upgraded to the Tier 2, with no extra charge, and on May 1st he is charged $3 for his new subscription tier, and another $3 on the first of each month following.

Allow subscription re-subscribe

Users can re-subscribe to a cancelled subscription even if the subscription has not expired yet. You might allow them to re-subscribe within your app by applying the same in-app product purchase flow to the cancelled subscription (using the same product ID). For more information, refer to Enable the purchase of an in-app product

The new subscription will replace the old one, and renew on the same expiration date. For example, Achilles has a subscription to Example Music App. His subscription is currently due to expire on August 1. On July 10, he re-subscribes to the 1-month subscription at the same price per month. The new subscription will be prorated with the remaining credit, immediately be active, and renew on August 1.

You should display an appropriate UI for subscription re-subscribe:

  • If a user does not have an active subscription, the app will have a “buy” button.
  • If the user has a cancelled subscription (SUBSCRIPTION_CANCELLED), the app might have a “resubscribe” button. For more information, refer to Handle SUBSCRIPTION_CANCELLED.

When you receive the purchase token, follow the same verification process used for a new purchase token. For more information, refer to Verify a purchase. The Google Play Developer API will return a linkedPurchaseToken in the subscription resource. Be sure to invalidate the token provided in the linkedPurchaseToken to ensure that the old token is not used to get access to your services.

Refund the cost of a subscription

Google Play does not provide a refund window for subscriptions. Instead, users will need to directly request a refund from you. Users can request a refund using the My Orders page in the Play Store, or by contacting you directly.

If you receive requests for refunds, you can use the Google Play Developer API or the Merchant Center to:

  1. Cancel the subscription (Purchases.subscriptions:cancel).
  2. Verify that it is already cancelled (returns an HTTP response code of 200) (Purchases.subscriptions:cancel.
  3. Refund the user's payment without cancelling the subscription (Purchases.subscriptions:refund).

If you want to refund more than the most recent payment, you can process additional refunds through the Merchant Center.

If the subscription is cancelled, a SUBSCRIPTION_CANCELLED state is sent to your secure backend server. To handle the SUBSCRIPTION_CANCELLED, refer to Handle SUBSCRIPTION_CANCELLED.

Revoke a subscription

Using the Google Play Developer API, you can revoke the a subscription using Purchases.subscriptions:revoke. Revoking a subscription instantly removes access to the subscription and is usually done when you or Google suspects fraud.

Cancel a subscription

A user can also cancel a subscription from the Play Store app. Using the Google Play Developer API, you can also cancel a subscription using Purchases.subscriptions:cancel.

Note: This API is usually used to when users request a refund from the My Orders page. For more information, refer to Refund the cost of a subscription

Users retain access to the content until the end of the current billing cycle. When the billing cycle ends, access is revoked.

Important: You shouldn't remove a subscription from Google Play while any user is still entitled to the content. Removing content that is owed to a user will result in penalties. For more information, refer to the the Cancellations section in Create a subscription.

Defer billing

Using the Google Play Developer API, you can advance the next billing date for a subscriber using Purchases.subscriptions:defer. The user continues to be subscribed to the content, and has full access to it, but is not charged during the deferral period. The subscription renewal date will be updated to reflect the new date. Deferred billing allows you to:

  • Give users free access as part of a bundle or a special offer, such as giving free access to web content to users who subscribe to a print magazine.
  • Give free access to customers as a goodwill gesture.

Billing can be deferred by as little as one day and as long as one year per call to the API. You can call the API again before the new billing date arrives to defer billing further.

For example, Darcy has a monthly subscription to online content for the Fishing Quarterly app. She is normally billed £1.25 on the first of each month. In March, she participates in an online survey for the app publisher. The publisher rewards her with six free weeks by deferring the next payment until May 15 (six weeks after her previously scheduled billing date of April 1). Darcy is not charged for April or the beginning of May, and still has access to the content. On May 15, she is charged the normal £1.25 subscription fee for the month. Her following renewal date will be June 15.

You might want to notify the user (using an email or within the app) to let them know that their billing date has been deferred (changed).

Win back a customer

If a loyal customer has left your service after a long time, you might want to offer a product ID that represents a special pricing for your subscription, also called a winback SKU. You can provide the offer in your app, or notify the user of the offer in an email. To start a winback subscription, launch the purchase flow in your Android app using the Google Play Billing Library. This is the same process as a new subscription, but you can determine which SKU is available to the user.

Next steps

After you have added subscription-specific features, proceed to Best Practices.