Your Android app can look perfectly legitimate and still be running on a rooted device, served from a tampered APK, or driven entirely by bots.
The Google Play Integrity API is how you find out. It gives your backend server a signed, encrypted verdict covering app authenticity, device certification, and Play Store licensing status before any sensitive action goes through.
Since SafetyNet Attestation shut down in January 2025, Play Integrity is the only supported path for Android app attestation through Google Play Services.
This guide covers everything: how the integrity token request flow works, what each verdict field actually signals, how to implement both standard and classic request modes, and how to handle failed verdicts without blocking legitimate users.
What Is the Google Play Integrity API?

The Google Play Integrity API is a security service by Google that lets Android apps verify requests come from genuine, unmodified app installs running on certified devices.
It replaced the SafetyNet Attestation API, which was fully shut down on January 31, 2025. Every new Android app integration now requires Play Integrity. There is no alternative path through Google’s own tooling.
The API returns a signed, encrypted verdict covering 3 core areas: the app binary, the device environment, and the user’s Play Store licensing status. Your backend server evaluates that verdict and decides what action to take. The client never makes that decision.
According to Google’s 2024 Android ecosystem report, apps using Play Integrity features see 80% lower usage from unverified and untrusted sources on average compared to apps without it. That number is hard to ignore if you’re dealing with fraud, bots, or in-app purchase abuse.
Google Play Protect scans more than 200 billion apps daily and, in 2024, blocked 2.36 million policy-violating apps and banned over 158,000 developer accounts (Google, 2024). Play Integrity API is a core part of that protection layer.
What the API Replaced: SafetyNet vs. Play Integrity
SafetyNet launched in 2017 as a device attestation tool. It served its purpose for about 5 years before the cracks became obvious.
Key differences between the two APIs:
| Feature | SafetyNet Attestation API | Google Play Integrity API |
|---|---|---|
| Verdict format | Boolean flags (ctsProfileMatch, basicIntegrity) | Structured labels (MEETS_BASIC_INTEGRITY, MEETS_DEVICE_INTEGRITY, MEETS_STRONG_INTEGRITY) |
| App licensing check | Not available | Included (appLicensingVerdict) |
| Request modes | Single per-call model | Standard requests (cached) and Classic requests (fresh) |
| Hardware-backed signals | Optional through evaluationType | Required for MEETS_STRONG_INTEGRITY |
| Additional protections | Limited | Includes app recognition, account risk, and replay protection |
| Status | Fully shut down on January 31, 2025 | Active and recommended for all new integrations |
SafetyNet’s original design predated Android’s investment in hardware-backed key attestation. Google rebuilt from scratch rather than retrofitting it. For most developers, migrating was straightforward since the core shape of the API (signed token, server-side verification) stayed the same.
The biggest structural change: Play Integrity introduced a per-app daily quota model and split request types into Standard and Classic. SafetyNet had no equivalent split.
How Does the Google Play Integrity API Work?

