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

# Integrate Connection Fingerprint

> How to call Connection Fingerprint from the browser, verify the signature in your backend, and turn the signals into risk decisions.

## The full path

<Steps>
  <Step title="Register your origins">
    The service answers CORS with an explicit allowlist of origins and `access-control-allow-credentials: true`. Send VU the exact origins — scheme, host, and port — for every environment before you start.
  </Step>

  <Step title="Call the API from the client">
    The fingerprint describes the connection making the call. It has to come from the user's device.
  </Step>

  <Step title="Forward the whole response to your backend">
    `userData` and `signature`, unmodified and unreordered.
  </Step>

  <Step title="Verify and score">
    Only after verifying should the signals reach your risk engine.
  </Step>
</Steps>

## Calling from the browser

```js theme={null}
const res = await fetch("https://fingerprint.api.vusecurity.com/", {
  credentials: "include",   // required: without it the fp cookie never travels
});
const fingerprint = await res.json();

// Forward AS-IS to your backend, together with your session context.
await fetch("/api/risk/evaluate", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ sessionId, fingerprint }),
});
```

<Warning>
  **`credentials: "include"` is not optional.** Without it the `fp` cookie is neither sent nor stored, and the service issues a brand-new identifier on every visit. Persistence — half the value of the product — disappears silently: the response is still `200` and every field is still there.
</Warning>

<Warning>
  **Never call this API from your server on the user's behalf.** The fingerprint is computed from the caller's TLS handshake. A call made from your backend returns your backend's fingerprint: identical for every one of your users, and therefore worthless.
</Warning>

## Verifying the signature

The response travels through the client. Without verification, anyone can edit `userData` in their developer tools before it reaches your backend.

```bash theme={null}
curl -s https://fingerprint.api.vusecurity.com/publicKey
```

```json theme={null}
{ "publicKey": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0K..." }
```

The value is a 4096-bit RSA public key in PEM format, base64-encoded. Decode it once and cache it; do not fetch it on every evaluation.

```js theme={null}
let key = null;
async function getPublicKey() {
  if (key) return key;
  const r = await fetch("https://fingerprint.api.vusecurity.com/publicKey");
  const { publicKey } = await r.json();
  key = Buffer.from(publicKey, "base64").toString("utf8"); // PEM
  return key;
}
```

<Warning>
  **Confirm the hash algorithm and the exact canonicalization of `userData` with VU** before writing the verification. The signature is produced over a specific serialization of that block: if your code re-serializes the object in another form — different spacing, different key order — verification fails even though the data is authentic. Carry the **raw** response body from the client all the way to the verifier; do not round-trip it through `JSON.parse` and `JSON.stringify` on the way.
</Warning>

<Tip>
  While you settle that detail with VU, do not leave the integration open: treat the response as unverified and never let it alone authorize a sensitive operation.
</Tip>

## Using the signals

No signal decides on its own. The value is in crossing them.

| Observation | What it suggests | Cross it with |
| - | - | - |
| `tlsFingerprintSslGreased` is `"0"` and the `user-agent` claims a modern browser | Automated client in disguise | `headerSignature`, header order |
| Known `tlsFingerprintHash`, new `cookie` and `etag` | Recognizable device that lost its state | `etagFirstRequest`, account history |
| Same `cookie` with a different `tlsFingerprintHash` | Browser update… or a stolen cookie | Time window, `geoData` |
| `geoData.country` differs from the account's usual one | Travel, VPN, or account takeover | Implied velocity between events, `accuracyRadius` |
| `http2Fingerprint` is `null` from a modern browser | Proxy or intermediate client | `headers`, `ip` |

<Warning>
  A `tlsFingerprintHash` is **not unique per device**: it identifies a combination of client, version, and platform. Millions of people running the same Chrome on the same Windows share a hash. Use it to spot inconsistencies and to group — never to authenticate.
</Warning>

## Persistence: two mechanisms, two lifetimes

`cookie` and `etag` identify the same visitor through different paths, and that redundancy is deliberate:

* **`cookie`** lasts a year and disappears when the user clears cookies or opens a private window.
* **`etag`** rides on the HTTP cache and often survives that clearing.
* **`etagFirstRequest`** tells you which case you are looking at: `true` is a freshly issued `etag`, `false` is one the client sent back — it had been here before.

Store both identifiers against the account. One rotating while the other persists is itself a signal.

## `/update`

An administrative operation protected by the `X-API-Key` header. It plays no part in the integration flow. Without a valid key it returns `401`:

```json theme={null}
{ "detail": "Invalid API Key" }
```

## Privacy

<Warning>
  This API produces personal data: IP address, approximate location, and persistent device identifiers. Under GDPR, LGPD, or equivalent regimes, using it requires a lawful basis, notice to the data subject, and a defined retention period. Involve your legal team before going to production, and store only what your risk engine actually queries.
</Warning>

## Before going to production

1. Every origin — development, staging, production — is registered with VU.
2. The call comes from the client, never from your backend.
3. `credentials: "include"` is present on every call.
4. The raw response body reaches the verifier intact.
5. Signature verification is implemented and agreed with VU.
6. The public key is cached, with a path to rotate it.
7. Every key in `geoData` is read as optional; `city` can be `null`.
8. `accuracyRadius` is taken into account whenever the coordinates are used.
9. No decision rests on a single signal.
10. No `tlsFingerprintHash` is used as a credential.
11. Identifiers have a defined, documented retention period.
12. There is a fallback for when the API does not answer: risk scoring degrades, it does not fall over.

<Card title="Back to the introduction" icon="fingerprint" href="/en/vucs/connection-fingerprint/introduction">
  Endpoints, response anatomy, and what every field means.
</Card>


## Related topics

- [Connection Fingerprint](/en/vucs/connection-fingerprint/introduction.md)
- [VU Cloud Services](/en/vucs/introduction.md)
- [Identity Link API Changelog](/en/identity-link/changelog.md)
- [VU Technical Documentation](/en/index.md)
- [Integrate Facial Antispoofing](/en/vucs/antispoofing-face/integration.md)


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