If your PWA is listed in Google Play and you want to monetize it by selling in-app products or subscriptions, Play policy will require you to implement Play Billing. There are two APIs that you will need to implement in your PWA: the Digital Goods API and the Payment Request API.
The Digital Goods API is an interface between your app and Google Play. It allows you to retrieve the digital products and details you’ve entered for your in-app products and subscriptions in the Play Console as well as retrieve existing purchases a user has made. If you haven’t added in-app products or subscriptions in the Play Console yet, make sure to follow the Play Console setup for Play Billing.
On November 30th, 2021, ChromeOS 96 was released with the Digital Goods API 2.0 implementation.
The origin trial for the first version of the Digital Goods API ended on January 30, 2022. Therefore it is now deprecated and only v2 of the API is available.
In May 2022, Google Play Console introduced changes to their subscription models which are not currently supported by the Digital Goods API.The previous subscription model is still supported by Play. You’ll notice that in the Play Console existing subscription SKUs have automatically been converted to this new format while keeping it backwards compatible. Any new subscription SKUs you create will need to also be marked as backwards compatible in the Play Console for it to be compatible with the Digital Goods API.
On May 22, 2022, The Digital Goods v2 origin trial ended and the API has been shipped as stable on ChromeOS 100. Therefore, the Digital Goods API stopped working for users who are not on ChromeOS 100 or later. Make sure you’ve implemented feature detection to handle this scenario and disable any features that require the Digital Goods API. You can let users know that they can update their ChromeOS version to enable those features again.
On June 23rd, 2022, ChromeOS 103 was released with the Digital Goods API 2.1 implementation. This release does not have any breaking changes and only includes new methods and additional fields:
Starting on August 2, 2023, Google Play requires all new apps to use version 5 or newer of the Play Billing LIbrary. By November 1, 2023, updates to existing apps must also use version 5 or newer of the Play Billing Library. Therefore, an existing app will continue to work but to publish a new version of an existing app, use the Bubblewrap version 1.20.1 or newer to continue to be compliant with Google Play requirements.
The Payment Request API handles the actual payment transaction when a purchase is made. It utilizes the item details that the Digital Goods API provides to make the in-app purchase using the appropriate payment method, which in our case is Google Play Billing.
You can detect if the Digital Goods API is supported by checking for the
getDigitalGoodsService method in the
The Digital Goods API was designed to be compatible with various browsers and digital stores, similar to how the Payment Request API is browser-agnostic and can be used with different payment providers. To obtain an instance of the service associated with Google Play Billing, pass the string
"https://play.google.com/billing" as the payment method to
If the method throws an error, the Google Play Billing payment method is not available (e.g. the user is accessing your PWA through the browser). Instead, you should offer another payment method for transactions.
Once you have the Digital Goods service connected to Google Play, you can use the API to retrieve information about products and purchases.
getDetails() method lets you get information about the items you’ve set up in the Play Console. Information like the product title, description, and price should be displayed to the user in your app UI so they know what is available for purchase and for how much.
getDetails() method will need a list of item IDs which correspond to the product IDs of the in-app products and subscriptions you created in the Play Console.
To get the appropriate price for the user’s locale, you will need to do some additional formatting:
In v2.1 of the API, one of the fields returned by
itemType. It is an enum where the value is
”subscription” to denote whether the corresponding item is an in-app product or subscription, respectively. Being able to differentiate between the two types of products can be useful if you need to apply different treatments to each product type. For example, you may have a specific page for users to subscribe and another page for the other non-subscription products. It’s also useful for knowing the appropriate Google Play Developer API REST resource to use in your backend (
Once your products and details are displayed to the user, you can build the purchase flow with the Payment Request API. When used in conjunction with the Digital Goods API, only one input parameter is required:
Play Billing only allows the purchase of a single item at a time; the price and details of the item are already known by the Play server, so the
details parameter is not necessary. See the explainer for a more detailed explanation.
supportedMethods member of the
methodData parameter in the
PaymentRequest to identify Google Play Billing as the payment method with the string
"https://play.google.com/billing". Then in the
data member, pass along the item ID as the
Then create the payment request and call
show() to start the payment flow:
This will display the Play purchase UI to the user, where they’ll see the details about the product they’re trying to purchase. They can either abandon the transaction or proceed with the payment. If the user cancels the payment, the promise returned by
show() will be rejected with an error. If they successfully pay and complete the purchase, the promise will resolve with a
PaymentResponse. In the
details property of the payment response, a purchase token is returned.
To prevent fraud, it’s critical to verify the purchase and purchase token on your back-end server. It’s also a good idea to keep track of users and their associated purchase tokens. Learn how to implement the verification on your back-end server.
After validating the purchase, call
complete() on the payment response to finish the payment flow and close out the billing UI. You can also pass in an optional
result string to indicate the state of the payment process. It is up to the browser whether to provide any indication of this result to the user. Chrome does not create any user-visible cues so it is recommended that you display your own error or success messages in your PWA.
This purchase flow is the same for both in-app products and subscription purchases. However, for subscriptions, Google Play has additional purchase options you can implement: upgrade and downgrade. When building the
data for the payment method, you’ll need to pass in the following to initiate an upgrade or downgrade flow:
sku: This is the item ID for the new subscription to be upgraded or downgraded to.
oldSku: This is the item ID for the user’s current subscription.
purchaseToken: This is the purchase token for the user’s current subscription. Like it was noted earlier, it’s a good idea to keep track of the purchase tokens in your backend. And for this scenario and others, you should associate a user to their current purchases and purchase tokens as well.
prorationMode: This is how the new subscription will be charged when it replaces the user’s current subscription.
|immediateAndChargeProratedPrice||The subscription is upgraded immediately, and the billing cycle remains the same. The price difference for the remaining period is then charged to the user.|
|immediateAndChargeFullPrice||The subscription is upgraded or downgraded and the user is charged full price for the new entitlement immediately. The remaining value from the previous subscription is prorated for time toward the new subscription. This proration mode was recently added in the Google Play Billing Library 4.0 release. It is now available through Bubblewrap starting with version 1.13.5.|
|immediateWithoutProration||TEMPORARILY DISABLED There is a potential fraud path with this proration mode where users could get an upgraded subscription without extra payment for one billing cycle. Please be aware that we have temporarily disabled this mode while we work on the fix.|
|immediateWithTimeProration||The subscription is upgraded or downgraded immediately. Any time remaining is adjusted based on the price difference, and credited toward the new subscription by pushing forward the next billing date. This is the default behavior.|
|deferred||The subscription is upgraded or downgraded only when the subscription renews. This is useful for downgrades especially.|
|unknownSubscriptionUpgradeDowngradePolicy||No set policy. This is not recommended.|
Learn more about the different proration modes in the Google Play Billing Library reference documentation. Check out the Android developer docs for more on subscription upgrade and downgrades and proration mode recommendations.
The usage of these additional fields will look something like this:
item is the
ItemDetails of the new subscription the user is trying to upgrade or downgrade to, and
oldPurchase is the
PurchaseDetails of the user’s current subscription.
After a user purchases an item, you should grant them the proper entitlements (access to the item or content they’ve just purchased). Then, acknowledge the purchase. Acknowledging a purchase lets Google Play know that you’ve received and processed the purchase appropriately.
You should acknowledge purchases from your backend server using the Google Play Developer API. We recommend granting entitlements and then acknowledging the purchase together in your backend server.
- After a user makes a purchase client-side, send the purchase token and item ID in a request to your backend server.
- On your backend, to get details about the purchase to verify it, call:
- Grant the appropriate entitlement in your backend database.
- Then acknowledge the purchase by calling:
When you acknowledge a purchase, this lets Google Play know that the user now owns the item and should not be allowed to purchase it again. If this is an item that the user will only need to purchase once and will own forever (e.g. a game character skin), then the item is not consumable.
Alternatively, the item may be something that you limit a user to one of at a time. Then the user will need to use the item before they can purchase another one. When the user “uses” the item, to let Google Play know that the user has consumed the item, you should call the
consume() method. Google Play will then make the item available for the user to purchase again.
For items that you allow a user to own multiples of, they need to be able to be purchased repeatedly without needing to be used first (we call these repeatable items). Similarly, these items need to be “consumed” before Google Play will let the user buy it again. Therefore, even if the user has not yet used the item, you need to call the
consume() method to mark the item as consumed.
The last key user flow is to check for existing purchases (in-app products that haven’t been consumed yet and on-going subscriptions) to let your users know what subscription or items they currently own. These existing purchases will be from previous Google Play purchases on any device made in-app or on the Play Store. Purchases made from outside the app in the Play Store are called out-of-app purchases.
When retrieving existing purchases, you should also check the acknowledgement status and acknowledge any purchases that were previously made but did not properly get acknowledged. It is recommended that purchases get acknowledged as soon as possible so the user’s entitlements are up-to-date and properly reflected in the app.
The Digital Goods API
listPurchases() method will return a list of
PurchaseDetails that contains the
purchaseToken for each of the purchases. You will need to use the Google Play Developer API on your backend server to check the state of purchases and acknowledge them appropriately. You should:
Call the Digital Goods API
listPurchases()method client-side to retrieve the user’s list of purchases.
For each purchase, pass the
itemIdto your backend.
If appropriate, grant entitlement in your backend database.
and check the
If the value is 0 (yet to be acknowledged), then call:
Learn more about how to verify purchases on your back-end server before granting entitlements.
listPurchases will return information about the user’s existing purchases, the
listPurchaseHistory() method (in v2.1 of the API) will return the most recent purchase made by the user for each item, regardless of whether the purchase is expired, canceled, or consumed. The
listPurchaseHistory() method returns a list of
PurchaseDetails containing the
purchaseToken for each purchase, which you will need to use with the Google Play Developer API on your backend server to retrieve more information.
Out-of-app purchases are purchases not made in the normal in-app purchase flow. These will usually occur in the Play Store instead of in your app. There are two main ways users may make an out-of-app purchase:
- Redeeming a promo code: In the Play Store user menu, in “Offers & notifications” -> “Redeem promo code” or in “Payments & subscriptions” -> “Redeem gift code”.
- Resubscribing: In the Play Store user menu, in “Payments & subscriptions” -> “Subscriptions”. Here, users may manage all their subscriptions across different apps. For expired or canceled subscriptions, users have the option to “Resubscribe”.
When users resubscribe from the Play Store, their purchases are not acknowledged automatically which may result in them being refunded. This behavior is intentional because users should only be charged for their subscription if they open the app to use it. The user may see a “Confirm subscription” like so, reminding them to open the app.
It is up to you as the developer to implement acknowledgement of these once the user launches the app. That’s why we recommend checking for existing purchases (usually when the app first launches) and acknowledging any purchases that are not acknowledged yet.
For a good user experience, it is important to provide a way for users to manage and cancel their subscriptions in-app. We recommend creating a deep link, on a settings page or menu, that will redirect the user to the Play Store’s subscription management page for your app. Replace the following URL with your appropriate “sub-product-id” and “app-package-name”:
These user flows and code snippets are a basic implementation to demonstrate how to use the DIgital Goods API and Payment Request API in your PWA to implement Play Billing. You should utilize the APIs as it makes sense in your app’s context and use cases. For an example of an end-to-end implementation, check out our open-source sample.
Then, take a look at how to implement crucial Play Billing components in your back-end server to keep your app secure and always updated with your user’s entitlements.