Drizz raises $2.7M in seed funding •
Featured on Forbes
Drizz raises $2.7M in seed funding •
Featured on Forbes
Logo
Schedule a demo
Blog page
>
Automating In-App Purchase Testing for Mobile Games: The Four Layers

Automating In-App Purchase Testing for Mobile Games: The Four Layers

A single in-game purchase touches four independent systems: storefront UI, payment sandbox, server-side receipt validation, and post-purchase inventory. Skipping any one layer is why payment-successful-but-item-not-delivered bugs ship. This is the layered testing pattern that catches them.
Author:
Asad Abrar
Posted on:
July 20, 2026
Read time:

In-app purchases carry more revenue risk per bug than any other testing surface in a mobile game.

When storefront misrenders a limited-time offer, when sandbox returns receipt validation error 21002, or when server credits a purchase but client fails to update player's inventory  failure lands directly on player's screen and, more importantly, on studio's revenue line.

The reason IAP testing feels harder than any other category is that a single purchase touches four independent systems: storefront UI, payment sandbox, server-side validation, and post-purchase inventory. Each has its own failure modes, and none of four is fully covered by any single testing tool.

Most studios end up assembling a custom stack. The complete mobile game testing guide already flags monetization as least mature category in space.

This post covers four layers, specific failure modes that show up in each, and stack that actually catches them.

The four layers of IAP testing

Every in-game purchase runs through same four systems in sequence, regardless of engine, storefront, or payment provider.

What this diagram helps with: a QA engineer can watch transaction move through each stage and attribute a bug to exact system where it happened, rather than debugging "shop is broken" as one undifferentiated problem. Roughly half of shipped IAP bugs live between stages 3 and 4  server credits item, but client fails to refresh inventory.

Layer 1: Storefront UI

Everything player sees before tapping Buy. Shop tiles, promotional pricing, limited-time offer countdowns, currency display, regional price conversion, restore-purchases button.

The failure modes at this layer are visual and driven by remote configuration:

  • Stale prices after a remote config push. The server updates price of a bundle at 09:00, client is still rendering yesterday's price at 09:15 because config didn't refresh on foreground.
  • Limited-time offers rendering past expiry. A weekend event ends Sunday at 23:59 in player's local time, but timer keeps ticking until next launch because it isn't recalculated against server time.
  • Currency conversion errors on regional pricing. A price displays as $0.99 in a market that should show €0.89, either because locale isn't detected correctly or because a decimal-separator mismatch turned 0,89 into a rendering error.
  • Missing bundle art or crashed shop tiles. A CDN failure or an addressables miss produces an empty tile that shop layout doesn't gracefully handle.

Traditional automation tools have a specific weakness here. The shop is rendered inside game's canvas, so Appium and other native automation frameworks see one opaque view instead of individual bundle tiles.

Vision AI reads rendered screen way a player does  matching on visible price text, promotional badges, and layout. It's layer of stack that catches storefront regressions on real release builds.

Layer 2: Payment sandbox

The Apple StoreKit test environment and Google Play Billing test environment sit between storefront and real payment processor during testing. Both are mandatory. Both have specific behaviours that differ from production, and testing IAP without exercising both sandbox environments end-to-end is one of most common gaps in mobile game QA.

Key failure modes at this layer:

  • Sandbox account exhaustion. Apple sandbox accounts can only make so many purchases before they hit a rate limit; hitting it mid-test run produces flaky failures that look like network errors.
  • Test purchase caching. iOS caches a completed sandbox purchase for account across reinstalls until receipt is explicitly cleared. A test that expects a fresh purchase gets a stale "already owned" response instead of expected clean state.
  • Different behaviour from production. Apple's StoreKit documentation is explicit that some transaction flows differ between sandbox and production. Subscriptions renew on an accelerated timer in sandbox. Refunds behave differently. Any test that assumes production behaviour from a sandbox result will produce false positives.
  • Payment cancellation and retry flows. The user taps Buy, gets payment sheet, taps Cancel, taps Buy again. Testing that second Buy produces a clean purchase and not a stuck "processing" state is single most-searched IAP test in research responses.

This layer belongs to first-party sandbox tools. Third-party automation frameworks (Drizz, Appium, Charles Proxy) can orchestrate around sandbox, but they cannot replace it. Detailed setup for both platforms is covered in sibling in-app purchase test guide for iOS and Android.

