Tag every Google Play purchase with an obfuscated account id, or a chargeback arrives with no way to trace it
Google Play lets you stamp a stable, hashed id onto every purchase and reads it back when a dispute lands. Set it and a chargeback review ties to the exact user whose usage you have to report. Skip it and you are matching a bare order id to guesses under a 24-hour clock.

Key takeaways
- The obfuscated account id is a string you attach to a Google Play purchase with setObfuscatedAccountId. Google Play stores it with the order and returns it later as obfuscatedExternalAccountId, so a purchase can be traced back to the user in your system who made it.
- In Google's words, the field lets Google Play detect irregular activity, such as many devices making purchases on the same account within a brief timeframe. Setting it feeds Google's own fraud screening at purchase time, before a transaction completes.
- The identifier is limited to 64 characters and must not carry personal information in cleartext. Google says storing PII such as emails in this field results in purchases being blocked, and recommends a one-way hash or encryption instead.
- When a bank chargeback needs your review, Google Play sends a PendingRefundReviewNotification that names an order, not a person. The obfuscated account id is the join key that maps that order back to the user record whose usage you have to report.
- You answer a dispute by calling orders.reviewrefund within 24 hours with a refundPreference, a sampleContentProvided flag, and consumption evidence like consumptionPercentageMilliunits and consumptionUsageEvents. You can only build that evidence once you know which user the order belongs to.
- For Google Play orders placed on or after August 3, 2026, a lost chargeback bills the developer the purchase price minus Google's service fee, plus the bank's chargeback fee. A dispute you cannot answer because you cannot identify the order is now a direct cost, not just a lost sale.
- Set the id on every purchase, not just subscriptions, and read it back server-side. On the client it comes from Purchase.getAccountIdentifiers, and on your backend it is the obfuscatedExternalAccountId field on the purchase record.
A Google Play chargeback review shows up naming an order and a purchase token. It does not tell you who the customer is. If you never stamped your own identifier onto that purchase, you are now matching a bare order id against your user table under a 24-hour clock, and you have to answer with usage evidence you may not be able to find. The obfuscated account id is the fix. It is a short string you attach at checkout that Google Play stores with the purchase and hands back to you later, so every order can be traced to the exact user who made it. Here is what the field is, why it decides whether you can answer a dispute at all, and what skipping it costs now that a lost chargeback is a bill.
What the obfuscated account id actually is
The obfuscated account id is one optional string you pass into the Google Play billing flow when a customer buys something. You set it with setObfuscatedAccountId on the BillingFlowParams builder, and Google stores it alongside the purchase. It is not the customer's name, not their email, and not their Google account. It is your own identifier for your own user, written in a form Google can keep without learning who the person is.
It is a string you set at checkout, not a name
In Google's words, setObfuscatedAccountId specifies an optional obfuscated string that is uniquely associated with the purchaser's user account in your app. The word obfuscated is doing real work. Google does not want your raw user id or anything that identifies the person. It wants a stable token that maps one to one to a user on your side, and nothing more. The field is limited to 64 characters, which holds a hash comfortably and not much else.
Google reads it for its own fraud screening first
Before it is ever useful to you, the field does a job for Google. The billing documentation says Google Play can use this value to detect irregular activity, such as many devices making purchases on the same account within a brief timeframe, and that Google uses this data to detect suspicious behavior and block some types of fraudulent transactions before they are completed. So the first payoff of setting it is upstream, in cleaner purchases and fewer of the fraudulent ones that turn into voids and disputes later. Google lists the obfuscated account id and the Voided Purchases API together as its two core anti-abuse tools for a reason.
Why it matters when a chargeback review lands
A refund you can see coming is easy. The hard case is the bank chargeback, because it does not start with your customer talking to you. It starts with the bank, and Google Play forwards it to you as a review with a clock attached.
The dispute names an order, not a person
When a customer disputes a charge with their bank and Google needs your input, Google Play sends a PendingRefundReviewNotification. That message identifies the order. It does not carry your user id, because Google never had your user id. It only had whatever you stamped onto the purchase. If that was nothing, you are now reverse-searching a bare order id and purchase token against your own records, hoping you logged the token at purchase time and hoping the match is unambiguous. If you set an obfuscated account id, the purchase carries your own hash, you look up the user in one query, and you move on to building evidence instead of hunting for identity.
What orders.reviewrefund actually asks you for
Answering the dispute means calling the orders.reviewrefund method within 24 hours. Google records your first call and ignores the rest, so the first answer is the only answer. These are the fields it wants, and every one of the evidence fields assumes you already know which user the order belongs to.
| Field | Required | What it carries |
|---|---|---|
| pendingRefundToken | Yes | The token from the PendingRefundReviewNotification you are answering |
| refundPreference | Yes | APPROVE, DECLINE, or NEUTRAL, your recommendation on whether Play should refund |
| sampleContentProvided | Yes | Whether you gave a free sample, trial, or a description of the feature before purchase |
| consumptionPercentageMilliunits | Optional | How much of the purchase the customer consumed, 0 to 100,000 milliunits |
| consumptionUsageEvents | Optional | A list of events, each an instance where the user consumed or used what they bought |

