← Files FingerprintARCHIVED FILE
skills/fingerprint-node/SKILL.md
3.34 KB · Oct 4, 2026 · 12:25 UTC
---
name: fingerprint-node
description: Integrate the Fingerprint Server API into a Node/Express backend — fetch an event by event_id and read the verified identification and Smart Signals.
---
# Fingerprint — Node (Server API)
Integrate the Fingerprint Server API into a Node/Express backend: take the single-use `event_id`
your frontend sends, fetch the event server-side, and read the verified identification and Smart
Signals. The server is the source of truth — never trust a `visitor_id` or a decision sent straight
from the client.
> Docs: 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.
## Package
`@fingerprint/node-sdk` — install the latest version.
## Env var
- `FINGERPRINT_SECRET_API_KEY` — the secret key. Server-side only; never sent to the browser.
## Steps
1. **Install** `@fingerprint/node-sdk`.
2. **Create one client** at startup with the secret key and region (`Region.Global` | `Region.EU`
| `Region.AP`, matching the workspace). Load `.env` (via `dotenv`) before the key is read —
plain Node does not auto-load `.env`, and a missing key fails at startup with "Api key is not
set". Pick the snippet by module system — check `package.json` `"type"`, not the file
extension, since a TypeScript project can be either:
- `"type": "module"` (ESM) → `snippets/client.mjs`. `import 'dotenv/config'` must be the
**first import**: ESM evaluates all imports, in order, before any statement in the file, so a
`dotenv.config()` call in the body runs too late.
- otherwise (CommonJS) → `snippets/client.js`.
3. **Fetch and check the event.** Given the `event_id`, call `client.getEvent(eventId)` and apply
the checks below before trusting the action. See `snippets/verify.js`.
## v4 event shape (flat — per the Server API event schema)
`getEvent` returns the event object directly:
- `event.identification.visitor_id` — the trusted visitor id
- `event.identification.confidence.score` — 0..1 (probability of a false-positive identification)
- `event.timestamp` — Unix ms of the event
- `event.replayed` — `true` if the payload was replayed
- `event.bot` — `"bad" | "good" | "not_detected"`
- `event.vpn`, `event.proxy`, `event.tampering`, `event.incognito` — booleans
- `event.suspect_score` — weighted Smart-Signals score (integer)
- `event.velocity` (object), `event.ip_blocklist` (object: `attack_source`, `email_spam`,
`tor_node`)
## Checks (do all of them)
- **Found:** `event.identification.visitor_id` exists.
- **Replay / freshness:** reject if `event.replayed === true`, or if `event.timestamp` is older
than your window (e.g. 2 minutes) — prevents reuse of an old `event_id`.
- **Confidence:** require `event.identification.confidence.score >= 0.9` for the action.
- **Smart Signals** (fail-closed for high-risk actions): `event.bot !== "not_detected"`,
`event.vpn`, `event.proxy`, `event.tampering`.
- **Identity match:** bind `visitor_id` ↔ user on first trusted use; re-check on later actions.
## Notes
- Fetch and check server-side on **every** sensitive action.
- Fail closed on lookup errors for high-risk flows.
- Each `event_id` is single-use per action — don't cache a pass/fail across requests.
- Keep the secret key out of logs and any client bundle.
SHA-256: d8b7fa58af7aaddaa7c6b802bd7435dd16e11e94c3e3c002983adc87fc9dbf3c