The full flow runs client-to-Google-to-server. Never client-to-client. That distinction is the whole point.
Google Play Protect’s enhanced fraud protection pilots shielded 10 million devices from over 36 million risky installation attempts in 2024, covering more than 200,000 unique apps (Google, 2024). The Play Integrity API is what gives developers their own version of that protection layer inside their specific apps.
The Integrity Token Request Flow
Step-by-step process:
- Your app’s backend generates a unique value (a nonce or request hash)
- The client calls
IntegrityManager.requestIntegrityToken()with that value - Google Play generates and signs an encrypted token using platform keys
- Your app receives the token and sends it to your backend server
- Your backend sends the token to
playintegrity.googleapis.comfor decryption - Google returns a structured verdict payload
- Your server reads the verdict and decides what happens next
One thing people miss early on: the token is opaque on the client side. You cannot read it locally. Any attempt to inspect or trust the verdict client-side breaks the security model entirely.
Server-Side Decryption and Verdict Evaluation
Your backend sends the encrypted token to Google’s API. The response comes back as a JSON payload with 5 top-level fields: requestDetails, appIntegrity, deviceIntegrity, accountDetails, and environmentDetails.
Always verify requestDetails first. Confirm that the requestHash (standard requests) or nonce (classic requests) matches what your server originally sent. If it does not match, reject the request immediately, regardless of what the verdict fields say.
The verdict fields are independent of each other. An app can return PLAY_RECOGNIZED but still fail MEETS_DEVICE_INTEGRITY. Your enforcement logic needs to handle each field separately based on the sensitivity of the action being protected.
The transition to hardware-backed security signals in May 2025 reduced device signals needing Google-side evaluation by roughly 90%, and improved verdict latency by up to 80% on Android 13+ devices (Google Android Developers Blog, December 2024).
What Do the Play Integrity API Verdicts Mean?
The integrity verdict is not a single pass/fail result. It is a structured payload with 3 independent verdict fields, each covering a different layer of trust. Understanding what each one actually signals is the difference between a useful integration and one that over-blocks or under-protects.
More than 95% of app installations from major malware families exploiting sensitive runtime permissions came from internet-sideloading sources, not the Play Store (Google, 2024). The verdict fields exist specifically to detect and surface that kind of environment.
App Recognition Verdict Breakdown
The appRecognitionVerdict field lives inside appIntegrity and tells you whether the APK running on the device matches what Google Play distributed.
Possible values:
PLAY_RECOGNIZED: App certificate and package name match Google Play records exactlyUNRECOGNIZED_VERSION: Certificate or package name does not match (modified or sideloaded APK)UNAPPROVED_DISTRIBUTION_CHANNEL: App was not installed through Google PlayUNEVALUATED: App integrity was not assessed, usually because device integrity did not meet the minimum threshold
Most apps should require PLAY_RECOGNIZED for any sensitive action. Banking apps and apps handling payments should treat anything else as a hard block.
Device Integrity Verdict Breakdown
Between June 2024 and May 2025, 239 malicious Play Store apps accumulated over 42 million installs (Zscaler, 2025). Device integrity checks help identify the environments where that kind of abuse is most likely to originate.
deviceRecognitionVerdict can return multiple labels simultaneously, representing increasing levels of device trust.
| Label | What It Means | Recommended For |
|---|---|---|
MEETS_BASIC_INTEGRITY | Device passes basic integrity checks but may be rooted, unlocked, or uncertified. | Low-risk features such as content browsing, news feeds, or guest access. |
MEETS_DEVICE_INTEGRITY | Device is a certified Android device and meets stronger device integrity requirements, typically including hardware-backed verification. | Most consumer apps, user accounts, e-commerce, and standard transactions. |
MEETS_STRONG_INTEGRITY | Device is certified, hardware-backed, and has recent security updates (generally within the last 12 months on supported Android versions). | Banking, payments, digital wallets, government services, and high-security applications. |
MEETS_VIRTUAL_INTEGRITY | Request originated from an official Android emulator running Google Play services. | Development, automated testing, and QA environments only. |
If deviceRecognitionVerdict is absent entirely, the device is likely rooted, running a custom ROM, or in an environment that does not pass any integrity checks. Treat a missing verdict the same as a failed one.
Account Details Verdict Breakdown
The accountDetails field checks one thing: did this user legitimately obtain your app from Google Play?
The field contains appLicensingVerdict with 3 possible values:
LICENSED: User installed or purchased the app from Google Play on this deviceUNLICENSED: User sideloaded the app or obtained it from a different storeUNEVALUATED: Licensing could not be checked (user not signed into Google Play, or device ineligible)
A research study published by ModZoo (2024) found that 6.82% of code-modified apps were malicious, compared to 1.70% of Google Play apps. The LICENSED check is a fast signal for identifying users who bypassed the Play Store entirely.
What Are the Two Request Modes in the Play Integrity API?
Standard and Classic. Pick the wrong one for your use case and you will either annoy users with latency or miss threats that require fresh assessments.
Google currently offers a default quota of 10,000 API integrity checks per day per app (Approov, 2024). Quota increases require a manual request through Play Console and take 2 to 3 working days to approve. Choosing the right request mode directly affects how quickly you hit that ceiling.
| Factor | Standard Requests | Classic Requests |
|---|---|---|
| Latency | A few hundred milliseconds on average | A few seconds on average |
| Token freshness | Uses on-device cached information managed by Google Play | Generates a fresh integrity assessment for every request |
| Rate limit | Up to 5 warm-ups per app instance per minute | Approximately 5 token requests per minute per app instance |
| Best for | Frequent, lower-risk checks and routine app actions | Infrequent, high-value actions such as payments or account changes |
| Attack protection | Google Play automatically handles replay and token-exfiltration protections | Developer must implement secure nonce generation and validation |
Standard requests use smart on-device caching while delegating protection against replay and exfiltration attacks to Google Play. You call prepareIntegrityToken() once to warm up the provider, then request tokens on demand. Warm-up typically takes under 10 seconds.
Classic requests initiate a fresh assessment on every call. They use more battery and data, and they are slower. Google explicitly recommends using them only for your most sensitive one-off actions: login, payment initiation, password reset, account deletion.
Most developers end up using both. Standard for routine checks across the app, Classic for the 2 or 3 actions where a fresh, unambiguous verdict is worth the latency cost.
How Do You Implement the Google Play Integrity API?