What skipping it actually costs
For most of Google Play's history, a chargeback you could not defend was a lost sale and a shrug. That changed. For orders placed on or after August 3, 2026, a lost chargeback bills the developer the purchase price minus Google's service fee, plus the bank's chargeback fee. The dispute you cannot answer is now a line item.
Walk one order. A customer disputes a $9.99 purchase with their bank. Google Play sends the review, and you have 24 hours. If you tagged the purchase, you find the user, see they consumed most of what they bought, and answer reviewrefund with a DECLINE preference and the consumption evidence, giving Google a real case to contest an illegitimate dispute. If you did not tag it, you either cannot identify the order in time or you answer with nothing, the dispute is decided without your side, and on a post August 3 order you pay the $9.99 minus Google's fee back, plus a flat bank chargeback fee that often lands near $20. On a small sale, that flat fee alone can be larger than what you netted.
- The lost proceeds: your net share of the sale, reversed.
- The bank's chargeback fee: a flat cost the card network sets, charged on top on orders placed after August 3, 2026, that a plain refund never carries.
- The wasted spend: the compute, third-party API calls, and storage the account already used, gone whether or not you could answer.
- The pattern you cannot see: without a stable account id you also cannot tell that the same user is disputing again and again, so serial abuse reads as unrelated one-off losses.
How to set it without getting purchases blocked
Two rules cover almost every mistake teams make with this field. Hash the id, and set it everywhere.
Hash your user id, never send PII
Do not put an email, a phone number, or any raw personal detail in this field. Google is explicit that storing PII such as emails in cleartext results in purchases being blocked, and it recommends a one-way hash or encryption to generate the value. The clean pattern is a one-way hash of your internal user id, computed the same way every time so the same user always produces the same 64-character string. Do not use the person's Google account id or your developer id either. The value should mean something only to your system.
Set it on every purchase, and read it back on your server
Attach the id to every billing flow, one-time products and subscriptions alike, so no purchase is ever unlabeled. After the purchase, read it back in two places. On the client, Purchase.getAccountIdentifiers returns an object whose getObfuscatedAccountId gives you the string you set. On your backend, the server-side purchase record carries it as the obfuscatedExternalAccountId field, and the server copy is the one to trust, because a dispute arrives at your server, not at the device.
Use setObfuscatedProfileId when one account has many profiles
If your app lets one account hold several profiles, a streaming household or a game with multiple characters, set setObfuscatedProfileId as well. It is the same kind of hashed, 64-character, no-PII string, scoped to the profile that made the purchase. Google notes that setting a profile id also asks for the account id to be passed, so send both. The result is that a dispute maps not just to the account but to the exact profile that spent the money.
The iOS parallel, in one line
The App Store has the same idea under a different name. On iOS you attach an appAccountToken, a UUID, to a purchase, and it comes back on the transaction and on the CONSUMPTION_REQUEST that Apple sends when a customer asks for a refund. The shape of the problem is identical on both stores. The dispute or refund flow references a transaction, and your own identifier is what ties it back to a user whose usage you can report.
| Detail | Google Play | App Store |
|---|---|---|
| Field you set | obfuscated account id via setObfuscatedAccountId | appAccountToken |
| Format | Hashed string, 64 characters, no PII | UUID |
| Where it comes back | obfuscatedExternalAccountId on the purchase | appAccountToken on the transaction |
| The window it feeds | orders.reviewrefund, 24 hours | CONSUMPTION_REQUEST, 12 hours |
| What you report | Consumption percentage and usage events | Apple's consumption fields |
None of this is hard to build. It is easy to skip, because the day you write the checkout code is not the day a chargeback arrives, and the cost of skipping it is invisible until then. RefundHalt sets and tracks the account identifier on both stores, keeps the purchase-to-user link so a dispute always resolves to a real customer, and answers Google Play's orders.reviewrefund and Apple's CONSUMPTION_REQUEST inside their windows with the consumption evidence recorded at the time of sale. The 24-hour clock is not the moment to discover you cannot tell who bought the thing.
Frequently asked questions
- What is the obfuscated account id in Google Play billing?
- It is an optional string you attach to a purchase with setObfuscatedAccountId that is uniquely associated with the buyer's user account in your app. Google Play stores it with the order, uses it to detect irregular activity like many devices buying on one account, and returns it to you later as obfuscatedExternalAccountId so you can tie a purchase back to a specific user.
- Can I put a user's email or id in the obfuscated account id field?
- No. Google says storing personally identifiable information such as emails in cleartext in this field results in purchases being blocked. Use a one-way hash or encryption to generate the value, keep it within 64 characters, and do not use the person's Google account id or your developer id.
- How does the obfuscated account id help with a Google Play chargeback?
- A chargeback review, the PendingRefundReviewNotification, names the order, not your user. The obfuscated account id is the join key that maps that order to the right user record, so you can answer orders.reviewrefund within 24 hours with real consumption evidence instead of guessing which customer the order belongs to.
- Should I set the obfuscated account id on subscriptions or only one-time purchases?
- Set it on every purchase, both one-time products and subscriptions. Any unlabeled purchase is one you cannot trace back to a user when a dispute or void arrives, and disputes can land on any order type.
- What is the difference between the obfuscated account id and the obfuscated profile id?
- The account id maps a purchase to a user account in your app. The profile id maps it to a specific profile inside that account, for apps where one account holds several profiles or characters. Both are hashed, 64-character strings with no PII, and Google notes that setting a profile id also requires passing the account id.
Sources and further reading
- Android Developers: Fight fraud and abuse (Play Billing)
- Android Developers: BillingFlowParams.Builder (setObfuscatedAccountId, setObfuscatedProfileId)
- Android Developers: AccountIdentifiers (getObfuscatedAccountId)
- Android Developers: Help Google dispute chargebacks
- Google Play Developer API: Method orders.reviewrefund
- Play Console Help: Chargeback cost responsibility update (August 3, 2026)
- Apple Developer: Handling refund notifications (CONSUMPTION_REQUEST, appAccountToken)
RefundHalt
The refund autopilot for the App Store and Google Play
Keep reading
An unrecognized charge on a bank statement turns into a chargeback, and a chargeback costs you more than a refund
When a customer can't tell what your app charged them, they call the bank instead of you, and that dispute lands as a chargeback. Apple shows everything as apple.com/bill and lets you change nothing. Google Play lets you set the statement name. Here is what each costs and what you control.
Apple can reverse a refund it already granted, and a reversed refund your server ignores locks out a customer who paid
When the App Store reverses a refund it already granted, it expects your server to reinstate the access you revoked. Here is how the refund, refund declined, and reversed refund notifications work on the App Store and Google Play, and what each one costs when you ignore it.