Layer 3: Server-side receipt validation

After a sandbox purchase completes, game client sends receipt to your backend, and backend validates it against Apple's or Google's servers and returns a signal to grant item. This is where most confusing bugs live.

Apple receipt validation status codes deserve their own memorisation exercise:

  • 21002  malformed receipt data. The most-Googled receipt error in space, and almost always a client-side base64 encoding problem, not a genuine server issue.
  • 21005  receipt server unavailable. Requires a client-side retry with backoff.
  • 21007  sandbox receipt sent to production endpoint. Shipped-to-production games see this when a QA build accidentally makes it into a release.

Apple's full list is documented in App Store Receipt validation guide.

Google Play Billing does not use numeric status codes in same way. It returns response codes like BILLING_UNAVAILABLE and ITEM_ALREADY_OWNED. The "already owned" semantic is one that causes most confusion for consumable purchases  client has to explicitly acknowledge purchase before item becomes available for repurchase.

Testing this layer is where Charles Proxy and Proxyman earn their place in stack. Intercept receipt validation request between client and server, rewrite response to force a specific error code, and observe how game client handles it.

This is how teams catch bug where a 21002 response leaves storefront stuck on "processing" instead of surfacing a retry. The same pattern generalises to any payment flow testing on mobile without failing test cards every sprint.

Layer 4: Post-purchase inventory sync

The layer that ships most production bugs and is one teams' automation touches least. After server validates receipt, game client is supposed to update player's inventory  add coin bundle to their wallet, unlock character, mark battle pass as purchased. Teams routinely test that purchase completes and forget to verify that item actually arrived.

Failure modes:

  • "Payment successful but item not delivered." The server credits purchase, response reaches client, and client's inventory UI fails to refresh. This is single most-cited IAP bug in research responses across both engines.
  • Duplicate credit on retry. The client didn't get first response, retried validation, and server credited purchase twice. This is a revenue-costing bug in other direction.
  • Ghost items after failed purchase. The purchase failed on Layer 3, but client optimistically added item to inventory in advance and forgot to roll back.
  • Restore purchases wiping progression. The player taps "Restore Purchases," and client naively overwrites current inventory instead of merging. Rare but catastrophic.

Catching a Layer 4 bug requires visually verifying that inventory screen shows new item after purchase completes. That's a visual regression check against game's rendered inventory UI, which sits inside same canvas that native automation cannot read.

Testing at this layer is a natural extension of same dynamic UI element handling that wider Vision AI stack handles for game builds.

Testing IAP in one afternoon

A single-afternoon evaluation is more informative than any vendor demo. Take five IAP flows from your live game  a single-item consumable, a bundle, a subscription, a limited-time offer, and a restore-purchases flow  and run them through each layer with your candidate stack.

  1. Layer 1: Author shop-tile test in your visual automation tool. Force price to change via remote config while test is running. Does test catch stale render?
  2. Layer 2: Run sandbox purchase. Kill network during payment sheet. Does test verify that a retry produces a clean purchase and not a stuck state?
  3. Layer 3: Use Charles Proxy to intercept receipt validation and force a 21002 response. Does your client surface correct retry, or does it hang?
  4. Layer 4: Complete a successful purchase and verify that inventory screen actually renders new item. Not just "purchase successful" toast  actual inventory tile.

An IAP test suite that doesn't do all four is not testing IAP. It is testing one layer and hoping other three work.

Tools that do this well

Three tools cover four layers together. No single tool covers all four alone; honest recommendation is a small stack rather than a monolith.

Drizz

Drizz is a Vision AI mobile testing platform that reads rendered screen and runs plain-English tests on real iOS and Android devices.

On IAP surface it covers Layers 1 and 4  storefront UI and post-purchase inventory sync. These are two layers no other automation tool touches directly for games.

Because Drizz matches on rendered pixels rather than on selectors or view hierarchies, it works on exact game canvas that Appium is blind to. Storefront tests verify that promotional prices, LTO timers, currency display, and bundle art render correctly across device matrix.

Post-purchase tests do specific check that catches "payment successful but item not delivered" bug: they verify inventory UI actually renders newly delivered item, not just success toast.

Reported flakiness on production customer suites sits around 5%. Every run returns per-step screenshots and action logs, which is difference between attributing a Layer 1 bug to a locale-conversion error and spending an afternoon debugging why shop tile "looks weird."

Suited to game QA teams shipping weekly or biweekly live-ops updates on Unity or Unreal titles, where storefront lives inside engine canvas. This is a subcategory drill-down for broader mobile game testing tool comparison.

Charles Proxy

Charles Proxy is industry-standard HTTP debugging proxy. On IAP surface, it covers Layer 3.

The workflow is direct: intercept receipt validation request between game client and your backend, rewrite response to force any error code client should handle, and observe result. Force a 21002. Force a 21005. Force a delayed response with a two-second timeout. Force a payload that returns success but with missing fields.

Every game with a receipt-validation server should have a Charles Proxy suite for Layer 3 negative testing. Proxyman is near-equivalent for macOS-native workflows, but Charles remains more widely adopted tool across game studios.

Best fit for any team validating a receipt-validation backend, which is roughly every game studio shipping IAP.

Apple StoreKit Testing + Google Play Billing Testing

The mandatory sandbox environments: non-negotiable, first-party, and free.

Apple's StoreKit Testing in Xcode provides local sandbox testing without a network round-trip, plus a full sandbox environment for pre-production.

Google's Play Billing test environment provides both static test SKUs (android.test.purchased, android.test.canceled, android.test.item_unavailable) and a full alpha-track sandbox against real Play Billing infrastructure.

Both are mandatory for Layer 2 and neither is replaceable by third-party tools. Best fit for every mobile game shipping IAP  there is no honest way to skip either sandbox.

Limitations of automated IAP testing

Automated IAP testing has real bounds:

  • Real-money production purchases cannot be tested against actual credit cards without spending real money. End-to-end production validation always has a manual pass in it.
  • Sandbox behaviour differs from production in specific documented ways. Any test suite that treats sandbox as identical to production will produce false positives.
  • Restore-purchases flows require sandbox account rotation and cannot be run continuously.
  • Cross-region pricing tests require test accounts in each target region, which is a non-trivial infrastructure investment for global games.

None of this makes IAP testing not worth automating. The automated suite catches pre-production and regression tier of bugs. A small manual pass on release candidate stays in picture.

FAQ

What is Apple receipt validation error 21002?

Status code 21002 means "data in receipt-data property was malformed or service experienced a temporary issue."

In practice, 21002 is almost always a client-side base64 encoding problem  receipt data being sent to Apple is not correctly encoded  rather than a genuine server issue on Apple's end.

The correct response is to re-encode receipt on client and retry. A game client that surfaces "network error, try again" for a 21002 is doing wrong thing.

Can I test IAP without an Apple sandbox account?

Partially. Apple's StoreKit Testing in Xcode allows local sandbox testing without a network sandbox account, which covers a large portion of Layer 2 test cases. Full end-to-end testing against Apple's real sandbox infrastructure requires a sandbox account. There is no way to test production-parity IAP behaviour without either local StoreKit test environment or a real sandbox account.

How do I test "payment successful but item not delivered"?

The bug lives at Layer 4  post-purchase inventory sync. To reproduce it, complete a real sandbox purchase, then verify that inventory screen actually renders new item.

The pattern most teams miss is verifying inventory UI itself. They verify "purchase successful" toast instead, which fires on Layer 2 completion and does not prove that Layer 4 succeeded.

A visual regression test on inventory screen after purchase catches this class of bug.

Do I need Charles Proxy or is Proxyman good enough?

Either works for Layer 3 interception. Charles is more widely adopted at game studios and has broader documentation for game-specific workflows. Proxyman is macOS-native and often preferred for its UI. Both can intercept HTTPS traffic on iOS and Android with right root certificate installed on test device. Pick one and standardise team on it  do not run both.

How much of IAP testing can be automated?

Roughly 85-90% of surface. Layers 1, 2, and 3 automate cleanly. Layer 4 automates with a visual regression tool that can see game canvas.

The remaining 10-15% is manual: production-parity real-money validation, sandbox account rotation for restore-purchases, and release-candidate smoke test that a human plays end-to-end before shipping.

That last 10% is not going away. It's sanity check that keeps IAP revenue safe on release day.

About the Author:

Asad Abrar
LinkedIn logo white letters in a blue rounded square background.
Co-founder & CEO, Drizz
Ex-Coinbase PM and IIT Kharagpur grad killing flaky mobile tests by day, and obsessing over F1 lap timings by night.
Schedule a demo