Browser fingerprinting SDK docs
Install the browser fingerprinting SDK and visitor ID JavaScript library, send browser signals to POST /api/identify, and fetch authoritative smart signals from your server. Use Events GET for online fraud detection workflows — account takeover prevention, credential stuffing defense, and bot detection API playbooks — with a persistent originId.
Trust model
Browser
POST /api/identify
Your backend
Store eventId
Events API
GET/PATCH /api/events/:eventId
Your policy
Gate on confidence + account
Use each eventId once within a 5-minute decision window. Fraud fields never belong in the browser.
What this SDK does
The browser fingerprinting SDK and visitor ID JavaScript client collect device signals in-browser, then your backend decides with server-authoritative enrichment.
DigitalFingerprint is a visitor identification platform delivered as a JavaScript SDK. Use it when you need a persistent visitor ID across cleared cookies, VPNs, and many private-browsing scenarios — without trusting fraud fields returned to the browser. Start with install, then wire Events GET before signup, checkout, or other high-value actions.
Quick start
Production integrations follow a three-step trust model. Gate sensitive actions on confidence plus account, not originId alone.
- 01
Install the SDK
Install @digitalfingerprintjs/client from npm, load cdn.digitalfingerprintjs.com, or import the Google Tag Manager template — then init with your public browser key (pk_…).
- 02
Identify in the browser
POST browser signals to https://api.digitalfingerprintjs.com/api/identify. Production keys return a slim payload; store eventId on your backend.
- 03
Enrich server-side
Fetch authoritative smart signals via GET /api/events/:eventId with a secret server key (sk_…). Attach account/order metadata after identify with PATCH /api/events/:eventId (linkedId/tags). Optionally GET /api/drn/:originId for global device reputation. Never trust fraud fields from the client.
Installation
Package @digitalfingerprintjs/client, public SDK class OriginID. The SDK collects 95+ browser signal fields on Chromium.
app.ts
npm install @digitalfingerprintjs/client
// or CDN: https://cdn.digitalfingerprintjs.com/v1/originid.global.js
import { OriginID } from "@digitalfingerprintjs/client";
const oid = OriginID.init({
endpoint: "https://api.digitalfingerprintjs.com/api/identify",
apiKey: process.env.NEXT_PUBLIC_ORIGINID_PUBLIC_KEY, // pk_… public browser key
onIdentify: (result) => {
// Production: send result.eventId to your backend
console.log(result.originId, result.eventId);
},
});
await oid.ready();Analytics / marketing
Single assignment path with optional confidence gating on sensitive actions via Events GET. Import the analytics-marketing rules preset from the console Limiter.
analytics-init.ts
import { OriginID } from "@digitalfingerprintjs/client";
// Analytics / marketing: import analytics-marketing rules preset from Limiter
const oid = OriginID.init({
endpoint: "https://api.digitalfingerprintjs.com/api/identify",
apiKey: process.env.NEXT_PUBLIC_ORIGINID_PUBLIC_KEY, // pk_…
onIdentify: (result) => {
// Send result.eventId to your backend for Events GET (secret sk_… key)
console.log(result.originId, result.eventId);
},
});
await oid.ready();
// Backend: gate sensitive actions when event.identification.confidence < 90Fraud / signup pattern
Gate on confidence + rules via Events GET before sensitive actions. SDK auto-seeds clientToken since v1.0.
fraud-init.ts
import { OriginID } from "@digitalfingerprintjs/client";
// Fraud / signup: gate on confidence + rules via Events GET
const oid = OriginID.init({
endpoint: "https://api.digitalfingerprintjs.com/api/identify",
apiKey: process.env.NEXT_PUBLIC_ORIGINID_PUBLIC_KEY, // pk_…
identifyOnDemand: true, // before OTP, checkout, password reset
getIdentifyMetadata: () => ({ linkedId: currentUserId }),
});
const { eventId } = await oid.ready();
// Backend: GET /api/events/:eventId with sk_… → gate on confidence + linkedIdScript tag
Serve originid.global.js from your origin or a CDN build of @digitalfingerprintjs/client. Prefer Google Tag Manager when you cannot redeploy site code.
index.html
<script
src="https://cdn.digitalfingerprintjs.com/v1/originid.global.js"
integrity="sha384-sLnmYFAc9KQJmcBlbZOiHELB9o2AttpyJTvc12Z4yYpGrYGN6roK3o9zso58YPXJ"
crossorigin="anonymous"
></script>
<script>
OriginID.init({
endpoint: "https://api.digitalfingerprintjs.com/api/identify",
apiKey: "YOUR_PUBLIC_API_KEY", // pk_… never use sk_ in the page
})
.ready()
.then((r) => console.log(r.originId, r.eventId));
</script>Google Tag Manager
Deploy DigitalFingerprint through GTM without changing website code. Identification results are pushed to the dataLayer for other tags.
Download the tag template, import it under GTM Templates, create a DigitalFingerprint tag with your public key (pk_…), and trigger on Initialization. Allowlist your website hostname on the key.
Template: https://cdn.digitalfingerprintjs.com/integrations/gtm/v1/template.tpl
The template loads the adapter at https://cdn.digitalfingerprintjs.com/integrations/gtm/v1/adapter.iife.min.js (not imported manually).
dataLayer result
After identify, read DigitalFingerprintResult.originId (Data Layer Variable) and fire dependent tags on custom event DigitalFingerprint.identified. Optional first-party proxy: set an endpoints row to your identify URL.
datalayer.js
window.dataLayer.push(function () {
if (this.get("DigitalFingerprintResult")) {
const result = this.get("DigitalFingerprintResult");
console.log(result.originId, result.eventId);
}
});Preview checklist
- DigitalFingerprint tag fires on Initialization (or your chosen trigger)
- dataLayer shows DigitalFingerprint.started then DigitalFingerprint.identified
- DigitalFingerprintResult.originId and eventId are present
- A matching visit appears in the DigitalFingerprint dashboard
SDK configuration
| Option | Default | Description |
|---|---|---|
| endpoint | https://api.digitalfingerprintjs.com/api/identify | Production identify URL (use relative /api/identify only for same-origin or CDN first-party proxy) |
| apiKey | n/a | Public browser key (pk_…) → Authorization: Bearer (hostname-bound) |
| environment | n/a | Optional production | staging override when key policy allows |
| responseMode | slim (prod keys) | slim | full; appends ?response=full when set to full |
| signingSecret | n/a | Not used with public keys (CAD-2). Legacy/self-host only — never put platform ORIGINID_SECRET in SaaS frontend JS |
| clientToken (auto) | SDK default | Auto-seeded on init when storage empty (cookie + localStorage); pre-seed via inline script for WebView bridges |
| autoIdentify | true | Call identify automatically on init |
| identifyOnDemand | false | Skip in-memory cache; full collect + POST on every identify/ready (use before OTP/checkout) |
| collectDelayMs | 0 | Defer heavy async probes until after first paint |
| disabledProbes | [] | Probe IDs sent as "disabled" in the payload |
| getIdentifyMetadata | n/a | Returns { linkedId?, tags? } merged into each identify body |
| onIdentify | n/a | Callback on successful identify |
| onError | n/a | Callback on identify failure |
Methods
| Method | Description |
|---|---|
| OriginID.init(config) | Create SDK instance; auto-identifies when autoIdentify is true |
| oid.identify(signals?, metadata?) | Collect signals (if omitted) and POST to identify |
| oid.ready() | Promise that resolves after auto-identify completes |
| oid.getOriginId() | Latest originId after identification |
| oid.getResult() | Latest full or slim response object |
| collectSignals() | Low-level: gather browser signals without identifying |
linkedId and tags
Attach stable business identifiers on each identify. Limits: linkedId 255 chars; up to 20 tag keys (64 / 256 chars). These are visit metadata, they do not change how originId is assigned.
identify.ts
await oid.identify(undefined, {
linkedId: "user_12345",
tags: { plan: "pro", signup_source: "web" },
});First-party clientToken
The server may return clientToken in slim responses for returning-visitor continuity. The SDK persists it in localStorage (normal browsing) or sessionStorage (incognito). Incognito tokens never write to durable storage and are linked to normal profiles via privacy-profile matching when hardware aligns.
POST /api/identify
Accepts collected browser signals plus optional linkedId, tags, clientToken, and sessionToken.
Request integrity
Public browser keys use platform-managed integrity (hostname allowlisting). Do not put platform ORIGINID_SECRET or a customer signingSecret in frontend JS. Legacy oid_… keys remain dual-accept during migration (self-host may use ORIGINID_REQUEST_SIGNING=required).
Query parameters
| Parameter | Effect |
|---|---|
| ?response=slim | Force slim browser payload (originId, eventId, clientToken, timestamp) |
| ?response=full | Return full identify JSON (staging/debug; not for production fraud logic) |
| ?format=fingerprint | Fingerprint-compatible JSON export (requires full response mode) |
| ?ruleset_id=rs_… | Optional. Evaluate one ruleset before persist; block responses are unbilled |
Slim response (production default)
Production keys default to slim unless overridden by query or per-key policy. Fraud fields such as confidence and smartSignals are never in slim browser payloads.
originIdeventIdclientTokentimestamp
Error responses
Rejects include rejectReason and billed: false when no visit is persisted.
| HTTP | rejectReason | Notes |
|---|---|---|
| 401 | invalid_key | Missing or invalid API key |
| 403 | HOSTNAME_NOT_ALLOWED | Browser Origin/Referer hostname not on the key allowlist |
| 403 | invalid_signature / waf_block | Bad HMAC signature or edge WAF block (unbilled) |
| 402 | plan_usage_exceeded | Hosted plan quota exceeded (when BILLING_ENFORCE_USAGE=true) |
| 409 | invalid_signature | Definitive signature replay when signing is required |
| 429 | rate_limit | Per-IP (60/min) or per-clientToken (120/min) limit exceeded |
Confidence & rules
Single continuity-first assignment path on every API key. Fraud vs analytics posture is confidence v2 + rules presets + Events GET gating, not merge policies.
| Concept | Description |
|---|---|
| Single assignment path | Continuity-first matching on all API keys: single assignment path for all keys |
| Explainable matching | matchPath (stable_hash, rule_matcher, privacy_profile_link, global_fingerprint): explainable continuity — no black-box ML |
| Confidence v2 | 0–100 merge false-positive risk; fusion penalties cap fingerprint merges at 70–89 on shared hardware |
| Rules presets | Import analytics-marketing, signup-protection, or shared-devices from console Limiter |
| Events GET gating | Gate signup when confidence < 90 and no linkedId (Fingerprint 0.90 equivalent) |
Rules preset integration
| Preset | Label | When to use |
|---|---|---|
| analytics-marketing | Analytics & marketing | Log all visits; optional confidence gating via Events GET |
| signup-protection | Fraud & signup | Block or step-up when confidence < 90 via Events GET + Limiter |
| shared-devices | Corporate fleets & kiosks | Extra guards when identical hardware may share an originId |
First-party clientToken
| Setting | Description |
|---|---|
| clientToken auto-seed | SDK 1.0+ seeds first-party token on init (normal browsing) |
| token_match | Matching clientToken → confidence 100, same originId |
| global_fingerprint | Cross-org continuity: exact stable+recall or probabilistic ≥90 → same originId; metrics stay per-tenant |
| Incognito | Session token only; privacy_profile_link for cross-mode continuity (Safari, Chrome, Firefox, Brave, Samsung Internet, iOS Safari) |
Import rules presets from the console Limiter or via POST /api/management/v1/api-keys project setup. Fraud vs analytics posture is expressed through rules presets and Events GET confidence gating , not per-key assignment forks.
GET/PATCH /api/events/:eventId
Authoritative enrichment for a single identify event. Confidence and smartSignals are stored at identify time, never recomputed. PATCH updates linkedId/tags after identify.
server.ts
// Your backend: authoritative enrichment (never trust browser fraud fields)
const rulesetId = process.env.ORIGINID_RULESET_ID; // optional, from /dashboard/rules
const apiBase = "https://api.digitalfingerprintjs.com";
const url = rulesetId
? `${apiBase}/api/events/${eventId}?ruleset_id=${rulesetId}`
: `${apiBase}/api/events/${eventId}`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${ORIGINID_API_KEY}` }
});
const event = await res.json();
// event.identification.confidence, event.smartSignals, event.ruleActionKey response fields
identification.originIdidentification.confidenceidentification.confidenceVersionidentification.linkConfidenceidentification.linkOriginIdconfidencePenaltiessmartSignalssuspectScoreriskLevelriskBreakdownmatchPathhighRecalldeviceReputationbrowserDetailsipInfolinkedIdtagsruleActionrulesetEvaluation
?format=fingerprint returns Fingerprint-compatible JSON (confidence 0–1). Native JSON uses scale 0–100. ?include=raw adds raw signal blobs when PERSIST_RAW_SIGNALS=true. Rate limits: default 600/min per API key, 1000/min per organization. Native Events JSON may include deviceReputation; the Fingerprint Accept export omits it — use GET /api/drn/:originId instead. After identify, PATCH /api/events/:eventId with linkedId / tags (full replace when tags present; secret key only).
Limiter (Beta)
Create rulesets at /dashboard/rules. Enabled rulesets evaluate on every POST /api/identify, the first matching block rule returns an unbilled response. Pass ?ruleset_id=rs_… on Events GET for inline evaluation.
| Field / param | Description |
|---|---|
| Enabled rulesets (auto) | All enabled project rulesets evaluate on POST /api/identify; first block wins (unbilled) |
| ?ruleset_id=rs_… (Events GET) | Evaluate one ruleset inline; response includes ruleAction and rulesetEvaluation |
| ?ruleset_id=rs_… (identify) | Optional. Evaluate one ruleset before persist instead of all enabled rulesets |
| ruleAction | Matched rule result: allow or block with status, headers, and body |
| rulesetEvaluation | Status when ruleset_id query param was passed (evaluated or not_found) |
GET /api/drn/:originId
Fingerprint-style device reputation across soft-linked clusters. Secret key only. Never returns other tenants' events.
Query by the public originId from identify. When the same device was minted under two IDs (e.g. hardware overlap without strong stable+recall agreement), DRN aggregates suspect scores and timestamps across the cluster. Response fields: canonicalOriginId, clusterOriginIds, suspectScore.minimum/maximum (30-day window), timestamps.
drn.ts
const res = await fetch(
"https://api.digitalfingerprintjs.com/api/drn/" + encodeURIComponent(originId),
{ headers: { Authorization: "Bearer " + process.env.ORIGINID_SECRET_KEY } },
);
const reputation = await res.json();Confidence model
identification.confidence expresses merge false-positive risk (0–100), not population uniqueness.
| Field | Description |
|---|---|
| identification.confidence | 0–100 merge false-positive risk (not population uniqueness); persisted per visit |
| identification.confidenceVersion | 2 (Fingerprint-aligned false-positive merge risk; `2.0` on Fingerprint export) |
| identification.linkConfidence | Privacy-link score when primary originId differs from link target (e.g. normal ↔ incognito continuity) |
| confidencePenalties[] | tls_binding_mismatch, ip_timezone_history, linked_id_velocity; caps merge confidence to 70–89 |
| highRecall | Supplementary originId when recallHash points elsewhere (primary confidence capped at 85 on link paths) |
v2 semantics
All new visits use confidenceVersion: 2. Token match and new visitors score 100 (Fingerprint 1.0). Fingerprint merges cap at 99; fusion penalties drop confidence to 70–89.
Signup gate example
Map Fingerprint 0.90 threshold to native 90. Always combine confidence with linkedId for returning accounts.
signup-gate.ts
const event = await fetch(`https://api.digitalfingerprintjs.com/api/events/${eventId}`, {
headers: { Authorization: `Bearer ${SECRET_KEY}` },
}).then((r) => r.json());
const confidence = event.identification.confidence; // 0–100 native
const linkedId = event.linkedId;
if (confidence < 90 && !linkedId) {
return blockSignup("step_up_required");
}POST /api/account-link
Optional endpoint for duplicate-account detection at registration.
Body: { "email": "user@example.com", "visitorId": "<originId>" }. The request field is named visitorId for API compatibility, pass your originId value. Returns duplicate risk score and reasons. Separate from linkedId on identify.
Smart Signals
Computed server-side after geo lookup and visit history are known. Never returned in slim browser responses.
| Field | Description |
|---|---|
| bot | Automation detection; includes result (good/bad/unknown) and optional bot_info |
| vpn | VPN detection with confidence and method flags (timezone, relay, etc.) |
| proxy | Proxy type (residential, datacenter, tor) and confidence |
| tampering | Browser integrity signal |
| tamperingDetails | anomalyScore, antiDetectBrowser, plugin/WebGL mismatches |
| incognito | Private browsing detected in client signals |
| privacySettings | Privacy-hardened browser settings |
| developerTools | DevTools open at collection time |
| virtualMachine | VM environment heuristic (≥2 indicators) |
| locationSpoofing | Impossible travel, language-region mismatch, or mobile GPS vs IP |
| mitmAttack | TLS/UA interception: v1 heuristic or v2 TLS-corroborated (pro/enterprise) |
| mitmTlsCorroborated | True when mitmAttack used v2 edge TLS corroboration |
| velocity | Rolling 5m / 1h / 24h windows for IPs, countries, events, linkedId fanout |
| ipInfo | Geo, ASN, ISP, datacenter flags for IPv4/IPv6 |
| ipBlocklist | Tor, attack-source heuristics, email-spam lists |
| highActivityDevice | Percentile or absolute high-activity rules per project |
| mobile | Root/jailbreak/emulator/integrity fields (native SDKs; defaults on web) |
| sdk | platform and version of the collecting SDK |
Suspect score and risk level live on the event root (suspectScore, riskLevel, riskBreakdown) with breakdown dimensions: network, reputation, integrity, automation, identity, environment, trust.
bot_info: Web Bot Auth
Events API includes smartSignals.bot.info with Web Bot Auth (RFC 9421) verification. Verified agents upgrade to result: good; spoofed crypto failures force bad.
| Field | Description |
|---|---|
| result | good | bad | unknown | not_detected; verdict after server corroboration + Web Bot Auth |
| identity | signed | verified | unknown | spoofed; prefer over legacy bot field (Fingerprint v4) |
| category | ai_agent | ai_assistant | ai_browser | browser_automation | … |
| provider | Operator vendor, e.g. OpenAI, Google |
| name | Human-readable agent name, e.g. ChatGPT-User |
| type | Legacy compat; use category when present |
| verified | Legacy compat; true when identity is signed or verified |
| spoofed | Legacy compat; true when identity is spoofed |
Edge Automation Intelligence (no-JS)
On pro / enterprise plans, forward edge classification headers on identify when the JS agent is not used. OriginID persists the result in smartSignals.bot.info (same as Events GET and webhooks).
| Header | Description |
|---|---|
| x-df-bot-category | Agent category (pro/enterprise only); alias x-fingerprint-bot-category |
| x-df-bot-provider | Operator vendor |
| x-df-bot-name | Agent display name |
| x-df-bot-identity | signed | verified | unknown | spoofed |
High-activity device
Rolling 7d event counts per project in Valkey flag the top 0.2% of visitors (default 99.8 percentile) once a project has ≥1000 visitors. Override per API key via policy.highActivityPercentile. Nightly job: GET /api/cron/high-activity-percentile with CRON_SECRET.
Limiter presets
Starting-point rulesets for console import, Developer → Limiter → Import preset.
| Preset slug | Use case |
|---|---|
| signup-protection | Registration and checkout: blocks bots, tampering, and risky signups |
| analytics-marketing | Analytics and marketing: light protection, low friction |
| shared-devices | Kiosks and corporate fleets: extra guards for reused hardware |
Account takeover & fraud playbooks
Account takeover prevention, credential stuffing detection, visitor ban enforcement, and bot detection API patterns — decide on your server after Events GET.
Install the SDK, call identify, send eventId to your backend, then GET /api/events/:eventId with a secret sk_… key before you allow, challenge, or block. Never trust browser slim fields for fraud decisions. Example thresholds below are illustrative only — tune them in your policy; they are not product defaults. Optional: apply the same rules to webhook identify.succeeded payloads.
| Playbook | Trigger | Example policy (tunable) |
|---|---|---|
| Account takeover prevention | Login success | Block bad bots; step-up MFA on new originId + confidence < 90; challenge linkedId visitor velocity |
| Credential stuffing detection | Login attempt (incl. failures) | Block bad bots; friction on high suspectScore; rate-limit velocity bursts; optional proxy/VPN friction |
| Visitor ban enforcement | Identify / sensitive action | Persist banned originId in your DB; deny when Events GET originId matches |
Account takeover prevention
Stop account takeover after login succeeds: fetch Events GET, block bad bots, step up MFA when a new originId arrives with low confidence, and challenge linkedId visitor velocity before issuing a full session.
Credential stuffing detection
Defend every login attempt — including failures — with bot detection API signals, high suspectScore friction, and velocity rate limits. Never trust a client originId alone for online fraud detection.
Visitor ban enforcement
Enforce visitor bans with fraud detection fingerprinting: resolve originId from Events GET, look it up in your customer-owned ban store, and deny sensitive actions. Bans are browser-scoped.
VPN and proxy friction examples remain optional while hosted IP intelligence runs in vendor mode (fixture-backed until live minFraud credentials).
Webhooks
Async delivery after each successful identify, full Events JSON, not slim SDK shape.
Register HTTPS endpoints in the dashboard (Developer → Webhooks). Envelope type identify.succeeded with data matching Events GET. Delivery is at-least-once with up to 5 retries; dedupe on webhook id within 72 hours.
Verify X-OriginID-Signature
- Read raw POST body bytes before JSON parsing.
- Parse t and v1 from X-OriginID-Signature (format: t={unix},v1={hex_hmac_sha256}).
- Reject if |now - t| > 300 seconds.
- Compute HMAC-SHA256 over {t}.{rawBody} using your endpoint signing secret.
- Compare v1 to the hex digest using constant-time comparison.
webhook-handler.ts
// Verify X-OriginID-Signature on incoming webhook POST
const rawBody = await request.text();
const header = request.headers.get("X-OriginID-Signature") ?? "";
const t = header.match(/t=(\d+)/)?.[1];
const v1 = header.match(/v1=([a-f0-9]+)/)?.[1];
if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) {
return new Response("stale", { status: 401 });
}
const expected = hmacSha256Hex(signingSecret, `${t}.${rawBody}`);
if (!timingSafeEqual(v1, expected)) {
return new Response("invalid", { status: 401 });
}Fingerprint migration
Industry-shaped JSON export and threshold migration notes for teams moving adapters.
Confidence threshold mapping
| Fingerprint (0–1) | OriginID native (0–100) |
|---|---|
| 1.0 | 100 |
| 0.95 | 95 |
| 0.90 | 90 |
| 0.70 | 70 |
Use ?format=fingerprint on identify and Events GET for adapter-compatible JSON. Map visitor_id → originId; confidence is 0–100 in native JSON and 0–1 in Fingerprint export.
fingerprint-export.ts
// Migration: Fingerprint-compatible JSON on Events GET
const res = await fetch(
`https://api.digitalfingerprintjs.com/api/events/${eventId}?format=fingerprint`,
{ headers: { Authorization: `Bearer ${SECRET_KEY}` } }
);
const fp = await res.json();
// fp.visitor_id → originId; fp.confidence.score is 0–1Go live
DigitalFingerprint hosts identify, enrichment, and the console, point your SDK and backend at the production API.
Production endpoints
| Surface | URL | Purpose |
|---|---|---|
| Console | https://dashboard.digitalfingerprintjs.com | API keys, allowed hostnames, Limiter, webhooks, visitor timeline |
| Identify | https://api.digitalfingerprintjs.com/api/identify | Browser POST: signal collection, match, and enrich |
| Events | https://api.digitalfingerprintjs.com/api/events/:eventId | Server GET: smart signals, suspect score, confidence, ruleAction, deviceReputation |
| Device reputation (DRN) | https://api.digitalfingerprintjs.com/api/drn/:originId | Server GET: cluster-level suspect score rollup + timestamps (secret key) |
| Account link | https://api.digitalfingerprintjs.com/api/account-link | Server POST: duplicate registration scoring at signup |
Browser traffic posts to https://api.digitalfingerprintjs.com/api/identify. Your backend fetches enrichment from https://api.digitalfingerprintjs.com/api/events/:eventId with the same secret API key. Do not POST identify to the marketing apex; digitalfingerprintjs.com/api/* is GET-only.
Secrets and configuration
| Item | Where to get it |
|---|---|
| Public API key | pk_… from console → browser OriginID.init apiKey (hostname-bound) |
| Secret API key | sk_… from console → server Authorization: Bearer on Events GET only |
| Ruleset ID | Optional public ruleset id from Limiter → ?ruleset_id on Events GET |
| Webhook secret | Per-endpoint signing secret from Developer → Webhooks |
Production checklist
Complete before production cutover.
- Public browser key (pk_…) on identify; secret server key (sk_…) on Events GET
- Browser SDK endpoint: https://api.digitalfingerprintjs.com/api/identify (not marketing apex; apex /api/* is GET 301 only)
- Install via npm @digitalfingerprintjs/client or official CDN cdn.digitalfingerprintjs.com
- Before production traffic (optional): Settings → Subdomains for first-party identify proxy; allowlist site hostname (SITE_ORIGIN)
- Allowed hostnames configured on each public API key (site host required when using a first-party proxy)
- No platform ORIGINID_SECRET / signingSecret in frontend JS (public keys use platform-managed integrity)
- Slim response verified; no smartSignals in browser payloads
- Backend tested: identify → eventId → GET /api/events/:eventId (and PATCH linkedId/tags when needed) with secret key
- Optional: GET /api/drn/:originId for global device reputation (secret key)
- Confidence thresholds migrated (Fingerprint 0–1 → OriginID 0–100)
- Sensitive actions use identifyOnDemand: true + Events GET (not cached browser identify)
- Production security review checklist completed
Changelog
- NewGoogle Tag Manager
Import DigitalFingerprint template.tpl into GTM — Start and identify without redeploying your site. Results push to dataLayer as DigitalFingerprintResult (do not send originId to Google Analytics).
- NewGlobal device reputation (DRN)
GET /api/drn/:originId and Events deviceReputation — Fingerprint-style cluster rollups across orgs while metrics stay per-tenant.
- NewWeb Bot Auth verification
bot_info.verified and bot_info.spoofed on Events GET with RFC 9421 Ed25519 signature validation for AI agents and search bots.
- NewHosted identify platform
Fully managed identify, Events API, and console at api.digitalfingerprintjs.com with no infrastructure to deploy on your side.
- UpdateConfidence v2
Confidence v2 on all new visits: merge false-positive risk scale, linkConfidence, fusion penalties, high-activity cap.
- BreakingSDK 1.0: default clientToken seeding
SDK auto-seeds first-party clientToken on init (Fingerprint parity). bootstrapToken config removed.
- UpdateLimiter on identify
Enabled rulesets auto-enforce on POST /api/identify; Events GET supports inline ?ruleset_id evaluation.
- UpdateRules presets
Importable Analytics & marketing, Signup & fraud protection, and Shared & corporate devices ruleset templates.
- UpdateProduction trust model
Production API keys default to slim browser responses; fraud fields via Events GET or webhooks.
- InfoDigitalFingerprint branding
Public product name DigitalFingerprint; SDK class OriginID (@digitalfingerprintjs/client); visitor identifier originId.
Ready to integrate?
Create a project in the console, copy your API key, and follow the quick start guide above.
