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

# Server-Side Verification

Validate fingerprints on your backend to prevent spoofing.

## Why Server-Side Verification?

Client-side fingerprinting can be spoofed. A malicious user could intercept the SDK response and replay a different `visitorId` to your application. **Always verify on the server** before making trust decisions like granting trial access, processing payments, or allowing votes.

This guide covers verifying `visitorId` values from the **Identify** product. If you want to classify API callers directly on the server without a client SDK at all, see the [Sentinel guide](/guides/sentinel) — it uses `@fingerprintiq/server` to inspect every incoming request at the middleware level.

Never trust client-side data alone. The `visitorId` sent from the browser is user-controlled. Verify it against the FingerprintIQ API using your server-side secret key.

## The Verification Pattern

**Identify on the client**

Call `fiq.identify()` in the browser and get a `visitorId`.
  **Send the visitorId to your server**

Include the `visitorId` in your API request body or as a header — not as a query parameter (avoid logging it in access logs).
  **Verify with the FingerprintIQ API**

Fetch the visit history for that `visitorId` from the FingerprintIQ API using your server-side secret key.
  **Apply your trust logic**

Check confidence, bot probability, recency, and any risk factors before making a decision.

## Client Code

```typescript
// 1. Identify the device
const result = await fiq.identify();
const { visitorId, confidence, botProbability } = result;

// 2. Send visitorId to your server with the user's request
const response = await fetch('/api/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ visitorId }),
});

const { verified } = await response.json();
```

## Server Implementation

```typescript Node.js / Express
app.post('/api/verify', async (req, res) => {
  const { visitorId } = req.body;

  const fiqRes = await fetch(
    `https://fingerprintiq.com/v1/demo/visits/${visitorId}`,
    {
      headers: {
        'X-API-Key': process.env.FIQ_SECRET_KEY,
        'Content-Type': 'application/json',
      },
    }
  );

  const data = await fiqRes.json();
  const latestVisit = data.visits[0];

  const isLegitimate =
    data.totalVisits >= 1 &&
    latestVisit?.confidence >= 0.8 &&
    latestVisit?.botProbability < 0.3 &&
    Date.now() - latestVisit?.timestamp < 5 * 60 * 1000; // within 5 minutes

  res.json({ verified: isLegitimate, visits: data.totalVisits });
});
```

```typescript Hono
import { Hono } from 'hono';

const app = new Hono();

app.post('/api/verify', async (c) => {
  const { visitorId } = await c.req.json();

  const fiqRes = await fetch(
    `https://fingerprintiq.com/v1/demo/visits/${visitorId}`,
    {
      headers: { 'X-API-Key': c.env.FIQ_SECRET_KEY },
    }
  );

  const data = await fiqRes.json();
  const latestVisit = data.visits[0];

  const isLegitimate =
    data.totalVisits >= 1 &&
    latestVisit?.confidence >= 0.8 &&
    latestVisit?.botProbability < 0.3;

  return c.json({ verified: isLegitimate });
});
```

```typescript Next.js API Route
// app/api/verify/route.ts
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
  const { visitorId } = await req.json();

  const fiqRes = await fetch(
    `https://fingerprintiq.com/v1/demo/visits/${visitorId}`,
    { headers: { 'X-API-Key': process.env.FIQ_SECRET_KEY! } }
  );

  const data = await fiqRes.json();
  const latestVisit = data.visits[0];

  return NextResponse.json({
    verified:
      latestVisit?.confidence >= 0.8 &&
      latestVisit?.botProbability < 0.3,
    totalVisits: data.totalVisits,
  });
}
```

## Security Best Practices

The checks below are layered defenses. Implement all of them — skipping any one check leaves a gap an attacker can exploit.

1. **Verify recency** — Check that the latest visit timestamp is within the last 5 minutes. A `visitorId` from an hour ago should not grant access to a current session.

2. **Check confidence** — Reject fingerprints with `confidence` below 0.7. Low confidence means too many signals failed to collect, which is itself suspicious.

3. **Monitor bot probability** — Flag visitors with `botProbability` above 0.3 for review. Block those above 0.7.

4. **Check risk factors** — Inspect the `riskFactors` array for signals like `HEADLESS_BROWSER`, `TOR_EXIT_NODE`, `UA_TLS_MISMATCH`, or `SOFTWARE_RENDERER`.

5. **Use server-side API keys only** — The secret key used to call the FingerprintIQ API must never be exposed to the browser.

Store verified `visitorId` values in your session after the first verification. This avoids a round-trip to the FingerprintIQ API on every authenticated request while still establishing the initial trust anchor.