Your ranked competitive game is bleeding players. Leaderboards are polluted with impossible scores, in-game currency is being duplicated, and legitimate players are quitting because the match feels broken. The culprit is almost always a modded APK or a memory editor running alongside your game client — and a single attestation call won’t stop it.

Key Takeaways

  • Play Integrity API verdicts must be verified server-side, never on the client
  • A passed integrity check does not guarantee a clean runtime — layer it with on-device detection
  • Use standard requests for session events; reserve classic requests for IAP and ranked match entry
  • Map each verdict combination to a specific enforcement action, not a binary block/allow
  • False positives on rooted or custom ROM devices require a shadow-restriction model, not a hard ban

Why Play Integrity API Is Not Enough on Its Own

The Play Integrity API is Google’s replacement for the deprecated SafetyNet Attestation API. It gives your game server a signed verdict about the device, the app, and the account making a request. That’s genuinely useful. But attestation happens at a point in time, and memory editors like GameGuardian can attach to your process after that check completes.

Think of the API as a checkpoint at the entrance, not a continuous guard inside the venue. A player on a clean device can pass attestation, then activate a speed hack mid-session. Your server needs to know about both the device state at session start and what’s happening inside the process at runtime.

This guide builds the full stack: API attestation, runtime tamper detection, and server-side enforcement logic. Each layer catches a different cheat vector.

How Play Integrity API Works and What It Replaced

The Play Integrity API is a device and app attestation service that lets your game server verify three things: whether the APK is unmodified and recognized by Google Play, whether the device passes Android security requirements, and whether the Google account has a history consistent with legitimate use. Unlike SafetyNet, which bundled device attestation and APK verification into a single opaque response, Play Integrity separates these into three distinct verdict categories you can act on independently.

The Three Verdict Categories

  • APP_INTEGRITY: Whether your APK is the version distributed through Google Play. Values include PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, and UNEVALUATED.
  • DEVICE_INTEGRITY: The device’s security posture. Values range from MEETS_STRONG_INTEGRITY (hardware-backed keystore, passes Play Protect) down to NO_INTEGRITY (emulator or heavily modified device).
  • ACCOUNT_DETAILS: Whether the account has a Play license for your app. The LICENSE_VERIFIED value confirms a legitimate purchase or install from the Play Store.

Standard vs. Classic Integrity Requests

Standard requests use a cached verdict and return in under 10 milliseconds on most devices. Classic requests generate a fresh verdict directly from Google’s servers and take 10 to 15 seconds — but they carry a higher quota cost and add visible latency. Use standard requests for session start and in-game action triggers. Reserve classic requests for in-app purchase flows and ranked match entry, where a fresh verdict justifies the tradeoff.

Requesting an Integrity Token from Your Game Client

Before you call IntegrityManager.requestIntegrityToken(), your game server must issue a nonce: a short-lived, session-specific string that ties the integrity token to a specific action. Without a server-issued nonce, a cheater can replay a valid token from a clean device against a compromised one.

Nonce Generation and Token Request

Your server generates a nonce by combining a session ID, a timestamp, and a random salt, then hashing the result. The client receives this nonce and passes it into the integrity request. Here’s the pattern in Kotlin using coroutines to keep the game loop unblocked:


// Fetch nonce from your game server first
val nonce = gameServer.fetchNonce(sessionId)

val integrityManager = IntegrityManagerFactory.create(context)
val request = IntegrityTokenRequest.builder()
    .setNonce(nonce)
    .build()

lifecycleScope.launch(Dispatchers.IO) {
    try {
        val response = integrityManager
            .requestIntegrityToken(request)
            .await()
        gameServer.verifyToken(response.token())
    } catch (e: IntegrityServiceException) {
        // Handle quota exceeded or service unavailable
        handleIntegrityFailure(e.errorCode)
    }
}
    

Don’t call this on every frame or every minor game event. Quota limits apply, and hitting them silently degrades your enforcement coverage. Throttle requests to meaningful session boundaries: match start, IAP trigger, leaderboard submission, and reward claim.

Verifying Verdicts Server-Side and Mapping Them to Enforcement Actions

The integrity token is an encrypted JWT. Your client cannot read it — and it shouldn’t try. Decryption happens server-side using the Google Play Developer API, with keys you download from the Play Console. Exposing decryption logic on the client defeats the entire model.

Play Integrity API Verdict Values and Enforcement Actions

  • MEETS_STRONG_INTEGRITY + PLAY_RECOGNIZED + LICENSE_VERIFIED: Allow. Standard play with full access to ranked modes and IAP.
  • MEETS_DEVICE_INTEGRITY + PLAY_RECOGNIZED: Allow with logging. Device passes basic checks; monitor session for behavioral anomalies.
  • MEETS_BASIC_INTEGRITY + PLAY_RECOGNIZED: Soft-block. Restrict ranked mode access; allow casual play; flag account for review.
  • UNRECOGNIZED_VERSION (any device integrity): Hard-block on IAP and leaderboard submission. The APK is modified or sideloaded.
  • NO_INTEGRITY: Hard-block on all competitive features. Likely an emulator or device with spoofed fingerprints.

Because the token is verified server-side, the enforcement decision never touches the client. A cheater who intercepts the network response can’t modify the verdict — your server holds the decryption keys.

Runtime Tamper Detection: Covering What the API Cannot See

A player on a stock Pixel with a legitimate Play Store install can pass every integrity check and still run GameGuardian in the background. The attestation happened before the cheat tool attached. Runtime detection fills this gap.

