Someone buys a chapter in your Android app. It opens, and they start reading. From the app screen, the purchase looks finished.
There is one more result to check: did Google Play receive confirmation that your app processed it?
The 30-second illustration shows those two outcomes side by side. It is an example flow, not a recording of a customer purchase.
What can go wrong
For a completed purchase, your app needs to verify the purchase, grant the right access, and tell Play it was processed. If an eligible purchase is left unacknowledged, Play can automatically refund it and revoke the entitlement. A consumable follows a different final step: consuming it also fulfills the acknowledgment requirement. A pending purchase is different again; it should not unlock new access until it becomes PURCHASED.
A test worth running
Use a license tester and a Play test payment method for a non-consumable item. After the purchase completes, check both outcomes:
- Can the person open exactly what they bought?
- Is the purchase acknowledged in Play, rather than only marked accessible in the app?
Then close and reopen the app. The correct access should still be there, without a second grant or a new purchase prompt. Repeat the exercise for any consumable or pending flow you support; their expected outcomes differ. Play's test-purchase timing is accelerated, so do not use the test refund window as the production deadline.
This small test catches a gap that is easy to miss when you watch only the app screen. It also gives you two concrete places to investigate when a purchase is later refunded: the app's entitlement record and Play's processing state.
References: Google Play purchase processing · Testing Play Billing
Prepared with AI assistance and checked against the linked Google documentation.
Top comments (8)
The two checks you set up, access works and then Play shows the purchase acknowledged, catch a useful gap. I'd add one interruption test between them: force-stop the app after the purchase succeeds locally but before verification or acknowledgment finishes, then reopen with the same account. That checks recovery without a duplicate grant or an unacknowledged purchase. Have you tried the same sequence after switching accounts or losing network mid-verification?
The interruption test is useful because access working once doesn’t establish that the app can recover after a restart.
We haven’t yet tested the sequence after switching accounts or losing network mid-verification.
That gives you two distinct failure paths, and they need different assertions. For mid-verification network loss, relaunch and check that the same purchase token restores exactly one entitlement and reaches ACKNOWLEDGED in Play. For account switching, check that the second account gets no entitlement from that token and that switching back restores the original, still once.
This distinction helps. Do you mean switching the app’s signed-in account or the Google Play account?
A related gap we hit on the promo-code path: when we redeemed a Google Play subscription promo code on a test device, our analytics (RevenueCat) recorded it as INITIAL_PURCHASE with period type NORMAL and price 0, not as a trial. The 'new trials' counter stayed at zero while the active-subscriber count went up by one. Entitlement worked, but the ledger didn't say what I expected, which is the same 'app screen is fine, the record says something else' pattern as an unacknowledged purchase. If you already test with a license tester, it may be worth adding one pass through Play Store > Payments & subscriptions > Redeem code and checking what your backend actually receives. (Disclosure: I work on an Android/iOS app that uses Play promo codes.)
What did you expect the purchase to be classified as?
I expected it to show up as a trial, or at least as a distinct promotional grant. What the record said was a normal initial purchase at price 0, so the trial counter never moved and I almost concluded the code had not worked. I now read promo redemptions from active subscribers who have spent nothing, not from the trial count.
The same lesson hit us on the client side. When a user closed the purchase sheet, the SDK returned a cancel code, and our funnel filed it as a purchase error. 26 Android sessions were counted as failed when nobody had failed. Splitting 'user cancelled' from 'actually errored' changed which problems we chased.
When you test, do you assert on the event type your backend receives, or only on entitlement plus the acknowledged state?
We check backend notification types as well as access and acknowledgment.
In live tests, we looked at purchase and expiry notifications and the corresponding access changes. Separate purchases confirmed acknowledgment in Play.
We haven’t verified the promo-code/trial reporting or cancellation-versus-error analytics cases you described. Our checks are on Google Play notifications; they don’t lead to conclusions about how RevenueCat classifies those events.