← FingerprintCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Fingerprint
Snapshot Sep 30, 2026 · 23:11 UTC · version 1.0.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "fingerprint-nextjs",
"description": "Add Fingerprint to a fullstack Next.js (App Router) app — identify visitors in the browser with the React SDK and verify the event_id server-side with the node SDK in a Route Handler or Server Action.",
"included_files": [
{
"relative_path": "skill.json",
"size_in_bytes": 346
},
{
"relative_path": "snippets/fingerprint-server.ts",
"size_in_bytes": 2072
},
{
"relative_path": "snippets/identify-on-action.tsx",
"size_in_bytes": 759
},
{
"relative_path": "snippets/layout.tsx",
"size_in_bytes": 487
},
{
"relative_path": "snippets/provider.tsx",
"size_in_bytes": 763
},
{
"relative_path": "snippets/route-handler.ts",
"size_in_bytes": 519
},
{
"relative_path": "snippets/server-action.ts",
"size_in_bytes": 541
}
],
"skill_md_contents": "---\nname: fingerprint-nextjs\ndescription: Add Fingerprint to a fullstack Next.js (App Router) app — identify visitors in the browser with the React SDK and verify the event_id server-side with the node SDK in a Route Handler or Server Action.\n---\n\n# Fingerprint — Next.js\n\nIntegrate Fingerprint into a Next.js (App Router) app. Next.js does both halves in one codebase:\nthe **client identifies** the visitor (producing a single-use `event_id`) and the **server**\nfetches that event from the Server API to read the verified identification and Smart Signals. The\nbrowser never holds the secret key and never makes trust decisions — the server does, using the\nchecks below.\n\n> Docs: React SDK https://docs.fingerprint.com/docs/react · Node Server SDK https://docs.fingerprint.com/reference/node-server-sdk · event schema: OpenAPI (https://github.com/fingerprintjs/fingerprint-pro-server-api-openapi) or the Fingerprint MCP event-schema resource.\n\n## Packages\n- `@fingerprint/react` — browser identification (client components). Install the latest version.\n- `@fingerprint/node-sdk` — Server API verification (Route Handlers / Server Actions). Install the latest version.\n\n## Env vars\nNext.js only exposes env vars prefixed with `NEXT_PUBLIC_` to the browser bundle. Everything else\nstays server-only.\n\n- `NEXT_PUBLIC_FINGERPRINT_PUBLIC_API_KEY` — public key, shipped to the browser (safe).\n- `NEXT_PUBLIC_FINGERPRINT_REGION` — workspace region for the client (`us` | `eu` | `ap`), shipped\n to the browser.\n- `FINGERPRINT_SECRET_API_KEY` — secret key. **Server-only**; the missing `NEXT_PUBLIC_` prefix\n keeps it out of the client bundle. Never reference it from a client component.\n- `FINGERPRINT_REGION` — workspace region for the server (`us` | `eu` | `ap`).\n\n> Read public values via `process.env.NEXT_PUBLIC_*`; they are inlined into client code. Read the\n> secret only inside server code (Route Handlers, Server Actions, server components). If you ever\n> see `FINGERPRINT_SECRET_API_KEY` referenced from a `'use client'` file, that's a leak.\n\n## Steps\n\n### Client — identify\n1. **Install** `@fingerprint/react`.\n\n2. **Wrap the app in `FingerprintProvider`.** The provider is a client component, so put it in a\n small `'use client'` wrapper and render that wrapper inside `app/layout.tsx` around `{children}`.\n Pass the public key and region from the `NEXT_PUBLIC_` vars. See `snippets/provider.tsx` and\n `snippets/layout.tsx`.\n\n3. **Identify on sensitive actions, not on every render.** In a client component, use\n `useVisitorData({ immediate: false })` and call `getData()` at the moment of a security-relevant\n action (login, signup, checkout, password reset). See `snippets/identify-on-action.tsx`.\n\n4. **Send the `event_id` to the server** with the action request. `getData()` returns\n `{ visitor_id, event_id }`; send the **`event_id`** (single-use, server-verifiable). Do not trust\n the client `visitor_id` — the server re-derives it from the Server API.\n\n### Server — verify\n5. **Install** `@fingerprint/node-sdk`.\n\n6. **Create one client** with the secret key and region (`Region.Global` | `Region.EU` |\n `Region.AP`, mapped from `FINGERPRINT_REGION`). Next.js loads `.env.local` automatically, so no\n `dotenv` is needed. See `snippets/fingerprint-server.ts`.\n\n7. **Verify the `event_id`** before running the sensitive handler: call `client.getEvent(eventId)`\n and apply the checks below. Use it from either a Route Handler (`app/api/.../route.ts`) or a\n Server Action (`'use server'`). See `snippets/route-handler.ts` and `snippets/server-action.ts`.\n\n## Verification checks (do all of them)\n- **Found:** `event.identification.visitor_id` exists.\n- **Replay / freshness:** reject if `event.replayed === true`, or if `event.timestamp` is older than\n your window (e.g. 2 minutes) — prevents reuse of an old `event_id`.\n- **Confidence:** require `event.identification.confidence.score >= 0.9` for the action.\n- **Smart signals** (fail-closed for high-risk actions): `event.bot !== \"not_detected\"`,\n `event.vpn`, `event.proxy`, `event.tampering`.\n- **Identity match:** bind `visitor_id` ↔ user on first trusted use; re-check on later actions.\n\n## v4 event shape (flat — per the Server API event schema)\n`getEvent` returns the event object directly:\n- `event.identification.visitor_id` — the trusted visitor id\n- `event.identification.confidence.score` — 0..1 (probability of a false-positive identification)\n- `event.timestamp` — Unix ms of the event\n- `event.replayed` — `true` if the payload was replayed\n- `event.bot` — `\"bad\" | \"good\" | \"not_detected\"`\n- `event.vpn`, `event.proxy`, `event.tampering`, `event.incognito` — booleans\n- `event.suspect_score` — weighted Smart-Signals score (integer)\n- `event.velocity` (object), `event.ip_blocklist` (object: `attack_source`, `email_spam`,\n `tor_node`) — for abuse / ATO logic\n\n## Best practices\n- One `FingerprintProvider` at the app root; don't re-instantiate per component.\n- Region must match the workspace region on **both** sides (`us` | `eu` | `ap`).\n- Don't block the UI on identification; handle the hook's `isLoading`/error states.\n- Verify server-side on **every** sensitive action; treat the client result as a hint only.\n- Fail closed on lookup errors for high-risk flows.\n- Each `event_id` is single-use per action — don't cache a pass/fail across requests.\n- Keep the secret key out of logs and out of any `NEXT_PUBLIC_` var or client component.\n"
}SHA-256: ddc4f252309115b003c318d4f8f825fb00f4454ee2e6145205843df9c3a038f4