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 ...
For further actions, you may consider blocking this person and/or reporting abuse
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?
I meant the app's signed-in account, since that is where a duplicate or leaked grant would show up: the purchase token belongs to the first user in your backend, so a second app user on the same device should get nothing from it, and switching back should restore it exactly once. Switching the Google Play account is a separate, lighter pass: the second Play account should not see that purchase as owned, so a restore there should return nothing for it.
Thanks for clarifying. So two important checks: preventing access from carrying over to another app user, and restoring the original user’s access without duplicates. We haven’t verified those exact scenarios yet.
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.