Device Ref

The deviceRef is how the engine tells one installation apart from another. It rides along on every pipeline session, every X-Device-Ref header, and the OTel resource, and server-side it defaults to the session id — so a client that fails to send a stable one is treated as a brand new device on every reconnect (see Session Reconnect).

It is derived from the identity the OS hands out, not generated once and stored, so a reinstall or a cleared app data directory lands on the same ref as before.

How it works

File Responsibility

Assets/Scripts/SystemNative/DeviceIdentity.cs

Per-platform lookup of the raw OS identity. Returns null where the platform has none.

Assets/Scripts/SystemNative/DeviceRef.cs

Turns that identity into the ref, and owns the dev-only random override.

The ref keeps the shape it has always had — unity-<platform>-<uuid> — but the UUID is now a SHA-256 of a fixed salt plus the OS identity, laid out as an RFC 4122 v5 UUID. The hash matters for two reasons: the raw OS identifier never leaves the device, and the salt keeps a ref from colliding with anything else derived from the same identifier.

The derived ref is also written to PlayerPrefs under DeviceRef — not as the source of truth, but so that a lookup that fails once (a JNI call before the activity exists, a keychain the OS will not open yet) answers with the ref the device derived before instead of minting a new one. The same slot is what the web client falls back to, and what installs from before this change already hold.

DeviceRef.Get() caches for the lifetime of the process. The value is read when a session opens and when telemetry initialises, so a change mid-run only shows up on the next session.

Per-platform identity

Platform Source Survives

Android

Settings.Secure.ANDROID_ID, scoped by the OS to this app’s signing key.

Reinstall. Not a factory reset, and not a change of signing key.

iOS

identifierForVendor, written to the keychain on first read and taken from there afterwards.

Reinstall — the keychain entry outlives the app, which matters because the vendor id itself resets once the last app from this vendor is gone.

Web

None. Browsers expose no device identity, so the ref falls back to a random one stored in PlayerPrefs.

A page reload. Not clearing site data.

Editor, desktop

SystemInfo.deviceUniqueIdentifier.

Reinstall.

The advertising identifiers (IDFA, GAID) are deliberately not used. Both are user-resettable and both need consent — an ATT prompt on iOS, the AD_ID permission on Android — which would make the ref neither stable nor free to collect.

Random override

Settings → About → Random device ref (dev mode only) swaps in a throwaway ref, so a build can be seen by the engine as a device it has never met. Turning it on rolls a fresh one every time; turning it off returns to the derived ref, unchanged. The override persists across restarts, so it stays put for as long as a test needs it.

It takes effect from the next session — an already-open pipeline keeps the ref it opened with, and telemetry keeps it until the app restarts.