> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shieldlabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Privacy & data handling

> What ShieldLabs collects, how it is handled, and the controls you have over the data.

ShieldLabs identifies users, devices, visitors and IP addresses as **pseudonymous entities, not named individuals**. Users are your accounts, known to ShieldLabs only by the hashed User HID you pass. The snippet collects technical attributes of the browser, device and network connection and posts them to the server, which derives the Device ID and Visitor ID and a [Risk Score](/features/risk-scoring) for each identification and delivers them to your backend. It never asks for, sees, or stores who the person actually is.

This page describes what is and is not collected and how you stay in control of the data. Transport, key, and webhook-verification practices live on the [Security](/security) page.

<Note>
  This page describes data handling factually. It is not legal advice and makes no regulatory compliance claim. How you disclose ShieldLabs in your own privacy policy, and on what legal basis you process this data, is your decision to make with your own counsel. For the formal document, see the [Privacy Policy](/legal/privacy-policy), the [Terms of Service](/legal/terms), and the [Cookie & Tracking Policy](/legal/cookie-policy).
</Note>

## What ShieldLabs collects

The snippet reads technical signals from the browser environment and the network connection. These are the raw inputs the server turns into identifiers and the Risk Score.

| Category | Examples | Used for |
| - | - | - |
| **Browser fingerprint** | Hundreds of stable browser and device characteristics | Deriving the durable Device ID |
| **Device and OS** | Browser name, operating system, device type, timezone | Identification and mismatch checks |
| **Network** | IP address (read server-side from the connection), connection type, VPN/proxy/Tor/datacenter indicators, network and connection indicators | [Risk signal](/features/risk-signals) detection |
| **Page context** | The current page URL (with the `#fragment` stripped) and the referrer | [Traffic source](/features/traffic-analytics) attribution |
| **Client-side ids** | A first-party `cookieID` and a `sessionID`, both minted by the snippet | Linking calls from the same browser and visit |

ShieldLabs collects 300+ browser, device and network signals. The [risk signals](/features/risk-signals) reference lists the ones that carry a weight in the Risk Score, and [How it works](/overview) shows the flow end to end.

## What ShieldLabs does NOT collect

ShieldLabs has no field for, and never asks for, any of the following:

* **Names, emails, or phone numbers.**
* **Passwords.** No site-user credentials are read or stored.
* **Payment data.** No card numbers, no bank details.
* **Form field contents.** The snippet does not read what a visitor types.
* **Full browsing history.** Only the current page URL and the referrer are captured, for traffic attribution.

ShieldLabs answers "is this the same account, device or visitor as before, what else is it linked to, and how risky is it?" It answers without knowing who the person is: users are your accounts under the hashed User HID you pass, and devices and visitors carry a Device ID and a Visitor ID.

## User HID: you supply it, and it must be pseudonymous

The User HID is the one value that comes from you, not from the browser. It is your account id, hashed, passed into the snippet so ShieldLabs can link every device, visitor and IP address that signs in to the same account. Users, account-level risk and all four High-Risk Events are built on it.

<Warning>
  **Always pass a hashed or pseudonymous value. Never pass a raw email, username, or account id.** ShieldLabs needs only to know that two identifications belong to the same account. A one-way hash gives you that link without ever sending us a real identifier.
</Warning>

<CodeGroup>
  ```js Native JS theme={null}
  // Hash your internal user id before passing it in.
  const enc = new TextEncoder().encode(currentUser.id);
  const digest = await crypto.subtle.digest("SHA-256", enc);
  const hashedId = [...new Uint8Array(digest)]
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");

  const mod = await import(
    "https://cdn.shieldlabs.ai/snippet.js?publicKey=YOUR_PUBLIC_KEY"
  );
  mod.checkAuthenticatedUser(hashedId);
  ```

  ```js Wrong theme={null}
  // Do NOT do this. Never pass raw PII as the User HID.
  mod.checkAuthenticatedUser(currentUser.email); // raw email
  mod.checkAuthenticatedUser(currentUser.id);    // raw account id
  ```
</CodeGroup>