The implementation splits across 2 environments: client-side token request and server-side verdict decryption. Both sides have to be right. A correct client-side setup with a broken server-side check gives you false confidence.
Prerequisites before writing a single line of code:
- Google Play Console access with the app listed (at minimum as internal test track)
- A Google Cloud project linked to the Play Console app
- Play Integrity API enabled in the Google Cloud project
- Service account credentials for server-to-server API calls
Client-Side Setup and Token Request
Add the dependency to your build.gradle:
implementation 'com.google.android.play:integrity:1.4.0'Standard request flow (Kotlin):
val integrityManager = StandardIntegrityManager.create(applicationContext)
// Warm up once
integrityManager.prepareIntegrityToken(
PrepareIntegrityTokenRequest.builder()
.setCloudProjectNumber(cloudProjectNumber)
.build()
)
// Request token on demand
val tokenRequest = StandardIntegrityTokenRequest.builder()
.setRequestHash(requestHash)
.build()
integrityManager.requestIntegrityToken(tokenRequest)
.addOnSuccessListener { response ->
val token = response.token()
// Send token to your backend
}Never read or trust the token on the client. Send it directly to your backend server. Any local inspection is meaningless since you cannot decrypt it without Google’s server-side API.
Server-Side Token Decryption
Your backend sends the token to https://playintegrity.googleapis.com/v1/{packageName}:decodeIntegrityToken using your service account credentials.
The decrypted payload structure:
{
"requestDetails": { ... },
"appIntegrity": {
"appRecognitionVerdict": "PLAY_RECOGNIZED"
},
"deviceIntegrity": {
"deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"]
},
"accountDetails": {
"appLicensingVerdict": "LICENSED"
},
"environmentDetails": { ... }
}Always validate requestDetails before reading any verdict field. Confirm the requestHash or nonce matches your original server-issued value. If it does not match, reject. Do not proceed to check the verdict fields on a mismatched request.
The API integration between your backend and Google’s decryption endpoint is where most server-side errors appear. Use the Google APIs Client Library for your language rather than raw HTTP calls. It handles authentication, retry logic, and token refresh automatically.
Google recommends not caching decrypted verdicts beyond the session duration of the action being protected. Stale verdicts open the door to proxying attacks, where a valid verdict from a trusted device gets replayed in a different environment.
What Is a Nonce and Why Does It Matter in Play Integrity Requests?
A nonce is a unique, single-use value that binds an integrity token request to a specific user action. Without a proper nonce, a valid token from a trusted device can be captured and replayed in a different environment.
This is not a theoretical risk. Replay attacks are a documented attack vector against mobile attestation APIs, and incomplete nonce implementations are one of the most common errors developers make during initial software development of Play Integrity integrations.
Nonce Requirements for Classic Requests
Hard requirements from Google’s documentation:
- Base64-encoded, URL-safe, no wrapping, no padding
- Minimum 16 bytes, maximum 500 bytes
- Generated server-side, not client-side
- Single-use per request (never reuse a nonce)
- Should not contain Personally Identifiable Information (PII) in cleartext
The nonce value is visible in cleartext to your app and to Google. Hash or encrypt any sensitive data before including it in the nonce field.
Generating nonces client-side is the mistake I’ve seen most often. The whole point is that the nonce comes from your server so your server can verify that the verdict it receives corresponds to the specific request it issued. A client-generated nonce removes that binding entirely.
Request Hash Binding for Standard Requests
Standard requests use requestHash instead of a nonce. The concept is the same but the implementation differs slightly.
Best practice for requestHash construction:
- Compute a SHA-256 digest of the critical request parameters for the action being protected
- Include the action type, relevant identifiers, and a server-issued timestamp
- Pass the hash to
setRequestHash()when building the token request - Your server verifies the hash in
requestDetails.requestHashmatches what it originally computed
Binding the hash to specific request context (transaction ID, user action type, server timestamp) means even if an attacker captures a valid token, reusing it for a different action or a different user fails the requestHash check on your server. This is the correct defense against proxying attacks for standard requests.
How Does the Play Integrity API Protect Against Specific Attack Types?
The API covers 4 distinct threat categories. Each one maps to a specific verdict field. Understanding which field catches which attack determines how you structure your enforcement logic.
Google’s own data shows that mobile malware increased roughly 67% year-over-year between mid-2024 and mid-2025, with spyware and banking trojans as the primary threat types (Zscaler, 2025). The verdict system is designed to catch the environments where these attacks originate, not the malware itself.
Modified App Installs
Threat: Attackers repackage your APK with modified code (cheats, unlocked premium features, malware injected into the binary) and distribute it through third-party sites.
Detection: appRecognitionVerdict returns UNRECOGNIZED_VERSION when the app certificate or package name does not match Google Play records.
A 2024 study found that 8.59% of code-modified apps from modded markets were malicious, versus 0.51% of code-identical apps (ModZoo, 2024). Requiring PLAY_RECOGNIZED for sensitive actions blocks this entire attack category.
Rooted and Non-Certified Devices
Rooted devices and custom ROMs remove the hardware-backed security guarantees that Android’s trust model depends on. An attacker with root access can intercept traffic, modify app memory at runtime, and manipulate the app’s local state in ways that no client-side check can detect.
Detection:
deviceRecognitionVerdictwill not containMEETS_DEVICE_INTEGRITY- May return
MEETS_BASIC_INTEGRITYonly, or return an empty verdict entirely - An absent
deviceRecognitionVerdictfield signals a likely compromised environment
From May 2025, Google required hardware-backed security signals for stronger integrity checks on Android 13+ devices (Approov, November 2025). This made it significantly harder for rooted devices to spoof the verdict.
Automated Bot Traffic
Bot traffic against Android apps typically runs on emulators or device farms. The Play Integrity API catches most of these environments, but the response depends on which type of emulator is being used.
Emulator detection behavior:
- Official Android emulators with Google Play: return
MEETS_VIRTUAL_INTEGRITY - Unofficial emulators without Google Play: return no
deviceRecognitionVerdictlabel - Device farms with genuine hardware: may pass
MEETS_DEVICE_INTEGRITY(not caught by verdict alone)
For apps where bot traffic is a major concern, Google’s optional recentDeviceActivity verdict signals when a device has made an anomalously high volume of API requests. That field requires opting in separately and is particularly useful for games and apps that see coordinated automated abuse. Pair it with server-side API rate limiting for the strongest defense against bot-driven abuse.
What Are the Quota Limits and Pricing for the Play Integrity API?
The Play Integrity API is free to use. No per-request charge from Google.
The catch is the quota. By default, each app gets 10,000 total integrity checks per day across all installs (Google Play Console documentation). High-traffic apps hit that ceiling fast, especially if they call the API on every user session rather than on targeted high-value actions.
Quota increases require submitting a request through Play Console. Google reviews these case by case, and the process takes 2 to 3 working days (Approov, 2024). There is no automatic scaling.
Default Quota Breakdown
Standard requests: Up to 5 warm-ups per app instance per minute, shared against the 10,000 daily total.
Classic requests: Capped at roughly 5 tokens per minute per app instance. Higher per-call cost against the daily budget because each call generates a fresh assessment.
SDKs using the Play Integrity API also operate under a separate 10,000-request-per-day default per SDK, not per app (Google Play SDK Console documentation). If your SDK is used across many apps, each app’s usage counts independently toward its own quota.
Exceeding quota does not return a failed verdict. It returns an error code instead, specifically TOO_MANY_REQUESTS for classic requests or the equivalent for standard requests. Your error handling needs to treat quota exhaustion differently from a genuine integrity failure, or you will accidentally block legitimate users when traffic spikes.
When to Request a Quota Increase
Request before you need it, not after. The 2-3 day review window means a traffic spike will cause outages if you have not planned ahead.
Games with competitive multiplayer, fintech apps running checks on every transaction, and any app running regression testing across large device pools all regularly need raised quotas.
Google’s recommendation: deploy the API in observation mode first (no enforcement) to measure your actual daily request volume before requesting an increase. That gives you real data to put in the quota request form rather than an estimate.
How Do You Test the Play Integrity API Integration?
Testing Play Integrity is trickier than most API integrations. You cannot get accurate verdicts from a local build or a sideloaded APK. The app must be distributed through Google Play, even if only on the internal test track.
The 3 testing environments available:
- Local testing with pre-defined fake responses (no Play distribution needed)
- Internal test track on Google Play (real verdicts, controlled distribution)
- Production monitoring in observation mode (real verdicts, no enforcement yet)
Play Integrity API Checker, a third-party tool available on the Play Store, lets developers quickly verify verdicts across device states: clean install, rooted, custom ROM, and emulator. Useful for QA teams that need to confirm verdict behavior without writing custom test code.
Local Testing with Fake Verdicts
Google provides a testing response configuration in Play Console under “Protected with Play” that lets you override the real verdict with a predefined response for testing purposes.
Test response options cover all verdict combinations:
PLAY_RECOGNIZED+MEETS_DEVICE_INTEGRITY+LICENSED(pass all)UNRECOGNIZED_VERSION+MEETS_BASIC_INTEGRITY+UNLICENSED(fail all)- Mixed combinations to test individual enforcement branches
Changes to test responses take effect immediately, including in production. Set your test responses, confirm the behavior, then clear them before full rollout. Leaving test responses active in production is a real mistake that bypasses your actual security checks.
Internal Test Track Requirements
Testing with real verdicts requires an app published to at least the Google Play internal testing track. Sideloaded builds return UNEVALUATED or UNAPPROVED_DISTRIBUTION_CHANNEL verdicts since they bypass the Play distribution pipeline.
Internal test track setup checklist:
- App signed with release keystore (not debug keystore)
- Google Cloud project linked in Play Console
- Play Integrity API enabled in the Cloud project
- Test users added to the internal testing track in Play Console
After first install from the test track, wait a few minutes before running integrity checks. There is a propagation delay between Play Store recognizing the install and the API returning accurate verdicts. Checking immediately after install commonly returns UNEVALUATED on the account details verdict even for legitimate test users.
What Are the Common Integration Errors in the Play Integrity API?
Most errors fall into 2 buckets: transient errors worth retrying, and configuration errors that will fail every time until you fix something. Treating them the same way causes unnecessary user-facing blocks and wasted quota.
| Error Code | Cause | Retryable? |
|---|---|---|
TOO_MANY_REQUESTS | Quota exceeded or request rate throttling. | ✅ Yes, retry using exponential backoff. |
NETWORK_ERROR | Device has no connectivity or cannot reach Google servers. | ✅ Yes, retry after checking network connectivity. |
GOOGLE_SERVER_UNAVAILABLE | Temporary issue on Google’s servers. | ✅ Yes, retry later; file a bug report if the issue persists. |
API_NOT_AVAILABLE | Google Play Store or Play Services is missing, disabled, or outdated. | ❌ No, prompt the user to update or install the required components. |
INTEGRITY_TOKEN_PROVIDER_INVALID | The Standard Integrity Token Provider has expired or become invalid. | ❌ No, recreate the provider by performing a new warm-up request. |
Transient Errors and Retry Logic
Google’s documented retry strategy for background operations: start with a 5-second initial delay, then double it on each failure (10s, 20s), with a maximum of 3 attempts (Android Developers documentation, 2024).
After 3 failed retries, treat the outcome as a failed integrity check. Do not keep retrying indefinitely. An overloaded device, sustained network failure, or an active attack can all produce repeated transient errors, and hammering the API burns through your daily quota.
For user-facing actions (payment confirmation, account login), use GET_INTEGRITY or GET_STRONG_INTEGRITY remediation dialogs instead of retrying silently. These are built-in Play dialogs that guide users through fixing the underlying issue, available from Integrity API library version 1.5.0 (August 2025).
Nonce and Configuration Errors
Nonce formatting mistakes cause silent failures that are tricky to debug. The token is generated but your server rejects it on verification because the nonce does not match what it expected.
The 3 most common nonce errors:
- Wrong encoding: nonce must be URL-safe base64 without padding or line wraps
- Client-generated nonce: nonce must come from your server, not from the app
- Nonce reuse: every request needs a fresh nonce; reused nonces invalidate replay protection
Configuration errors on the server side usually show up as 403 responses from playintegrity.googleapis.com. Check that the Google Cloud project number in your client code matches the linked project in Play Console, and that your service account has the correct playintegrity scope. These two mismatches together account for the majority of server-side decryption failures developers encounter during initial app deployment.
How Does the Play Integrity API Differ from SafetyNet Attestation?
SafetyNet returned 2 boolean flags. Play Integrity returns structured label strings with richer context and an entirely new verdict category that SafetyNet never had.
SafetyNet Attestation was announced deprecated in June 2022. New developer onboarding ended January 31, 2023. The API fully shut down January 31, 2025, breaking any apps that had not migrated (YinkoShield, 2025).
Verdict Format Differences
SafetyNet used boolean outputs:
basicIntegrity: true/falsectsProfileMatch: true/false- Optional
evaluationType: HARDWARE_BACKEDadded later
Play Integrity uses label strings:
MEETS_BASIC_INTEGRITY,MEETS_DEVICE_INTEGRITY,MEETS_STRONG_INTEGRITY,MEETS_VIRTUAL_INTEGRITY- A device can return multiple labels simultaneously
- An absent verdict field signals a more serious failure than a failed verdict
The mapping roughly works like this: SafetyNet’s basicIntegrity: true plus evaluationType: HARDWARE_BACKED corresponds to Play Integrity’s MEETS_STRONG_INTEGRITY. But Play Integrity now requires a security patch within the last 12 months to qualify for MEETS_STRONG_INTEGRITY on Android 13+ devices, a condition SafetyNet never enforced.
New Capabilities in Play Integrity
SafetyNet had no app licensing check. Play Integrity’s appLicensingVerdict is entirely new, letting you verify that the user actually obtained your app from Google Play rather than sideloading it or pirating it.
Additional optional verdicts SafetyNet never offered:
playProtectVerdict: checks whether Play Protect is active and found malicious appsappAccessRiskVerdict: detects apps with screen capture, overlay, or device control permissionsrecentDeviceActivity: flags devices making an unusually high volume of API requestsdeviceRecall(beta): identifies previously flagged devices even after app reinstall or device reset
For most Android development teams migrating from SafetyNet, the core migration replaces SafetyNetClient.attest() with IntegrityManager.requestIntegrityToken(), updates server-side decryption to call playintegrity.googleapis.com, and maps the old boolean logic to the new label-string logic. The structural shape of the API is similar enough that most migrations are mechanical rather than architectural.
What Server-Side Infrastructure Does the Play Integrity API Require?
The server side is not optional. It is where all meaningful security decisions happen. Getting the client integration right while skipping proper backend setup produces a false sense of security.
Required backend components:
- A Google Cloud project linked to your Play Console app
- Play Integrity API enabled in the Cloud project’s API library
- A service account with
playintegrityscope for server-to-server auth - Backend endpoint to receive tokens from the client and call Google’s decryption API
- Logic to evaluate verdict fields and return a trust decision to the app
Token Decryption Options
By default, Google manages response encryption for classic requests. Your server calls playintegrity.googleapis.com with the token, and Google handles decryption and returns the plaintext payload.
Self-managed encryption is the alternative. You download your own encryption keys from Play Console and handle decryption locally without a round-trip to Google’s servers on every verification. This option trades setup complexity for lower latency and reduced dependency on Google’s decryption endpoint uptime. Switching between the two modes requires code changes on your backend server.
Node.js, Python, Java, and Go all have Google API client libraries that handle the playintegrity scope auth and the decryption endpoint call. Using the client library is faster and less error-prone than raw HTTP calls, especially for handling token refresh and service account credentials. The back-end development work for this integration is not heavy, but the credential setup in Google Cloud is where most teams lose an afternoon the first time.
Verdict Caching Risks
Do not cache decrypted verdicts beyond the session duration of the action being protected.
Cached verdicts create proxying risk. An attacker captures a valid verdict from a trusted device and replays it in a different environment (Guardsquare, 2025). The cached verdict looks legitimate because it was legitimate, just not for this request.
Google automatically prevents integrity tokens from being decrypted many times. Attempting to repeatedly decrypt the same token results in cleared verdicts: the device recognition verdict becomes empty, and app recognition and licensing verdicts revert to UNEVALUATED (Android Developers documentation). Build your server-side logic to treat a cleared verdict on repeated decryption as a signal of possible token reuse abuse.
How Do You Handle Failed Integrity Verdicts Without Blocking Legitimate Users?
Hard-blocking on every failed verdict is the wrong default. Device attestation can fail for benign reasons: an outdated Play Services version, a brief network drop, an OEM quirk in the hardware-backed attestation implementation. Binary allow/deny decisions turn that into user-facing outages.
Attestation failures may occur due to device-specific quirks, OEM implementation differences, or bugs, resulting in false positives that block legitimate users (Zimperium, 2025). Your enforcement strategy needs to account for that reality.
Tiered Enforcement by Action Risk
Google’s own recommended approach: implement a tiered enforcement strategy where the strictness of the check matches the sensitivity of the action being protected (Android Developers Blog, October 2025).
| Action Type | Minimum Verdict Required | Response to Failure |
|---|---|---|
| Content browsing, basic app use | MEETS_BASIC_INTEGRITY | Allow access with monitoring and limited trust. |
| Account creation, standard in-app actions | MEETS_DEVICE_INTEGRITY + PLAY_RECOGNIZED | Require additional verification, CAPTCHA, or step-up authentication. |
| Payments, account changes, data export | MEETS_STRONG_INTEGRITY + LICENSED | Block the action and display a remediation message. |
For a real-world example: Spotify reported 2 million users running modded versions of its app in 2017 to bypass subscriptions (ModZoo, 2024). For that kind of abuse, requiring PLAY_RECOGNIZED and LICENSED on premium feature access directly targets the attack without touching legitimate paying users.
Observation Mode Before Enforcement
Deploy the API without enforcement first. Collect verdict data for your actual user base for at least 1 to 2 weeks before applying any blocking logic.
Why this matters:
- You will see what percentage of your existing users are already returning non-ideal verdicts
- You can correlate verdict patterns with known abuse signals from your existing fraud data
- You get a baseline to measure the impact of enforcement before rolling it out
This step is especially important for apps with older user bases. Some mobile app security teams skip observation mode, enable enforcement on day one, and then spend the next week handling support escalations from legitimate users on older or less common Android devices that return lower integrity verdicts due to hardware limitations rather than malicious intent.
Remediation Over Hard Blocks
Use Play’s built-in remediation dialogs before hard-blocking users.
From library version 1.5.0 (August 2025), 2 new dialogs are available: GET_INTEGRITY handles device integrity and app integrity issues together. GET_LICENSED targets unauthorized access and app tampering specifically.
When a user triggers a failed verdict on a sensitive action, show the appropriate dialog. It guides the user to fix the underlying issue (update Play Services, reinstall from Play Store, or resolve a device certification problem) without requiring them to contact support. After the dialog closes, re-request the verdict to confirm the issue is resolved before proceeding.
Log all verdicts server-side regardless of enforcement outcome. Verdict patterns across your user base are the signal that tells you when to tighten enforcement, when to loosen it, and when your own defect tracking should flag an anomaly in your integration rather than a genuine attack.
FAQ on Google Play Integrity API
What is the Google Play Integrity API?
The Google Play Integrity API is a security service that lets Android apps verify requests come from genuine, unmodified app installs running on certified Android devices.
It returns a signed, encrypted verdict covering app authenticity, device integrity, and Play Store licensing status. Your backend server evaluates that verdict and decides what action to take.
What replaced SafetyNet Attestation API?
The Play Integrity API replaced SafetyNet Attestation, which was fully shut down on January 31, 2025.
Play Integrity covers everything SafetyNet did, plus adds app licensing checks and richer device verdict labels that SafetyNet never offered.
Is the Play Integrity API free to use?
Yes. Google charges nothing per request.
The default quota is 10,000 checks per day per app across all installs. Quota increases are available through Play Console but require a manual review taking 2 to 3 working days.
What does the deviceIntegrity verdict mean?
It tells you whether the app is running on a genuine, certified Android device.
Possible labels include MEETS_DEVICE_INTEGRITY, MEETS_STRONG_INTEGRITY, MEETS_BASIC_INTEGRITY, and MEETS_VIRTUAL_INTEGRITY. A missing verdict field signals a likely rooted or compromised device.
What is the difference between standard and classic requests?
Standard requests use on-device cached verdicts. Latency averages a few hundred milliseconds and Google handles replay protection.
Classic requests generate a fresh assessment on every call, average a few seconds, and require you to implement nonce-based replay protection yourself.
What is a nonce in the Play Integrity API?
A nonce is a unique, single-use value generated server-side that binds an integrity token to a specific user action.
It prevents replay attacks where a valid token from a trusted device gets reused elsewhere. Never generate nonces client-side or reuse them across requests.
Can the Play Integrity API detect rooted devices?
Yes, partially. Rooted devices typically fail MEETS_DEVICE_INTEGRITY and return only MEETS_BASIC_INTEGRITY or no verdict label at all.
Since May 2025, Google requires hardware-backed security signals for stronger checks, making it significantly harder for rooted devices to spoof verdicts.
Does the Play Integrity API work on emulators?
Official Android emulators with Google Play return MEETS_VIRTUAL_INTEGRITY. Unofficial emulators without Google Play return no device recognition verdict label at all.
For bot detection, also opt in to the recentDeviceActivity verdict, which flags devices making an unusually high volume of API requests.
How do you test the Play Integrity API?
Google provides pre-defined test responses in Play Console that override real verdicts for debugging.
For real verdict testing, distribute your app through at least the Google Play internal test track. Sideloaded builds return UNEVALUATED verdicts since they bypass the Play distribution pipeline.
Should you block all users with failed integrity verdicts?
No. Hard-blocking on every failed verdict causes false positives from OEM quirks, outdated Play Services, or brief network failures.
Use a tiered enforcement strategy: require stricter verdicts only for high-risk actions like payments, and allow lower verdicts for basic content browsing with monitoring.
Conclusion
This conclusion is for an article presenting the Google Play Integrity API as the standard mechanism for Android app attestation, device certification, and Play Store licensing verification.
The verdict system covers 3 independent layers: appRecognitionVerdict, deviceIntegrity, and accountDetails. Each one targets a distinct threat, from tampered APKs to rooted devices to sideloaded installs.
Getting the integration right means choosing between standard and classic request modes deliberately, handling nonce generation server-side, and building a tiered enforcement strategy rather than hard-blocking on every failed check.
With SafetyNet fully retired, there is no fallback. Play Integrity API is the path forward for any Android development team serious about bot traffic prevention, in-app purchase fraud prevention, and protecting users from compromised environments.
- What Is the Google Play Integrity API? - August 30, 2026
- C++ Cheat Sheet - August 28, 2026
- How to Connect to a GitHub Repository From VS Code - August 26, 2026