APK Signature Verification at Runtime

Call PackageManager.getPackageInfo() with the GET_SIGNING_CERTIFICATES flag and compare the returned certificate hash against your expected signing key hash. A repackaged APK will carry a different certificate even if it passed attestation on a clean device before being distributed to others.

Hook Framework Detection

Frida and Xposed Framework are the two most common hooking tools used to modify game behavior at runtime. Detect Frida by scanning /proc/self/maps for known Frida agent library names (frida-agent, re.frida.server). Detect Xposed by checking for the presence of XposedBridge in the loaded class list via reflection. Neither check is foolproof against advanced evasion, but they raise the cost of cheating significantly.

Debugger and Root Detection

Check android.os.Debug.isDebuggerConnected() in production builds. A debugger attached to a live session is a strong signal of active tampering. For root detection, check for su binary presence in common paths and test whether RootBeer or a native equivalent returns positive. Don’t hard-block on root alone — rooted devices are a false positive risk for legitimate players.

Handling False Positives Without Punishing Legitimate Players

GrapheneOS users, developers running custom ROMs, and players on older devices with non-standard configurations will fail integrity checks they shouldn’t fail. Hard-blocking everyone below MEETS_STRONG_INTEGRITY will hurt your legitimate player base.

The better model is shadow restriction: allow the player to continue in casual modes, silently exclude them from ranked queues and leaderboard submission, and flag the account for manual review. You preserve the player experience while limiting competitive impact.

Build a feedback loop. Log every flagged session with the verdict combination, device model, and gameplay data. After two to four weeks, correlate flagged accounts with actual cheating behavior. Players who were flagged but showed no anomalous gameplay patterns are false positives — adjust your thresholds accordingly.

Known Bypass Vectors and How Layered Defense Reduces Their Impact

Play Integrity API can be bypassed. On devices with unlocked bootloaders, tools like Magisk with the DenyList configuration can spoof device fingerprints and pass MEETS_DEVICE_INTEGRITY checks. This is a documented and widely known attack vector, not a theoretical risk.

What does your server actually see when a sophisticated cheater bypasses attestation? A verdict that looks legitimate. This is exactly why server-side behavioral analysis matters. Speed hacks produce movement events that exceed physical map traversal limits. Resource duplication exploits create economy deltas that don’t match server-authoritative state. Impossible event sequences — collecting a reward before the trigger condition is met — are detectable without any client-side signal at all.

The practical defense model combines three layers: API attestation catches modded APKs and compromised devices at session start; runtime checks detect hook frameworks and memory editors mid-session; server-side anomaly detection catches cheaters who passed both. No single layer is a silver bullet, and you shouldn’t treat any of them as one.

Deciding Where to Enforce Based on Your Game’s Risk Profile

Not every game mode carries the same risk. A single-player story mode with no leaderboard or economy impact doesn’t need classic integrity requests at session start. A ranked competitive mode with real-money IAP does.

Apply this decision model:

  • Ranked competitive modes: Classic integrity request at match entry; hard-block on NO_INTEGRITY and UNRECOGNIZED_VERSION
  • In-app purchase flows: Classic request before purchase confirmation; block on any APP_INTEGRITY failure
  • Leaderboard and reward submissions: Standard request with server-side behavioral validation; soft-block on MEETS_BASIC_INTEGRITY
  • Casual or single-player sessions: Standard request with logging only; no enforcement action

The next architectural step is integrating these signals into a risk scoring system rather than evaluating each check in isolation. A player with MEETS_DEVICE_INTEGRITY, a detected Frida signature, and three speed-hack anomalies in the same session carries a very different risk profile than any single signal suggests alone.

Frequently Asked Questions

What is the difference between Play Integrity API and SafetyNet?

SafetyNet Attestation was Google’s previous device verification API, now deprecated. Play Integrity API replaces it with three separate verdict categories — app integrity, device integrity, and account details — giving developers more granular enforcement options. The migration path involves replacing the SafetyNet client dependency with the Play Integrity API library and updating your server-side decryption logic to handle the new JWT verdict format.

When should I call the Play Integrity API during a game session?

Call it at session-meaningful boundaries: match start, in-app purchase initiation, leaderboard submission, and reward claim. Don’t call it on frequent game events like player movement or score updates — quota limits apply, and unnecessary calls add latency without improving coverage.

Can a cheater bypass Play Integrity API?

Yes. Devices with unlocked bootloaders running tools like Magisk can spoof device fingerprints and pass device integrity checks. This is why runtime tamper detection and server-side behavioral analysis are required complements to API attestation, not optional additions.

What should I do when I get a MEETS_BASIC_INTEGRITY verdict?

Don’t hard-block. Apply a soft restriction: allow casual play, exclude the account from ranked modes and leaderboard submission, and flag for review. Log the session and correlate with gameplay anomaly data before taking permanent action. This approach avoids punishing legitimate players on non-standard devices.

How do I protect in-app purchases specifically?

Gate IAP flows with a classic integrity request immediately before the purchase confirmation step. Verify that APP_INTEGRITY returns PLAY_RECOGNIZED and ACCOUNT_DETAILS returns LICENSE_VERIFIED. Block the purchase server-side if either check fails — never rely on client-side validation for transaction authorization.

Download the free Play Integrity API enforcement threshold decision matrix to map every verdict combination to the right game response for your risk level. Explore more Android game security guides on agiledroid.com to build a complete anti-cheat strategy, and subscribe to the agiledroid.com newsletter for updates when Play Integrity API verdicts or Google Play policies change.