SafetyNet Attestation API

The SafetyNet Attestation API helps you assess the security and compatibility of the Android environments in which your apps run. You can use this API to analyze devices that have installed your app.

Note: This API contains both client-side and server-side components. For details about each components, see Architecture.

SafetyNet examines software and hardware information on the device where your app is installed to create a profile of that device. The service then attempts to find this same profile within a list of device models that have passed Android compatibility testing. The API also uses this software and hardware information to help you assess the basic integrity of the device, as well as the APK information of the calling app. This attestation helps you to determine whether or not the particular device has been tampered with or otherwise modified. It also provides information about the app that is using this API so that you can assess whether the calling app is legitimate.

The goal of this API is to provide you with confidence about the integrity of a device running your app. You can then obtain additional signals using the standard Android APIs. You should use the SafetyNet Attestation API as an additional in-depth defense signal as part of an anti-abuse system, not as the sole anti-abuse signal for your app.

Note: This API isn't designed for DRM-like checks, and the API doesn't provide signals for particular app use cases, such as GPS emulation status or screen lock status.

This document shows you how to use the SafetyNet APIs to request a compatibility check and how to verify the response that the API provides. You might also find it helpful to learn about the 10 things you might be doing wrong when using the SafetyNet Attestation API.

Note: To see an Android app that contains a complete implementation of the SafetyNet Attestation API, see the SafetyNet API sample on GitHub. You can use this sample to learn more about how to verify devices' integrity from your app.

Additional terms of service

By accessing or using the SafetyNet APIs, you agree to the Google APIs Terms of Service, and to these Additional Terms. Please read and understand all applicable terms and policies before accessing the APIs.

SafetyNet Terms of Service

As with any data collected in large volume from in-the-field observation, there is a chance of both false positives and false negatives. We are presenting the data to the best of our understanding. We extensively test our detection mechanisms to ensure accuracy, and we are committed to improving those methods over time to ensure they continue to remain accurate.

You agree to comply with all applicable law, regulation, and third party rights (including without limitation laws regarding the import or export of data or software, privacy, and local laws). You will not use the APIs to encourage or promote illegal activity or violation of third party rights. You will not violate any other terms of service with Google (or its affiliates).

You acknowledge and understand that the SafetyNet API works by collecting hardware and software information, such as device and application data and the results of integrity checks, and sending that data to Google for analysis. Pursuant to Section 3(d) of the Google APIs Terms of Service, you agree that if you use the APIs that it is your responsibility to provide any necessary notices or consents for the collection and sharing of this data with Google.

Obtain an API key

In order to call the methods within the SafetyNet Attestation API, you must pass in an API key. To create this key, complete the following steps:

  1. Go to the Library page in the Google APIs Console.
  2. Search for the Android Device Verification API. When you've found the API, click on it. The Android Device Verification API dashboard screen appears.
  3. If the API isn't already enabled, click Enable.
  4. If the Create credentials button appears, click on it to generate an API key. Otherwise, click the All API credentials drop-down list and select the API key that is associated with the project for which the Android Device Verification API is enabled.
  5. In the sidebar on the left, click Credentials. Copy the API key that appears.

    Use this API key whenever you call the attest() method of the SafetyNetClient class.

After reviewing all the relevant documentation for this API—including best practices—estimate the number of calls your app might make to the API. If you need to make more than 10,000 requests per day across all API keys in your project, fill out this quota request form.

Check the Google Play services version

Before you use the SafetyNet Attestation API, you must ensure that the correct version of Google Play services is installed on the user's device. If an incorrect version is installed, your app might stop responding after calling the API. If your app detects that an incorrect version is installed, you should ask the user to update the Google Play services app on their device.

To check whether the installed version of Google Play services is compatible with the version of the Android SDK that you're using, call the isGooglePlayServicesAvailable() method, as shown in the following code snippet:


