---
title: "Installation identity"
description: "Generate a random stable installation ID without hardware fingerprints and recover safely after reinstall or state loss."
slug: "/docs/v1/security/installation-id"
section: "Security"
order: 21
audience: "all"
level: "advanced"
last_updated: "2026-10-17"
version: "v1"
related: ["/docs/v1/security/signed-responses","/docs/v1/security/threat-model"]
draft: false
---
Persist one random [installation ID](/docs/v1/start/glossary#installation-id) per application installation and reuse it for [activation](/docs/v1/start/glossary#activation) and validation.

## What you will learn
- Generate and retain a privacy-conscious identity.
- Understand server hashes, validation binding and [device](/docs/v1/start/glossary#device) limits.
- Recover from reinstall without silently consuming extra devices.

## Prerequisites
- Read [the activation flow](/docs/v1/start/activation-validation-deactivation).
- Keep state in a private per-user directory.
- Use the [official SDK](/docs/v1/start/glossary#official-sdk)'s existing identity unless you are implementing a REST client.

## Identity contract
Activation's device_id is a trimmed string16–255 characters. Validation sends the same value in X-Installation-ID. The platform stores a keyed HMAC-SHA256 device hash; the signed response includes plain SHA-256 of the installation ID so the client can compare its own identity without the server pepper.

The raw installation ID is not stored in the device row. Optional device name, platform and application version are separate descriptive fields. A hash associated with a [customer](/docs/v1/start/glossary#customer) is not automatically anonymous data.

Use cryptographically random UUIDs or similarly high-entropy random IDs. Do not use a MAC address, disk serial, CPU ID, advertising ID, email address, IP address or a cross-product hardware fingerprint. A random installation ID reduces unnecessary device tracking but does not remove your privacy obligations. [CNIL distinguishes pseudonymisation from anonymisation](https://www.cnil.fr/fr/node/698).

## Persist before activation
1. Select a private per-user directory namespaced by application, origin, [product](/docs/v1/start/glossary#product) and environment.
2. Create the random ID once, before the first activation request.
3. Save it without overwriting an existing identity.
4. Reuse it on every run and include it with validation.
5. Compare its SHA-256 to the verified signed device.installation_hash.
Expected result: restarting the same installation does not create a new identity. Serialize first-run initialization; parallel processes must not race a partially written file.

Official Python, PHP, JavaScript and C# clients create and persist their own identities. Do not generate a new custom ID beside the SDK and send inconsistent values.

## Complete REST identity example
Python3.9+, standard library. Run python3 installation.py /absolute/private/path/installation-id. Two runs print the same UUID. Use a new temporary directory for tests. The path is your explicit local file, not a public web directory.
```python
"""Random persisted installation identity, Python3.9+; no hardware fingerprint.
Run: python3 installation.py PATH_TO_PRIVATE_ID_FILE. Output the same UUID each run.
This standalone REST-client example does not replace an official SDK identity.
"""
import os
import pathlib
import sys
import uuid

def installation_id(path):
    path = pathlib.Path(path)
    path.parent.mkdir(mode=0o700,parents=True,exist_ok=True)
    try:
        value = str(uuid.uuid4())
        with path.open('x') as file:
            os.chmod(path,0o600)
            file.write(value+'\n')
    except FileExistsError:
        pass
    # A damaged identity is not silently replaced and charged as a new device.
    value = path.read_text().strip()
    if str(uuid.UUID(value)) != value: raise ValueError('Invalid stored identity')
    return value

if __name__ == '__main__':
    try:
        if len(sys.argv)!=2: raise ValueError('Expected private identity path')
        print(installation_id(sys.argv[1]))
    except Exception:
        print('Installation identity is unavailable. Restore it or contact support.',file=sys.stderr)
        sys.exit(1)
```

A damaged identity is refused, not silently replaced. This demonstration uses exclusive file creation; use a startup lock if multiple processes initialize concurrently. Windows needs appropriate user-only ACLs, not an assumption that Unix modes are enforced.

## Device and activation limits
The server enforces concurrent active-device limits and any cumulative activation limit. Deactivation frees an active-device seat but does not decrement cumulative activation_count. Re-activation can rotate tokens; do not assume an old token remains valid.

A copied VM image containing the same ID/token/cache is not a genuinely new trusted installation merely because the hardware differs. Conversely, deleting the ID and generating a new one can consume a new seat or hit a cumulative limit. Do not reset identities as a retry strategy for DEVICE_LIMIT_REACHED.

## Reinstall and recovery
1. If the app still runs, deactivate the old installation before removing its state.
2. If reinstall retains the same trusted user state, reuse the existing ID.
3. If identity was lost, generate a new ID only through a clear reactivation path.
4. Explain DEVICE_LIMIT_REACHED without accusing the customer.
5. Ask the customer to release an old device or contact the [developer](/docs/v1/start/glossary#developer) for a supported reset.
6. After reset, activate again; old revoked tokens do not revive.
Expected result: recovery uses authorized device actions rather than fabricating more identifiers. Preserve user files even when a [license](/docs/v1/start/glossary#license) cannot be reactivated.

## Expected result
The same installation retains its ID and bound token across normal restarts; reinstall recovery respects server device limits.

## Common mistakes
- Regenerating an ID on every launch.
- Using a hardware serial or email as device_id.
- Omitting the validation installation header because it is transport-optional.

## Security notes
Keep IDs and token state private. Never treat a device hash as proof of a unique person or immutable physical device. Avoid broad backups that clone active credentials into new installations.

## Troubleshooting
| Symptom | Cause | Action |
| --- | --- | --- |
| DEVICE_MISMATCH | ID differs from the activated installation | Restore matching state or reactivate deliberately |
| DEVICE_LIMIT_REACHED after reinstall | Lost identity created another device | Release the old seat or request a supported reset |
| Invalid saved ID | Corruption or unexpected state modification | Refuse silently replacing it; restore or contact support |

## Next steps
Read [signed responses](/docs/v1/security/signed-responses) and [the threat model](/docs/v1/security/threat-model), then validate your own integration in [Sandbox](/docs/v1/start/glossary#sandbox).

## Related
- [Verification examples](/docs/v1/security/verify-ed25519)
- [Offline mode](/docs/v1/security/offline-mode)
- [Security and disclosure](/security)
