Shipped a React PWA to Google Play as a TWA, offline-first, no backend, and learned some painful Play Billing lessons
▲ 17 r/PWA+1 crossposts

Shipped a React PWA to Google Play as a TWA, offline-first, no backend, and learned some painful Play Billing lessons

I built a small PWA (a 30-minute guided Ashtanga yoga practice generator) and shipped it to the Play Store as a Trusted Web Activity. Sharing the build because it's a fairly "pure" PWA and I hit a few gotchas that might save someone time.

https://preview.redd.it/p900pmsnshth1.png?width=559&format=png&auto=webp&s=f47e124a8db52ea89d6409b7895a40165ba9ffc7

The stack / shape

  • React 19 + Vite + TypeScript, no backend at all. Everything (preferences, practice history, entitlement) lives on-device.
  • vite-plugin-pwa (Workbox) for the service worker; fully offline-capable once loaded, including the audio (voice cues, bell, ambient loops are precached).
  • State-based navigation wired into the History API so the Android back gesture steps through screens instead of closing the app.
  • Pose art is inline SVG, code-split and lazy-loaded so the home screen stays light.
  • Same codebase serves the web app and the installed Android app (TWA via Bubblewrap). No separate native code.

Things that went well

  • PWA-first meant "write once, ship to web + Play" genuinely worked.
  • Offline audio via the Web Audio API (gapless ambient loop with an AudioBufferSourceNode + GainNode, which <audio loop> couldn't do without an audible seam).
  • Privacy as a feature: no accounts, no tracking, no ads, no network calls. Easy to reason about, and my favourite selling point.

The painful lessons (Play Billing in a TWA) I added a one-time in-app purchase via the Digital Goods API + Play Billing. This is where TWAs get sharp edges:

  1. Play automatic protection requires minSdk 24+, my first bundle (minSdk 23) was rejected outright.
  2. The Digital Goods API is only injected by Chrome-backed TWA providers. My default browser is Brave, which verifies the TWA (so it ran full-screen, no URL bar, looked totally fine) but does not inject window.getDigitalGoodsService. Result: hasDGService: false, PaymentRequest.show() rejecting instantly, no purchase sheet, and hours of chasing the wrong things. Switching the default browser to Chrome fixed it immediately.
  3. Play's newer "purchase options" product model needs a buy option flagged legacy/backwards-compatible, or the android-browser-helper bridge can't see the product via getDetails.
  4. Post-install Play Billing client race, right after a fresh install, the service can be not-ready and the first purchase attempt silently fails; force-stop + reopen clears it.

Net takeaway: a TWA is a great way to get a PWA into the Play Store, but billing only works for users whose provider browser supports Digital Goods (effectively Chrome). I handle the rest gracefully, when isBillingAvailable() is false, the app just doesn't offer the purchase and stays fully functional as the free tier.

Disclosure: I made this, so there's a link, but I'm posting mainly for the build discussion. Happy to go deeper on any part (service worker setup, the Web Audio looping, the TWA billing wiring).

Play Store (TWA): https://play.google.com/store/apps/details?id=com.ashtanga30.twa

Anyone else shipped TWAs with billing? Curious how you handle the non-Chrome-provider gap, that feels like the biggest weakness of the TWA-plus-billing path right now.

reddit.com
u/Squirlynl — 10 days ago

Looking for testers - 30m Yoga/Ashtanga app

Sharing my app's closed test for anyone who wants to join.

ashtanga30 generates a ~30-minute Ashtanga practice and guides you through it breath by breath, with spoken pose cues and a live view of where you are in each flow.

Join the closed test:

  1. Join the group: https://groups.google.com/g/ashtanga30
  2. Opt in: https://play.google.com/apps/testing/com.ashtanga30.twa
  3. Install: https://play.google.com/store/apps/details?id=com.ashtanga30.twa

If the opt-in link says you're not a tester yet, give it ~10 minutes after joining the group.

Feedback welcome but not required. Thanks for taking a look.

reddit.com
u/Squirlynl — 2 months ago

Looking for testers - 30m Yoga/Ashtanga app

Sharing my app's closed test for anyone who wants to join.

ashtanga30 generates a ~30-minute Ashtanga practice and guides you through it breath by breath, with spoken pose cues and a live view of where you are in each flow.

Join the closed test:

  1. Join the group: https://groups.google.com/g/ashtanga30
  2. Opt in: https://play.google.com/apps/testing/com.ashtanga30.twa
  3. Install: https://play.google.com/store/apps/details?id=com.ashtanga30.twa

If the opt-in link says you're not a tester yet, give it ~10 minutes after joining the group.

Feedback welcome but not required. Thanks for taking a look.

reddit.com
u/Squirlynl — 2 months ago