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
- Complete the SDK setup.
- Review the Integrity API security considerations.
- Read and understand the Integrity API terms of service and data handling information.
- In your Google Cloud Console, create a Cloud project or choose an existing Cloud project that you want to use with Play Integrity for PC. Navigate to APIs & services and enable Google Play Integrity API.
- If you expect to make over 10K Play Integrity for PC requests per day, you should request to increase your daily maximum.
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:
- Create a service account within the Google Cloud project that's linked to your app.
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>" }'
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. |