Crossdeck University
Watch — service account, notifications, one line at purchase Film in production
0:00 / 0:00
Lesson 3 of 4 · Connect your revenue

Connect Google Play

Play works differently from Stripe and Apple — a service-account key and a notification topic instead of an OAuth click. Set it up once, then add the one Play Billing line that says who's buying.

6 min Dashboard · Android

When you're done: a Google Play purchase lands on the right Crossdeck customer and grants their entitlement.

1 What this is & why it matters

Play's model: a service account and a notification topic

Each rail has its own platform-side shape, and knowing Play's up front prevents the most common "why isn't this working" question. Stripe connects with an OAuth click; Apple uploads .p8 keys; Google Play uses a service-account JSON key you upload, plus a Pub/Sub topic that Google publishes purchase notifications to.

One honest difference to expect: Play has no bulk history. Stripe lets Crossdeck list your past subscriptions; Google's stance is that a subscription belongs to the user-and-purchase-token relationship, not to an enumerable list, so Crossdeck can only fetch a purchase once it has a token to ask about. That means Play starts from a clean slate and fills in as purchases happen — expected, not a bug.

2 How to connect it

Service account, notifications, then one line at purchase

The dashboard walks you through the platform steps; the only code is the last one:

1 · Create a service account in Google Cloud, download its JSON key, and grant it access in Play Console (Users & permissions → the service account's client_email). Then upload the JSON in the Crossdeck dashboard. The key is a credential — Crossdeck stores it in Secret Manager.

2 · Wire Real-time Developer Notifications. In Play Console, point your app's RTDN topic at the Pub/Sub topic Crossdeck owns. Crossdeck receives Google's purchase notifications there.

3 · Tell Crossdeck who's buying. At purchase time, set the obfuscated account ID on the Play Billing flow to your user's ID — the same value you pass to identify():

// the same stable user ID you pass to identify()
val params = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(/* … */)
    .setObfuscatedAccountId(currentUserId)
    .build()

billingClient.launchBillingFlow(activity, params)
3 How the code works, piece by piece

The obfuscated account ID is Android's identity hint

setObfuscatedAccountId is Android's equivalent of Apple's appAccountToken — it stamps your user's ID onto the purchase. When Google's notification lands, Crossdeck re-fetches the purchase from the Play Developer API, reads the obfuscated account ID off it, and links the resulting customer to your existing developer user.

Skip it and the Play purchase still arrives, but with no hint of who bought it, so it attaches to a rail-only customer that has to be reconciled later. Setting it to the value you already pass to identify() is what closes that gap — the same identity, carried through every rail, so a buyer on Android lands on the very same person who bought on the web or in your iOS app.

4 The green result in your dashboard

The Play purchase lands on the right customer

Make a test purchase. Google's notification arrives, Crossdeck re-fetches the purchase, reads the account ID, and the subscription appears on the customer you identified — entitlement active, ready for your gate.

app.cross-deck.com · customer timeline
google sub · attached

user_847's Play subscription, matched by obfuscatedAccountId — entitlement live. Same person, third rail.

Play connects with a service-account key and an RTDN topic, not an OAuth click — and it has no bulk history, so it fills in as purchases happen. At purchase, setObfuscatedAccountId(currentUserId) with the same value you pass to identify() ties the sale to the right person. That's all three rails connected.