Integrate Play Integrity for PC into your app

Play Integrity for PC helps you check that game events and server requests are coming from a genuine instance of Google Play Games for PC on a genuine PC device. By detecting potentially risky devices and unknown emulators, your game's backend server can respond with appropriate actions to prevent cheating, unauthorized access, fraudulent traffic, and abuse.

Pre-requisites

Step 1: Decide how you'll use Play Integrity for PC in your game

Decide when you'll call Play Integrity for PC to obtain an integrity verdict about the environment. For example, you could request a verdict when the game is opened, when a player signs in, or when a player joins a multiplayer game. Then decide how you'll handle different integrity responses. For example, you could:

  • Collect the response without any enforcement actions, and analyze the data internally to understand if it's a useful signal of abuse.
  • Collect the response and implement logic on your backend server to allow devices that pass integrity verdicts to play your game normally, while challenging or denying access to traffic that's coming from suspicious environments.
  • Collect the response and implement logic on your backend to match players on devices that pass integrity checks together, while matching traffic coming from suspicious environments together.

Step 2: Request integrity tokens in your game

Warm up Play Integrity for PC

Prepare (or "warm up") Play Integrity for PC, which allows Google Play to intelligently cache partial attestation information on the device in order to decrease the latency on the critical path when you make a request for an integrity verdict. You could do this asynchronously as soon as your game opens so that you can make on-demand integrity requests when you need to.

void PrepareIntegrityToken(
  const PrepareIntegrityTokenParams & params,
  PrepareIntegrityTokenContinuation continuation
)

On success, the continuation will be called with a PrepareIntegrityTokenResultValue containing a RequestTokenData that should be used to request an integrity token. This data should be cached in-memory and reused for the duration of the application's session for calls to RequestIntegrityToken.

Only if your application determines that it is necessary to entirely re-evaluate the integrity verdict should a call to PrepareIntegrityToken be made.

Details
Parameters params: Parameters containing a Google Cloud project number.
continuation: The async callback to return the integrity token provider to.

A code snippet showing how the PrepareIntegrityToken action should be called is provided as follows:

google::play::integrity::IntegrityClient client_;

google::play::integrity::PrepareIntegrityTokenResult
IntegrityInterface::PrepareIntegrityToken(int64_t cloud_project_number) {
  google::play::integrity::PrepareIntegrityTokenParams params;
  params.cloud_project_number = cloud_project_number;

  auto promise = std::make_shared<
      std::promise<google::play::integrity::PrepareIntegrityTokenResult>>();
  client_.PrepareIntegrityToken(
      params,
      [promise](
          google::play::integrity::PrepareIntegrityTokenResult result) {
        promise->set_value(std::move(result));
      });

  return promise->get_future().get();
}

Request your integrity token

Integrity tokens are a mechanism for your game to verify the device is not tampered with. Whenever your game makes a server request that you want to check is genuine, you can request an integrity token and then send it to your game's backend server for decryption and verification.

When you're checking a user action in your app with the Play Integrity API for PC, you can use the RequestIntegrityTokenParams::request_hash field to mitigate against tampering attacks. For example, you may want to report the player's score to your game's backend server, and your server wants to verify this score has not been tampered with by a proxy server. Play Integrity for PC can return the value you set in this field, inside the signed integrity response. Without the requestHash, the integrity token will be bound only to the device, but not to the specific request, which opens up the possibility of attack.

void RequestIntegrityToken(
  const RequestIntegrityTokenParams & params,
  RequestIntegrityTokenContinuation continuation
)

To mitigate the possibility of an attack, when you request an integrity verdict:

  • Compute a digest of all relevant request parameters (e.g. SHA256 of a stable request serialization) from the user action or server request that is happening.
  • Set the RequestIntegrityTokenParams::request_hash field to the digest.
Details
Parameters params: Parameters containing the prepared RequestTokenData and integrity check request hash.
continuation: The async callback to return the data to.

A code snippet showing how the RequestIntegrityToken action can be called is provided as follows:

absl::StatusOr<google::play::integrity::RequestIntegrityTokenResult>
IntegrityInterface::RequestIntegrityToken(
    const google::play::integrity::PrepareIntegrityTokenResult&
        prepare_integrity_token_result,
    const std::string& request_hash) {
  // Check if the prepare_integrity_token_result is OK
  if (!prepare_integrity_token_result.ok()) {
    return absl::FailedPreconditionError(
        absl::StrCat("PrepareIntegrityTokenResult is not OK. Error code: ",
                     prepare_integrity_token_result.error_code));
  }

  google::play::integrity::RequestIntegrityTokenParams params{
      .request_token_data =
          prepare_integrity_token_result.request_token_data,
      .request_hash = request_hash};

  auto promise = std::make_shared<std::promise<
      google::play::integrity::RequestIntegrityTokenResult>>();
  client_.RequestIntegrityToken(
      params,
      [promise](google::play::integrity::RequestIntegrityTokenResult result) {
        promise->set_value(std::move(result));
      });

  return promise->get_future().get();
}

Step 3: Decrypt and verify integrity tokens on your game's backend server next

Decrypt an integrity token

After you request an integrity verdict, the Play Integrity API provides an encrypted response token. To obtain the device integrity verdicts, you must decrypt the integrity token on Google's servers:

  1. Create a service account within the Google Cloud project that's linked to your app.
  2. On your app's server, fetch the access token from your service account credentials using the playintegrity scope, and make the following request:

    playintegrity.googleapis.com/v1/<var>PACKAGE_NAME</var>:decodePcIntegrityToken -d \
     '{ "integrity_token": "<var>INTEGRITY_TOKEN</var>" }'
    
  3. Read the JSON response.

The resulting payload is a plain-text token that contains integrity verdicts and details alongside developer-provided information. A decrypted integrity token looks as follows:

{
  "requestDetails": {
    "requestPackageName": "com.your.package.name",
    "requestTime": "2025-08-29T13:10:37.285Z",
    "requestHash": "your_request_hash_string"
  },
  "deviceIntegrity": {
    "deviceRecognitionVerdict": [
      "MEETS_PC_INTEGRITY"
    ]
  },
}

Verify the integrity token

The requestDetails field of the decoded integrity token contains information about the request, including developer-provided information in the requestHash.

The requestHash and packageName fields should match those of the original request. Therefore, verify the requestDetails part of the JSON payload by making sure that the requestPackageName and requestHash match what was sent in the original request, as shown in the following code snippet:

const auto& request_details = json_payload["requestDetails"];

if (request_details.value("requestPackageName", "") != <YOUR_PACKAGE_NAME>) {
  // Don't trust the verdicts.
}

// Check for the existence of the request_hash.
// If you set a request hash in the request and it's not present, you shouldn't
// trust the verdicts.
if (!request_details.contains("requestHash")) {
    // Don't trust the verdicts.
}


// The requestHash from request_details needs to match the request hash your
// app provided.
if (request_details.value("requestHash", "") != <PROVIDED_REQUEST_HASH>) {
    // Don't trust the verdicts.
}

// You can read the rest of payload's fields.

Step 4: Decide what action to take based on the integrity verdict

The deviceIntegrity field can contain a single value, deviceRecognitionVerdict. You can use this value to determine whether or not your game is running on a PC that passes Play integrity checks (which is a MEETS_PC_INTEGRITY response). Your game's backend server can collect this information and use it to determine what action your game should take, such as allowing a game event to proceed or denying access to risky traffic.

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_PC_INTEGRITY"]
}

deviceRecognitionVerdict can have the following values:

MEETS_PC_INTEGRITY
The game is running on a genuine PC environment, where no on-device tampering was detected.
Empty (a blank value)
The game is running on a device that has signs of attack (such as API hooking) or system compromise (such as device running a tampered Google Desktop Services version), or the app is not running on a physical device (such as an emulator that does not pass Google Play integrity checks).

Step 5: Handle error codes

If your game makes a Play Integrity for PC request and the call fails, your game receives an error code. These errors can happen for various reasons, such as environmental issues like a poor network connection, problems with your API integration, or malicious activity and active attacks.

Retryable error codes

The cause of these errors is sometimes due to transient conditions, and thus you should retry the call with an exponential back-off strategy.

IntegrityError Error Description Error Code
kNetworkError Network connectivity issue on device. 5
kTooManyRequests Too many requests made from the device. 6
kClientTransientError A transient issue with the client. 7

See here for more recommendations on retry strategies.

Non-Retryable error codes

Automatic retries are unlikely to help in these cases. However, a manual retry may help if the user addresses the condition that caused the issue.

IntegrityError Error Description Error Code Recommended Action
kError Fatal error during SDK action. 1 Verify your API implementation before retrying.
kCloudProjectNumberIsInvalid The Cloud Project number is invalid. 2 Verify that your cloud project number is configured on Google Cloud Console correctly and the requests are made with the correct cloud project number.
kRequestHashTooLong The request hash is too long. 3 The generated request hashes are too long. Make sure they are less than 500 characters.
kNoValidPreparedTokenFound There is no prepared token before making the token request. 4 Call the [PrepareIntegrityToken][prepare-token] action before making the [RequestIntegrityToken][request-integrity-token] call.
kSdkRuntimeUpdateRequired An update is needed for the Play for Native SDK. 8 Make sure that the Google Play services client on the device is up to date and you are using the latest version of the Play for Native PC SDK.