---
title: "Epsilon Integrity"
canonical_url: "https://apidocs.sportradar.com/resources/epsilon-sdk/docs/modules/integrity"
markdown_url: "https://apidocs.sportradar.com/resources/epsilon-sdk/docs/modules/integrity.md"
last_updated: "2026-10-05T08:22:41Z"
---

# Epsilon Integrity

The `epsilon-integrity-check` module requests a device attestation token so your backend can verify that the app is running on a legitimate device. Android uses the Play Integrity API. iOS uses App Attest.

> **Tip**
>
> The module returns the token. Your backend verifies it.

## Features

- **Single API**: One `DeviceIntegrityCheck` entry point on every target.
- **Android Play Integrity**: Requests a Play Integrity token and retries transient Play errors with the same nonce.
- **iOS App Attest**: Creates a hardware-backed key, stores its identifier in the Keychain, attests it, and later produces assertions.
- **Structured result**: Success and failure are both represented by `IntegrityCheckResult`.

## Supported Platforms

- Android
- iOS

> **Note**
>
> JVM and JavaScript call `nonceProvider` and then return an empty `IntegrityCheckResult`. Attestation runs on Android and iOS.

## Key Components

### DeviceIntegrityCheck

Requests an attestation token for a nonce supplied by your backend.

### IntegrityCheckResult

Holds either the attestation `token` or an `error` message.

### DeviceIntegrityCheck

Construct it with a `CommonContext` from `epsilon-core`. On Android that type is `android.content.Context`. On iOS, JVM, and JavaScript, pass the stub `Context` object from `ag.sportradar.mobile.epsilon.context`.

`getIntegrityToken` calls `nonceProvider` once and embeds that nonce in the attestation. Fetch the nonce from your backend inside the lambda. Coroutine cancellation is propagated to the caller. Any other failure from the nonce provider, or from the platform attestation call, is returned as `IntegrityCheckResult.error`.

**Request example**

```kotlin
val integrityCheck = DeviceIntegrityCheck(commonContext)

val result = integrityCheck.getIntegrityToken {
    backend.fetchNonce()
}

val token = result.token
if (token != null) {
    backend.verifyIntegrityToken(token)
} else {
    val message = result.error
}
```

> **Note**
>
> On iOS the class is exported as `EpsilonDeviceIntegrityCheck`.

### IntegrityCheckResult

| Property | Meaning                                                                  |
| :------- | :----------------------------------------------------------------------- |
| `token`  | Attestation token to send to your backend. `null` when the check failed. |
| `error`  | Human-readable failure message. `null` when the check succeeded.         |

On Android and iOS, a finished check sets one of these properties. On JVM and JavaScript, both stay `null` after a successful nonce fetch.

> **Note**
>
> On iOS the type is exported as `EpsilonIntegrityCheckResult`.

## Platform behavior

### Android

The Android implementation calls the Play Integrity API with the nonce and returns the Play Integrity token.

> **Warning**
>
> The Play nonce must be a URL-safe, non-wrapping Base64 string between 16 and 500 characters. The same nonce is reused for retries, so it has to stay valid for the whole retry window.

- Each Play request times out after 60 seconds.
- Transient failures are retried up to 3 times.
- Delays are 5 seconds, then 10 seconds, then 20 seconds.

Retried Play error codes are network failure, too many requests, Google server unavailable, client transient error, and internal error. Other Play errors are returned immediately in `IntegrityCheckResult.error`.

Link the app to Play Integrity in the Play Console. This module sends only the nonce. Play resolves the cloud project from that app linking.

### iOS

The iOS implementation uses `DCAppAttestService`. The nonce string is SHA-256 hashed before it is passed to App Attest. The returned token is the Base64-encoded attestation object or assertion.

> **Warning**
>
> Enable the App Attest capability on the app. Devices where App Attest is unavailable return that failure in `IntegrityCheckResult.error`.

Lifecycle:

1. The first successful call generates a key, stores its key ID in the Keychain, attests the key with Apple, and returns the attestation object.
2. Later calls generate an assertion with the stored key.
3. When Apple reports the stored key as invalid, the key ID is removed and a new key is created and attested.

### JVM and JavaScript

These targets call `nonceProvider` and then return `IntegrityCheckResult()` with `token` and `error` both `null`.

## Usage

Add the dependency to your `commonMain`:

```kotlin
dependencies {
    implementation("ag.sportradar.mobile.epsilon:epsilon-integrity-check:<version>")
}
```

### Dependency on Core

This module depends on `epsilon-core` and exports it, so `CommonContext` is available when you include integrity.

> **Note**
>
> To use the types from Swift, export the module from your iOS framework. See the [Integration Guide](https://apidocs.sportradar.com/resources/epsilon-sdk/docs/integration_guide.md).