if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
        == ConnectionResult.SUCCESS) {
  // The SafetyNet Attestation API is available.


if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
        == ConnectionResult.SUCCESS) {
  // The SafetyNet Attestation API is available.

Request a compatibility check

A SafetyNet compatibility check allows your app to check if the device running your app has passed Android compatibility testing and whether your app has been modified by an unknown source. The compatibility check creates a device profile by gathering information about the device's hardware and software characteristics, including the platform build.

Ideally, you should perform this check to protect all critical actions—including logins, purchase events, and acquisition of new in-app products—in your app. Attestation calls, however, lead to latency, mobile data usage, and battery usage, so it makes sense to find a balance between security and usability. For example, you might choose to request a compatibility check upon login and run re-checks at most once every 30 minutes. You can also let your server decide when your app should request a compatibility check to make it harder for adversaries to predict the timing of your check.

To perform a check using the API, you need to obtain an API key that is valid for the Android Device Attestation API in the Google APIs Console. Your app can then perform the following steps to use the service:

  1. Obtain a single use token
  2. Send the compatibility check request
  3. Read the response
  4. Validate the response

For more information about Android compatibility testing, see Android Compatibility and the Compatibility Testing Suite (CTS).

Because SafetyNet checks use network resources, the speed of responses to requests can vary, depending on a device's network connection status. The code described in this section should be executed outside of your app's main execution thread to avoid pauses and unresponsiveness in your app's user interface. For more information about using separate execution threads, see Sending Operations to Multiple Threads.

Obtain a single use token

The SafetyNet API uses security techniques to help you verify the integrity of the communications between your app and the service. When you request a compatibility check, you must provide the API key that you generated when Obtaining an API Key. You must also provide a single use token in the form of a number used once, or nonce, as part of your request. A nonce is a random token generated in a cryptographically secure manner.

You can obtain a nonce by generating one within your app each time you make a compatibility check request. As a more secure option, you can obtain a nonce from your own server, using a secure connection.

A nonce used with a SafetyNet request should be at least 16 bytes in length. You should introduce variability in your nonce, and you should derive part of the nonce from the data you're sending to the server. For example, you could concatenate the hash of the username with the request timestamp to form the nonce.

Important: Include as many pieces of data in the nonce as possible. In doing so, you make it more difficult for attackers to carry out replay attacks. For example, deriving the nonce from the username limits replay attacks to the same account. However, deriving the nonce from all the details of a purchase event limits the attestation result to that purchase event only.

After you make a compatibility check request, the response from the SafetyNet service includes your nonce, so you can verify it against the one you sent. As the name indicates, you should only use a nonce value once, for a single compatibility check request. Use a different nonce for any subsequent compatibility check requests.

For additional guidelines on using cryptography functions, see Security Tips.

Send the compatibility check request

After you have established a connection to Google Play services and have created a nonce, you're ready to make a compatibility check request. Because the response to your request may not be immediate, you can set up a callback listener to handle the response from the service, as shown in the following code example:


// The nonce should be at least 16 bytes in length.
// You must generate the value of API_KEY in the Google APIs dashboard.
SafetyNet.getClient(this).attest(nonce, API_KEY)
        .addOnSuccessListener(this) { response ->
            // Indicates communication with the service was successful.
            // Use response.jwsResult to get the result data.
        .addOnFailureListener(this) { e: Exception ->
            // An error occurred while communicating with the service.
            if (e is ApiException) {
                // An error with the Google Play services API contains some
                // additional details.
                // You can retrieve the status code using the
                // e.statusCode property.
            } else {
                // A different, unknown type of error occurred.
                Log.d(TAG, "Error: ${e.message}")



// The nonce should be at least 16 bytes in length.
// You must generate the value of API_KEY in the Google APIs dashboard.
SafetyNet.getClient(this).attest(nonce, API_KEY)
        new OnSuccessListener<SafetyNetApi.AttestationResponse>() {
            public void onSuccess(SafetyNetApi.AttestationResponse response) {
                // Indicates communication with the service was successful.
                // Use response.getJwsResult() to get the result data.
    .addOnFailureListener(this, new OnFailureListener() {
        public void onFailure(@NonNull Exception e) {
            // An error occurred while communicating with the service.
            if (e instanceof ApiException) {
                // An error with the Google Play services API contains some
                // additional details.
                ApiException apiException = (ApiException) e;
                // You can retrieve the status code using the
                // apiException.getStatusCode() method.
            } else {
                // A different, unknown type of error occurred.
                Log.d(TAG, "Error: " + e.getMessage());

The onSuccess() method indicates that communication with the service was successful, but it doesn't indicate if the device has passed the compatibility check. The next section discusses how to read the compatibility check result and verify its integrity.

Note: The preceding code snippet uses a non-blocking version of the attest() method. If you're making a blocking call instead, always set a response timeout. That way, your app remains responsive, even if a slow network connection causes a delayed response from the SafetyNet Attestation API.

Read the compatibility check response

When your app communicates with SafetyNet, the service provides a response containing the result of the compatibility check and includes additional information to help you verify the integrity of the message. The result is provided as a SafetyNetApi.AttestationResponse object. Use the getJwsResult() method of this object to obtain the data of the request. The response is formatted as a JSON Web Signature (JWS). The following JWS excerpt shows the format of the payload data:

  "nonce": "R2Rra24fVm5xa2Mg",
  "timestampMs": 9860437986543,
  "apkPackageName": "",
  "apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
                                  certificate used to sign requesting app"],
  "apkDigestSha256": ["base64 encoded, SHA-256 hash of
                      the APK installed on a user's device"],
  "ctsProfileMatch": true,
  "basicIntegrity": true,

The contents of the JWS message depend on the scenario:

  • If the value of ctsProfileMatch is true, then the profile of the device running your app matches the profile of a device that has passed Android compatibility testing.

  • If the value of basicIntegrity is true, then the device running your app likely wasn't tampered with, but the device hasn't necessarily passed Android compatibility testing.

    Note: The basicIntegrity parameter is a weaker check than ctsProfileMatch. If you don't need the device running your app to pass CTS, use the basicIntegrity parameter, as it allows your app to run on a wider variety of devices. If your app requires stronger device status guarantees, however, you should use only the result from ctsProfileMatch. For more information, see the Possible attestation results section.

  • The apkPackageName, apkCertificateDigestSha256, and apkDigestSha256 parameters provide information about the APK that you can use to verify the identity of the calling app. These parameters are absent if the API cannot reliably determine the APK information.

    Caution: You should trust this APK information only if the value of ctsProfileMatch is true.

    Note: In most cases, you should verify your app's integrity using the apkCertificateDigestSha256 parameter. This value typically corresponds to the hash of the certificate(s) returned using the signatures field.

    We don't recommend using the apkDigestSha256 field because the APK hash's value isn't stable. This value changes with every release and can even change between releases because of other factors, such as an app distribution channel adding metadata.

Possible attestation results

The JWS message contains two parameters that indicate the attestation check result: ctsProfileMatch and basicIntegrity. The status of the device running your app could affect the value for each parameter, as shown in Table 1:

Table 1. Examples of how device status could affect the values of basicIntegrity and ctsProfileMatch

Device Status Value of "ctsProfileMatch" Value of "basicIntegrity"
Certified, genuine device that passes CTS true true
Certified device with unlocked bootloader false true
Genuine but uncertified device, such as when the manufacturer doesn't apply for certification false true
Device with custom ROM (not rooted) false true
Emulator false false
No device (protocol emulator script) false false
Signs of system integrity compromise, such as rooting false false
Signs of other active attacks, such as API hooking false false

Error cases

The JWS message can also show several types of error conditions:

  • A null result indicates that the call to the service didn't complete successfully.
  • An error parameter indicates that an issue occurred, such as a network error or an error that an attacker feigned. Most errors are transient and should be absent if you retry the call to the service. You may want to retry a few more times with increasing delays between each retry.

    Important: If you trigger more than 5 calls per minute, you exceed the API's fixed rate limit, which causes the remaining requests during that minute to return an error.

    If an error occurs, the result cannot represent a passed test, as an attacker might intentionally trigger such an error.

Advice for passing future checks

When present, the advice parameter provides information to help explain why the SafetyNet Attestation API set either ctsProfileMatch or basicIntegrity to false in a particular result. The parameter's value contains a list of strings, such as the ones in the following example:


In your app, you can translate the values in the advice parameter into user-friendly messages to help the user pass future attestation checks, as shown in the following list:

The user should lock their device's bootloader.
The user should restore their device to a clean factory ROM.

Verify the compatibility check response

You should take steps to make sure that the compatibility check response actually came from the SafetyNet service and includes data that matches your request data.

Caution: You should send the entire JWS response to your own server, using a secure connection, for verification. We don't recommend that you perform the verification directly in your app because, in that case, there is no guarantee that the verification logic itself hasn't been modified.

Follow these steps to verify the origin of the JWS message:

  1. Extract the SSL certificate chain from the JWS message.
  2. Validate the SSL certificate chain and use SSL hostname matching to verify that the leaf certificate was issued to the hostname
  3. Use the certificate to verify the signature of the JWS message.
  4. Check the data of the JWS message to make sure it matches the data within your original request. In particular, make sure that the nonces, timestamps, package names, and the APK certificate SHA-256 hashes match.

Validate the response with Google APIs

You should verify the JWS statement using the standard crytographic solutions found in the SafetyNet samples on GitHub. For cases where this is inconvenient, such as during early testing, Google provides an Android Device Verification API for verifying the JWS statement.

Note: The API method to verify response messages has a fixed rate limit of 10,000 requests per day, per project. You should use the verify() method only for testing during the initial development stage. You shouldn't call the method in a production scenario.

Important: This use of the verify() method to verify the response message only validates that the JWS message was signed by SafetyNet. It doesn't verify that the payload of the verdict matches your expectations.

After enabling this API for your project, you can call the verification service from your app or server. You need the contents of the JWS message from the SafetyNet API and your API key to call the verification API and get a result.

To use the Android Device Verification API, complete the following steps:

  1. Create a JSON message containing the entire contents of the JWS message. Use the following format:
    { "signedAttestation": "<output of getJwsResult()>" }
  2. Use an HTTP POST request to send the message with a Content-Type of "application/json" to the following URL:
  3. The service validates the integrity of the message. If the message is valid, it returns a JSON message with the following contents:
    { "isValidSignature": true }


The overall SafetyNet Attestation protocol, which appears in Figure 1, involves the following steps:

  1. Your app makes a call to the SafetyNet Attestation API.
  2. The API requests a signed response using its backend.
  3. The backend sends the response to Google Play services.
  4. The signed response is returned to your app.
  5. Your app should forward the signed response to a server that you trust.
  6. The server verifies the response and sends the result of the verification process back to your app.
Figure 1. SafetyNet Attestation API protocol

After completing these steps, if the result indicates that the device has passed your app's risk-model evaluation, your app can resume its services.


For additional guidance on working with the SafetyNet APIs, view the samples that are available on GitHub.


You can help us make the SafetyNet Attestation API even better by providing feedback on it.


If you would like to receive updates about the SafetyNet Attestation API, you can join the SafetyNet API clients mailing list.

Learn more

To learn more about the SafetyNet Attestation API, navigate to the following links: