Doorman's defaults are a starting point. You can change how browser features are weighted, how much Jev contributes to matching, and the thresholds your application uses for extra verification. Configure these on your server; a browser request cannot override them.
These options configure the TypeScript createDoorman handler on Node, Vercel and Cloudflare. Native Elixir does not expose the same custom weight configuration; Python and Go clients use their upstream engine’s policy.
Import createDoorman from your server adapter. These settings change private similarity evidence. They never restore a guessed browser ID or authenticate a user in the recommended flow.
const doorman = createDoorman({
db,
secret: process.env.DOORMAN_IDENTITY_SECRET!,
namespace: "my-app",
evaluator: { apiKey: process.env.JEV_API_KEY! },
scoring: {
similarity: {
sameTimezone: 0.02,
viewportSimilarity: 0,
sameWebglRenderer: 0.16,
},
confidence: { deterministic: 0.6, evaluator: 0.4 },
candidateFloor: 0.65,
ambiguityMargin: 0.03,
},
});Unspecified similarity features retain their defaults. The combined weights are normalized to sum to one. A zero weight excludes that feature from the weighted match. Confidence weights are relative too: 60 and 40 mean the same as 0.6 and 0.4. Provide both confidence weights together.
| Feature | Default relative weight |
|---|---|
| Platform | 0.18 |
| Browser family | 0.12 |
| Timezone | 0.05 |
| Languages | 0.07 |
| Screen dimensions | 0.14 |
| Viewport dimensions | 0.02 |
| CPU concurrency | 0.10 |
| Device memory | 0.07 |
| Touch capabilities | 0.05 |
| WebGL vendor | 0.07 |
| WebGL renderer | 0.13 |
The exact keys are exported as SIMILARITY_WEIGHTS. Advanced callers can use calculateSimilarity(a, b, weights) or pass scoring to createVisitorEngine. resolveScoring returns a frozen, normalized snapshot suitable for recording with an experiment.
The default confidence blend remains 35% deterministic similarity and 65% Jev's sameVisitor. If evaluation fails or is disabled, Doorman uses deterministic similarity alone, regardless of blend settings. Weights do not turn off Jev calls; omit the evaluator to disable them. Known cookies still provide continuity without a global search.
Negative, non-finite, unknown and all-zero weights are rejected at construction. candidateFloor accepts 0.5–1; ambiguityMargin must be above 0 and at most 1; the normal matching safety checks remain active.
Safety checks remain active. Contradictory devices cannot match, saturated lookup buckets cannot support a confident historical match, and near ties need a positive margin. Evidence coverage still uses the default feature weights, including the 0.55 minimum coverage floor, so concentrating all weight on timezone cannot turn a sparse observation into confident identity. Changing weights never puts automation or abuse into identity matching.
Start with independently labeled traffic from your application. Split by time and user/session group, choose weights and thresholds on a validation set, then measure errors on a held-out set. Include keyboard-only, accessibility, privacy-browser, mobile and remote-desktop users. Record coverage and abstentions alongside false positives and missed agents.
Do not tune on the final test set or call a higher score an accuracy improvement. The public dataset results show why: matching can be wrong at high scores, and behavior classifiers vary by agent family. Risk policy stays application-owned; Doorman never blocks or challenges automatically.
scoring.similarity.fontSimilarity adds an optional relative weight for the fixed local-font set (default 0). It does not increase minimum evidence coverage or override contradiction/ambiguity caps. For example, 0.05 adds a modest contribution when both sets are available. Collection and limits.
activity.correlation.minConfidence controls which server-derived links contribute related activity (default 0.8, permitted range 0.5–1). This is separate from browser matching. Request-shape similarity alone is not abuse. Correlation guide.