The same hashing applies to `forceCheckAuthenticatedUser`. When you call `checkAnonymous`, no user id is sent at all (the User HID is sent as `anonymous`), as the full client API in the [snippet reference](/setup/snippet) lays out.

## Two network addresses, kept distinct

ShieldLabs works with two different network addresses, and they are never mixed.

* The connection's **public IP** is read server-side from the request and used to derive location, reputation, and the [risk signals](/features/risk-signals) that flag a masked connection.
* The **local IP** is the address the browser itself reports, which can differ from the public IP when traffic runs through a VPN or proxy. It arrives on the webhook in the `local_ip` correlation field, with its country, and ShieldLabs links each local IP to the users, devices and visitors seen with it. The History API searches by public IP only. In the analytics dashboard, each user, device, visitor and public IP card lists its linked local IPs, with the identifications behind each.

Keep the local IP correlation field server-side. It exists for matching requests to each other, not for display, so do not surface it to your own users.

## Client-side storage

To recognize a returning browser without a server round trip, the snippet keeps two values in the visitor's own browser:

| Value | Where it lives | Lifetime |
| - | - | - |
| `cookieID` | A first-party cookie and `localStorage` (`SameSite=Lax`, `Secure` on HTTPS) | 2 years, lost when the visitor clears cookies or site storage |
| `sessionID` | `localStorage` (legacy `sessionStorage` migrated on read) | The current visit window |

Both are random UUIDs minted on the visitor's device. They are first-party only. The durable **Device ID is derived server-side from the stable browser environment, not stored on the device**, which is why it survives a cookie clear while the `cookieID` does not. The [Identifiers](/features/identification) page lays out how the ids relate.

## When the snippet runs on your site

The SDK does not wait for a consent banner. Identification starts when your code calls `checkAnonymous()` (or the other exports). Gate the call yourself if applicable law or your policy requires prior consent, and see the warning on [Install the JS Snippet](/setup/snippet). Details: [Cookie & Tracking Policy §2](/legal/cookie-policy).

## Where your data is stored

ShieldLabs processes and stores identification data in its own infrastructure, in a single region. There is no per-customer data-residency or region selection today, so you cannot pin storage to a specific country or cloud. Identification records are retained for **up to 12 months**; you can export them or request earlier deletion at any time. If you have a specific residency or retention requirement, email **[contact@shieldlabs.ai](mailto:contact@shieldlabs.ai)**.

## You control retention

Your data is yours to read, export, and remove.

<CardGroup cols={2}>
  <Card title="Export" icon="download" href="/dashboard/analytics">
    Filter identifications in the analytics dashboard and export them as CSV. Exports are free and never count toward your plan.
  </Card>

  <Card title="Read programmatically" icon="code" href="/api/server-api">
    Pull identifications for any identifier through the History API, keyed by User HID, Device ID, Visitor ID, IP, request ID, Session ID or Cookie ID.
  </Card>
</CardGroup>

Deletion is request-based: there is no self-serve delete endpoint today, so to remove stored records, or for any other data-handling question, email **[contact@shieldlabs.ai](mailto:contact@shieldlabs.ai)**.

## Data minimization in practice

The design choices above all point the same way: collect the technical signals needed to identify devices and visitors and score risk, and nothing that identifies a person.

* Identifiers are **derived** (Device ID, Visitor ID) or **pseudonymous** (User HID, supplied hashed by you), never tied to a name or email by ShieldLabs.
* The public IP and the device's local IP are kept distinct, and the local IP correlation field stays server-side.
* The snippet captures the **current** page URL and referrer for attribution, not a browsing trail.
* No passwords, payment data, or form contents are ever read.

## Related

* [Security](/security): webhook signature verification, key management, and transport.
* [Users, devices, visitors and IPs](/concepts/entities): the identities ShieldLabs links and scores, and how they connect.
* [Identifiers](/features/identification): how the request ID, Device ID, Visitor ID and User HID are built and how durable each one is.
* [Risk signals](/features/risk-signals): every risk signal and its weight.
* [Server API](/api/server-api): read and export your stored identifications.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.