@ianmenethil/zp-devicefp 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -103
- package/dist/cdn/zp.dfp.esm.js +294 -84
- package/dist/cdn/zp.dfp.js +287 -84
- package/dist/cdn/zp.dfp.manifest.json +17 -17
- package/dist/cdn/zp.dfp.min.js +1 -1
- package/dist/cdn/zp.dfp.obf.js +1 -1
- package/dist/npm/index.cjs +301 -84
- package/dist/npm/index.d.ts +21 -8
- package/dist/npm/index.mjs +294 -84
- package/docs/api-reference.md +520 -472
- package/docs/architecture.md +171 -40
- package/docs/privacy.md +20 -20
- package/docs/signals.md +425 -383
- package/docs/testing.md +54 -32
- package/package.json +3 -3
package/docs/signals.md
CHANGED
|
@@ -1,383 +1,425 @@
|
|
|
1
|
-
# Signal Reference
|
|
2
|
-
|
|
3
|
-
Every signal collected by the library, including its name, tier, sync support, description, and the shape of its `value` when `status` is `'ok'`.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Signal overview
|
|
8
|
-
|
|
9
|
-
| # | Signal | Tier | Sync | Description |
|
|
10
|
-
|---|--------|------|------|-------------|
|
|
11
|
-
| 1 | `ua` | core | yes | Legacy `navigator.userAgent` and related properties |
|
|
12
|
-
| 2 | `uaHints` | core | no | User-Agent Client Hints (brands, platform, high-entropy values) |
|
|
13
|
-
| 3 | `locale` | core | yes | Language, locale, calendar, time zone, number/date formatting |
|
|
14
|
-
| 4 | `screen` | core | yes | Screen dimensions, color depth, orientation, DPR, media queries |
|
|
15
|
-
| 5 | `hardware` | core | yes | Hardware concurrency, device memory, platform |
|
|
16
|
-
| 6 | `storage` | core | yes | localStorage, sessionStorage, IndexedDB, Web SQL availability |
|
|
17
|
-
| 7 | `fonts` | core | yes | Installed font detection via DOM measurement |
|
|
18
|
-
| 8 | `canvas` | core | yes | Canvas 2D rendering fingerprint (GPU+driver signature) |
|
|
19
|
-
| 9 | `webgl` | core | yes | WebGL renderer, vendor, extensions, GPU capabilities |
|
|
20
|
-
| 10 | `audio` | core | no | OfflineAudioContext oscillator+compressor signature |
|
|
21
|
-
| 11 | `mediaDevices` | extended | no | Media device kind enumeration (counts only, no labels) |
|
|
22
|
-
| 12 | `permissions` | extended | no | Permissions API state for geolocation, notifications, camera, microphone |
|
|
23
|
-
| 13 | `webrtc` | extended | no | RTCPeerConnection codec and extmap capability hash |
|
|
24
|
-
| 14 | `frameInfo` | extended | yes | Iframe context: count, domains, top-level check |
|
|
25
|
-
| 15 | `networkInfo` | extended | yes | NetworkInformation API: effective type, downlink, RTT, saveData |
|
|
26
|
-
| 16 | `paymentSupport` | extended | yes | PaymentRequest API availability |
|
|
27
|
-
| 17 | `referrerInfo` | extended | yes | `document.referrer` |
|
|
28
|
-
| 18 | `navigationInfo` | extended | yes | PerformanceNavigationTiming type (navigate/reload/back_forward/prerender) |
|
|
29
|
-
| 19 | `riskSignals` | extended | no | Bot/headless detection: 9 heuristics |
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
1
|
+
# Signal Reference
|
|
2
|
+
|
|
3
|
+
Every signal collected by the library, including its name, tier, sync support, description, and the shape of its `value` when `status` is `'ok'`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Signal overview
|
|
8
|
+
|
|
9
|
+
| # | Signal | Tier | Sync | Description |
|
|
10
|
+
|---|--------|------|------|-------------|
|
|
11
|
+
| 1 | `ua` | core | yes | Legacy `navigator.userAgent` and related properties |
|
|
12
|
+
| 2 | `uaHints` | core | no | User-Agent Client Hints (brands, platform, high-entropy values) |
|
|
13
|
+
| 3 | `locale` | core | yes | Language, locale, calendar, time zone, number/date formatting |
|
|
14
|
+
| 4 | `screen` | core | yes | Screen dimensions, color depth, orientation, DPR, media queries |
|
|
15
|
+
| 5 | `hardware` | core | yes | Hardware concurrency, device memory, platform |
|
|
16
|
+
| 6 | `storage` | core | yes | localStorage, sessionStorage, IndexedDB, Web SQL availability |
|
|
17
|
+
| 7 | `fonts` | core | yes | Installed font detection via DOM measurement |
|
|
18
|
+
| 8 | `canvas` | core | yes | Canvas 2D rendering fingerprint (GPU+driver signature) |
|
|
19
|
+
| 9 | `webgl` | core | yes | WebGL renderer, vendor, extensions, GPU capabilities |
|
|
20
|
+
| 10 | `audio` | core | no | OfflineAudioContext oscillator+compressor signature |
|
|
21
|
+
| 11 | `mediaDevices` | extended | no | Media device kind enumeration (counts only, no labels) |
|
|
22
|
+
| 12 | `permissions` | extended | no | Permissions API state for geolocation, notifications, camera, microphone |
|
|
23
|
+
| 13 | `webrtc` | extended | no | RTCPeerConnection codec and extmap capability hash |
|
|
24
|
+
| 14 | `frameInfo` | extended | yes | Iframe context: count, domains, top-level check |
|
|
25
|
+
| 15 | `networkInfo` | extended | yes | NetworkInformation API: effective type, downlink, RTT, saveData |
|
|
26
|
+
| 16 | `paymentSupport` | extended | yes | PaymentRequest API availability |
|
|
27
|
+
| 17 | `referrerInfo` | extended | yes | `document.referrer` |
|
|
28
|
+
| 18 | `navigationInfo` | extended | yes | PerformanceNavigationTiming type (navigate/reload/back_forward/prerender) |
|
|
29
|
+
| 19 | `riskSignals` | extended | no | Bot/headless detection: 9 heuristics |
|
|
30
|
+
| 20 | `adblock` | extended | no | Ad blocker detection via DOM bait element |
|
|
31
|
+
| 21 | `geolocation` | extended | no | Geographic coordinates via Geolocation API |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Core signals
|
|
36
|
+
|
|
37
|
+
### `ua` — User-Agent string
|
|
38
|
+
|
|
39
|
+
**Tier:** core | **Sync:** yes | **APIs used:** `navigator`
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// value shape:
|
|
43
|
+
{
|
|
44
|
+
userAgent: string; // navigator.userAgent
|
|
45
|
+
appVersion: string; // navigator.appVersion
|
|
46
|
+
vendor: string; // navigator.vendor
|
|
47
|
+
platform: string; // navigator.platform
|
|
48
|
+
webdriver: boolean; // navigator.webdriver
|
|
49
|
+
maxTouchPoints: number; // navigator.maxTouchPoints
|
|
50
|
+
cookieEnabled: boolean; // navigator.cookieEnabled
|
|
51
|
+
vendorSub: string; // navigator.vendorSub
|
|
52
|
+
doNotTrack: string | null; // navigator.doNotTrack ("1", "0", "unspecified", or null)
|
|
53
|
+
plugins: string[]; // navigator.plugins mapped to "name::description::filename"
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Returns `'unsupported'` if `navigator` is not available.
|
|
58
|
+
|
|
59
|
+
### `uaHints` — User-Agent Client Hints
|
|
60
|
+
|
|
61
|
+
**Tier:** core | **Sync:** no | **APIs used:** `navigator.userAgentData`
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// value shape:
|
|
65
|
+
{
|
|
66
|
+
brands: { brand: string; version: string }[]; // low-entropy brands
|
|
67
|
+
mobile: boolean; // userAgentData.mobile
|
|
68
|
+
platform: string; // userAgentData.platform
|
|
69
|
+
architecture?: string; // high-entropy: CPU architecture
|
|
70
|
+
bitness?: string; // high-entropy: 32/64
|
|
71
|
+
formFactors?: string[]; // high-entropy: device form factors
|
|
72
|
+
fullVersionList?: { brand: string; version: string }[]; // high-entropy: full versions
|
|
73
|
+
model?: string; // high-entropy: device model
|
|
74
|
+
platformVersion?: string; // high-entropy: OS version
|
|
75
|
+
wow64?: boolean; // high-entropy: 32-bit on 64-bit
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Returns `'unsupported'` if `navigator.userAgentData` is not available. Returns `'blocked'` if `getHighEntropyValues` throws.
|
|
80
|
+
|
|
81
|
+
### `locale` — Language and internationalization
|
|
82
|
+
|
|
83
|
+
**Tier:** core | **Sync:** yes | **APIs used:** `navigator`, `Intl`
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
// value shape:
|
|
87
|
+
{
|
|
88
|
+
language: string; // navigator.language
|
|
89
|
+
languages: readonly string[]; // navigator.languages
|
|
90
|
+
locale: string; // Intl.DateTimeFormat resolved locale
|
|
91
|
+
calendar: string; // e.g. "gregory", "iso8601"
|
|
92
|
+
numberingSystem: string; // e.g. "latn", "arab"
|
|
93
|
+
timeZone: string; // IANA timezone e.g. "America/New_York"
|
|
94
|
+
hourCycle: string; // e.g. "h12", "h23"
|
|
95
|
+
timeZoneOffsetMinutes: number; // UTC offset in minutes
|
|
96
|
+
formattedNumber: string; // Intl.NumberFormat sample: "123,456.789"
|
|
97
|
+
formattedDate: string; // Intl.DateTimeFormat sample for Jan 2, 2024
|
|
98
|
+
formattedRelativeDay: string | undefined; // Intl.RelativeTimeFormat: "yesterday" etc.
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Returns `'unsupported'` if `navigator` or `Intl` is not available.
|
|
103
|
+
|
|
104
|
+
### `screen` — Screen and display
|
|
105
|
+
|
|
106
|
+
**Tier:** core | **Sync:** yes | **APIs used:** `screen`, `navigator`, `matchMedia`, `devicePixelRatio`
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// value shape:
|
|
110
|
+
{
|
|
111
|
+
width: number; // screen.width
|
|
112
|
+
height: number; // screen.height
|
|
113
|
+
availWidth: number; // screen.availWidth
|
|
114
|
+
availHeight: number; // screen.availHeight
|
|
115
|
+
colorDepth: number; // screen.colorDepth
|
|
116
|
+
pixelDepth: number; // screen.pixelDepth
|
|
117
|
+
orientationType: string; // screen.orientation.type
|
|
118
|
+
orientationAngle: number; // screen.orientation.angle
|
|
119
|
+
maxTouchPoints: number; // navigator.maxTouchPoints (0 if missing)
|
|
120
|
+
devicePixelRatio: number | undefined; // window.devicePixelRatio
|
|
121
|
+
fakedResolution: boolean; // true if availWidth/Height exceeds screen.width/height (FP2 has_lied_resolution)
|
|
122
|
+
ccaScreenSize: string; // Cardinal Commerce outerWidth/outerHeight bucket ('01'–'04')
|
|
123
|
+
colorGamutP3: boolean | 'unsupported'; // (color-gamut: p3) media query
|
|
124
|
+
prefersReducedMotion: boolean | 'unsupported'; // (prefers-reduced-motion: reduce)
|
|
125
|
+
prefersContrastMore: boolean | 'unsupported'; // (prefers-contrast: more)
|
|
126
|
+
forcedColorsActive: boolean | 'unsupported'; // (forced-colors: active)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Returns `'unsupported'` if `screen` is not available.
|
|
131
|
+
|
|
132
|
+
### `hardware` — Hardware properties
|
|
133
|
+
|
|
134
|
+
**Tier:** core | **Sync:** yes | **APIs used:** `navigator`
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
// value shape:
|
|
138
|
+
{
|
|
139
|
+
hardwareConcurrency: number; // navigator.hardwareConcurrency (logical CPU cores)
|
|
140
|
+
deviceMemory: number | undefined; // navigator.deviceMemory (GB, may be undefined)
|
|
141
|
+
platform: string; // navigator.platform
|
|
142
|
+
maxTouchPoints: number; // navigator.maxTouchPoints
|
|
143
|
+
touchEventCreationSuccessful: boolean; // document.createEvent('TouchEvent') succeeded
|
|
144
|
+
onTouchStartAvailable: boolean; // 'ontouchstart' in window
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Returns `'unsupported'` if `navigator` is not available.
|
|
149
|
+
|
|
150
|
+
### `storage` — Storage API availability
|
|
151
|
+
|
|
152
|
+
**Tier:** core | **Sync:** yes | **APIs used:** `localStorage`, `sessionStorage`, `indexedDB`, `openDatabase`, `navigator`
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// value shape:
|
|
156
|
+
{
|
|
157
|
+
cookiesEnabled: boolean; // navigator.cookieEnabled
|
|
158
|
+
localStorage: 'available' | 'blocked' | 'unsupported'; // write-read-delete probe
|
|
159
|
+
sessionStorage: 'available' | 'blocked' | 'unsupported'; // write-read-delete probe
|
|
160
|
+
indexedDb: 'available' | 'unsupported'; // typeof indexedDB check
|
|
161
|
+
openDatabase: 'available' | 'unsupported'; // typeof openDatabase check (Web SQL)
|
|
162
|
+
pdfViewerEnabled: boolean; // navigator.pdfViewerEnabled
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### `fonts` — Font detection
|
|
167
|
+
|
|
168
|
+
**Tier:** core | **Sync:** yes | **APIs used:** DOM (`document.createElement`, `offsetWidth`)
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
// value shape:
|
|
172
|
+
{
|
|
173
|
+
detectedFonts: string[]; // sorted list of detected font family names
|
|
174
|
+
fontCount: number; // count of detected fonts
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Tests 70 fonts against 3 generic families (monospace, sans-serif, serif) by rendering hidden `<span>` elements and measuring width differences. Returns `'unsupported'` if the DOM is not available.
|
|
179
|
+
|
|
180
|
+
**Font set:** matches the Fingerprint2 / Cardinal Commerce canonical font list (Andale Mono, Arial, Baskerville, Calibri, Comic Sans MS, Consolas, Courier New, Franklin Gothic Medium, Garamond, Georgia, Helvetica, Impact, Lucida Console, Meiryo, Monaco, MS Gothic, Palatino, Segoe UI, Symbol, Tahoma, Times New Roman, Trebuchet MS, Verdana, Wingdings, and 46 more).
|
|
181
|
+
|
|
182
|
+
### `canvas` — Canvas 2D fingerprint
|
|
183
|
+
|
|
184
|
+
**Tier:** core | **Sync:** yes | **APIs used:** Canvas 2D (`getContext('2d')`)
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
// value shape:
|
|
188
|
+
{
|
|
189
|
+
dataUrl: string; // canvas.toDataURL() — base64 PNG of rendered pattern
|
|
190
|
+
winding: boolean; // ctx.isPointInPath(1, 1, 'evenodd')
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Renders a 280×80 canvas with a filled rectangle (#f60), text ("Browser FP"), and an arc. Differences in GPU, driver, and browser anti-aliasing produce distinct fingerprints.
|
|
195
|
+
|
|
196
|
+
Returns `'unsupported'` if the canvas 2D context is unavailable. Returns `'error'` if rendering throws.
|
|
197
|
+
|
|
198
|
+
### `webgl` — WebGL fingerprint
|
|
199
|
+
|
|
200
|
+
**Tier:** core | **Sync:** yes | **APIs used:** WebGL (`getContext('webgl')`, `WEBGL_debug_renderer_info`)
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
// value shape:
|
|
204
|
+
{
|
|
205
|
+
vendor: string; // UNMASKED_VENDOR_WEBGL or VENDOR
|
|
206
|
+
renderer: string; // UNMASKED_RENDERER_WEBGL or RENDERER
|
|
207
|
+
version: string; // WebGL version string
|
|
208
|
+
shadingLanguageVersion: string; // GLSL version string
|
|
209
|
+
maxTextureSize: number; // MAX_TEXTURE_SIZE
|
|
210
|
+
maxViewportDims: Int32Array; // MAX_VIEWPORT_DIMS
|
|
211
|
+
extensions: string[]; // getSupportedExtensions() sorted
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Attempts `webgl` context first, falls back to `experimental-webgl`. Uses `WEBGL_debug_renderer_info` for unmasked GPU strings when available.
|
|
216
|
+
|
|
217
|
+
Returns `'unsupported'` if canvas/WebGL is not available.
|
|
218
|
+
|
|
219
|
+
### `audio` — AudioContext fingerprint
|
|
220
|
+
|
|
221
|
+
**Tier:** core | **Sync:** no | **APIs used:** `OfflineAudioContext`, `OscillatorNode`, `DynamicsCompressorNode`
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
// value shape:
|
|
225
|
+
{
|
|
226
|
+
sampleRate: number; // rendered.sampleRate
|
|
227
|
+
length: number; // rendered.length (number of sample frames)
|
|
228
|
+
signalValue: number; // sum of absolute channel data values (6 decimal places)
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Creates an OfflineAudioContext (1 channel, 5000 samples, 44100 Hz), plays a 10 kHz triangle wave through a DynamicsCompressor with tuned parameters, then sums the absolute values of the rendered output. Different audio hardware/drivers produce distinct values.
|
|
233
|
+
|
|
234
|
+
Returns `'unsupported'` if `OfflineAudioContext` (or `webkitOfflineAudioContext`) is not available. Returns `'blocked'` if rendering throws.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Extended signals
|
|
239
|
+
|
|
240
|
+
### `mediaDevices` — Media device enumeration
|
|
241
|
+
|
|
242
|
+
**Tier:** extended | **Sync:** no | **APIs used:** `navigator.mediaDevices.enumerateDevices`
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
// value shape — an object keyed by MediaDeviceKind:
|
|
246
|
+
{
|
|
247
|
+
audioinput: number; // count of audio input devices
|
|
248
|
+
audiooutput: number; // count of audio output devices
|
|
249
|
+
videoinput: number; // count of video input devices
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Only device counts and kinds are collected — no device labels or IDs. Requires a secure context (HTTPS) and a visible document.
|
|
254
|
+
|
|
255
|
+
Returns `'blocked'` if not in a secure context, if document is not visible, or if `enumerateDevices` throws. Returns `'unsupported'` if `mediaDevices` is not available.
|
|
256
|
+
|
|
257
|
+
### `permissions` — Permissions API state
|
|
258
|
+
|
|
259
|
+
**Tier:** extended | **Sync:** no | **APIs used:** `navigator.permissions.query`
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// value shape:
|
|
263
|
+
{
|
|
264
|
+
geolocation: 'granted' | 'denied' | 'prompt' | 'unsupported';
|
|
265
|
+
notifications: 'granted' | 'denied' | 'prompt' | 'unsupported';
|
|
266
|
+
camera: 'granted' | 'denied' | 'prompt' | 'unsupported';
|
|
267
|
+
microphone: 'granted' | 'denied' | 'prompt' | 'unsupported';
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Queries 4 permission names in parallel. Each individual query that fails returns `'unsupported'` for that key.
|
|
272
|
+
|
|
273
|
+
Returns `'unsupported'` if `navigator.permissions` is not available. Returns `'blocked'` if all queries fail together.
|
|
274
|
+
|
|
275
|
+
### `webrtc` — WebRTC codec capability
|
|
276
|
+
|
|
277
|
+
**Tier:** extended | **Sync:** no | **APIs used:** `RTCPeerConnection`
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
// value shape:
|
|
281
|
+
{
|
|
282
|
+
codecs: string[]; // sorted audio/video codec names from SDP rtpmap lines
|
|
283
|
+
extmaps: string[]; // sorted extmap IDs from SDP
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Creates an RTCPeerConnection, opens a data channel, generates an SDP offer, and parses supported codecs and extmap entries. The peer connection is closed after collection.
|
|
288
|
+
|
|
289
|
+
Returns `'unsupported'` if `RTCPeerConnection` (or `webkitRTCPeerConnection`) is not available. Returns `'blocked'` if SDP negotiation throws.
|
|
290
|
+
|
|
291
|
+
### `frameInfo` — Iframe context
|
|
292
|
+
|
|
293
|
+
**Tier:** extended | **Sync:** yes | **APIs used:** DOM, `window.top`
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
// value shape:
|
|
297
|
+
{
|
|
298
|
+
iframesCount: number; // count of <iframe> elements in the document
|
|
299
|
+
isTopLevel: boolean; // whether window === window.top
|
|
300
|
+
iframeDomains: string[]; // hostnames extracted from iframe src URLs
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Returns `'unsupported'` if `document` is not available. Returns `'error'` if enumeration throws.
|
|
305
|
+
|
|
306
|
+
### `networkInfo` — Network Information
|
|
307
|
+
|
|
308
|
+
**Tier:** extended | **Sync:** yes | **APIs used:** `navigator.connection` (vendor-prefixed)
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
// value shape:
|
|
312
|
+
{
|
|
313
|
+
effectiveType: string | null; // 'slow-2g' | '2g' | '3g' | '4g' | null
|
|
314
|
+
downlink: number | null; // estimated downlink speed in Mbps
|
|
315
|
+
rtt: number | null; // estimated round-trip time in ms
|
|
316
|
+
saveData: boolean | null; // data-saver mode
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Checks `navigator.connection`, `navigator.mozConnection`, and `navigator.webkitConnection` for the NetworkInformation API (Chrome, Firefox, older WebKit).
|
|
321
|
+
|
|
322
|
+
Returns `'unsupported'` if `navigator` or the connection API is not available.
|
|
323
|
+
|
|
324
|
+
### `paymentSupport` — PaymentRequest API
|
|
325
|
+
|
|
326
|
+
**Tier:** extended | **Sync:** yes | **APIs used:** `window.PaymentRequest`
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
// value shape:
|
|
330
|
+
{
|
|
331
|
+
paymentRequest: boolean; // whether PaymentRequest constructor exists
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### `referrerInfo` — Document referrer
|
|
336
|
+
|
|
337
|
+
**Tier:** extended | **Sync:** yes | **APIs used:** `document.referrer`
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
// value shape:
|
|
341
|
+
{
|
|
342
|
+
referrer: string; // document.referrer (empty string if no referrer)
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Returns `'unsupported'` if `document` is not available.
|
|
347
|
+
|
|
348
|
+
### `navigationInfo` — Navigation type
|
|
349
|
+
|
|
350
|
+
**Tier:** extended | **Sync:** yes | **APIs used:** `PerformanceNavigationTiming`
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
// value shape:
|
|
354
|
+
{
|
|
355
|
+
navigationType: string | number | null;
|
|
356
|
+
// 'navigate' | 'reload' | 'back_forward' | 'prerender' (modern)
|
|
357
|
+
// 0 | 1 | 2 | 255 (legacy performance.navigation.type)
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Prefers `PerformanceNavigationTiming.type`. Falls back to deprecated `performance.navigation.type` in older browsers.
|
|
362
|
+
|
|
363
|
+
Returns `'unsupported'` if `performance` is not available. Returns `'error'` if probing throws.
|
|
364
|
+
|
|
365
|
+
### `riskSignals` — Bot and headless detection
|
|
366
|
+
|
|
367
|
+
**Tier:** extended | **Sync:** no | **APIs used:** `navigator`, `Notification`, `Permissions`, `Performance`
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
// value shape:
|
|
371
|
+
{
|
|
372
|
+
webdriver: boolean | null; // navigator.webdriver flag
|
|
373
|
+
headlessHints: string[]; // detected headless indicators
|
|
374
|
+
uaConsistency: boolean | null; // UA platform vs UA-CH consistency
|
|
375
|
+
notificationPermission: string | null; // Notification.permission
|
|
376
|
+
permissionsHeadlessHint: boolean | null; // denied+default mismatch
|
|
377
|
+
timeToCaptureMs: number | null; // ms since navigation start
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### Headless hints checked
|
|
382
|
+
|
|
383
|
+
| Hint code | Trigger |
|
|
384
|
+
|-----------|---------|
|
|
385
|
+
| `headless-ua` | UA contains `"HeadlessChrome"` |
|
|
386
|
+
| `missing-chrome-object` | Chrome UA but `window.chrome` is not an object |
|
|
387
|
+
| `zero-outer-dimensions` | `outerWidth === 0` or `outerHeight === 0` |
|
|
388
|
+
| `no-plugins-on-desktop-chrome` | Chrome UA (non-mobile) but `navigator.plugins` is empty |
|
|
389
|
+
| `empty-languages` | `navigator.languages` is an empty array |
|
|
390
|
+
|
|
391
|
+
Returns `'unsupported'` if `navigator` is not available. Returns `'blocked'` if collection throws.
|
|
392
|
+
|
|
393
|
+
### `adblock` — Ad blocker detection
|
|
394
|
+
|
|
395
|
+
**Tier:** extended | **Sync:** no | **APIs used:** DOM (`document.createElement`, `offsetHeight`)
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
// value shape:
|
|
399
|
+
{
|
|
400
|
+
adblockEnabled: boolean; // true if a bait element was hidden/collapsed by an ad blocker
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Appends a `div` with ad-blocker-targeted class names (e.g. `adsbox`, `pub_300x250`) to the document body, waits 100 ms, then checks whether the element's dimensions collapsed to zero. The element is removed immediately after measurement.
|
|
405
|
+
|
|
406
|
+
Returns `'unsupported'` if `document` is not available or the DOM is not accessible.
|
|
407
|
+
|
|
408
|
+
### `geolocation` — Geographic coordinates
|
|
409
|
+
|
|
410
|
+
**Tier:** extended | **Sync:** no | **APIs used:** `navigator.geolocation`
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
// value shape:
|
|
414
|
+
{
|
|
415
|
+
latitude: number; // decimal degrees
|
|
416
|
+
longitude: number; // decimal degrees
|
|
417
|
+
accuracy: number; // radius in metres
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Calls `navigator.geolocation.getCurrentPosition()` with `timeout: timeoutMs` and `maximumAge: 60000`. The browser will prompt the user for permission on first use.
|
|
422
|
+
|
|
423
|
+
Returns `'unsupported'` if `navigator.geolocation` is absent (HTTP context or non-browser runtime).
|
|
424
|
+
Returns `'blocked'` when the user denies the permission prompt (`PERMISSION_DENIED`, error code 1).
|
|
425
|
+
Returns `'error'` for other geolocation failures (position unavailable, timeout from the Geolocation API itself).
|