---
title: Fingerprinting
description: "Device fingerprinting is how TrustLens identifies the actor behind a checkout request. Card-testing botnets routinely rotate IP addresses to evade simple IP-based rate limits, but they have a much harder time rotating the full set of browser and device characteristics…"
url: "https://webstepper.io/docs/trustlens/card-testing-defense/fingerprinting/"
updated: "2026-10-18"
category: Card Testing Defense
---

# Fingerprinting

Device fingerprinting is how TrustLens identifies the actor behind a checkout request. Card-testing botnets routinely rotate IP addresses to evade simple IP-based rate limits, but they have a much harder time rotating the full set of browser and device characteristics that make up a fingerprint. This page describes what TrustLens fingerprints, why those specific signals, and how the Pro tier extends the fingerprint with an additional layer.

---

## What's in the Fingerprint

Every checkout attempt carries two fingerprints.

### Browser fingerprint

A small script on the cart and checkout pages reads these signals in the shopper's browser:

| Signal | Why Useful |
| --- | --- |
| Canvas rendering | A small rendered canvas differs between browser/OS combinations due to font and rendering differences |
| Screen | Width, height, pixel ratio, and color depth — headless bots often have unusual values |
| Timezone | The browser's time zone — often mismatched on proxied bots |
| Language | The browser's preferred language |
| Platform | The operating system the browser reports |
| WebGL vendor and renderer | The graphics hardware and driver, which is hard to fake consistently |

The script hashes these signals in the browser with SHA-256 and sends only the resulting 22-character fingerprint with the checkout (as a hidden field on the classic checkout, or a request header on the Blocks checkout). The raw values never leave the browser.

### Server fingerprint

On the server, TrustLens also builds a fingerprint from the request's IP address, User-Agent, and Accept-Language headers, hashed with SHA-256. It is used on its own when the browser sends no fingerprint (JavaScript blocked, or a bot posting straight to the checkout endpoint), and it is always recorded alongside the browser fingerprint so that a bot rotating its browser fingerprint still accumulates declines against the server one.

---

## Pro: The 12-Font Signal

Pro adds a seventh browser signal: a 12-font detection check. The script measures how 12 common fonts render against the browser's default fonts and records which ones are installed, producing a per-system signature.

Why fonts: card-testing botnets are usually run on compromised hosts (residential proxies, virtual machines, hijacked browsers) where the attacker has limited control over installed software. The font set on each compromised host is whatever happens to be there — and replicating a target font set consistently across many botnet nodes is significantly harder than spoofing User-Agent strings.

The 12-font signal makes fingerprint collisions across botnet nodes much rarer, which means lockouts catch more attempts before the bot has time to switch fingerprints. It's added while Pro is licensed and Card-Testing Defense is on.

---

## How Stable Is the Fingerprint?

A legitimate customer's fingerprint is stable across multiple checkout attempts in the same session — same browser, same window, same device. It can change when:

- The customer switches browsers (Chrome → Firefox) — different canvas rendering, platform, and WebGL values
- The customer switches devices (laptop → phone) — every signal changes
- The customer moves the window to a different monitor — different screen values
- Browser update changes rendering — slightly different canvas output
- Operating system update — possibly different font set (Pro)

The server fingerprint changes whenever the IP address changes, for example when a phone moves between Wi-Fi and mobile data. For card-testing-defense purposes, this stability is sufficient. Legitimate customers rarely change devices mid-checkout-burst; attackers can change User-Agent strings but struggle to fake the full fingerprint consistently.

---

## What the Fingerprint Is Used For

| Use | Description |
| --- | --- |
| Velocity counters | Counts declines and submissions per fingerprint over rolling 60-second and 1-hour windows |
| Lockout enforcement | Holds the offending fingerprint for 90 seconds, escalating to 15 minutes, 1 hour, and 24 hours for repeat offenders |
| Customer scoring | A customer who submitted checkout from a device later caught card testing gets a −30 signal ("Linked to N device fingerprint(s) involved in a card-testing attack"), for as long as those velocity events are retained |
| 24-hour intelligence (Pro) | Top 10 attacking fingerprints displayed for forensic review |
| Allowlists (Pro) | The fingerprint allowlist accepts exact fingerprint hashes |

The card-testing fingerprint is separate from Linked Accounts. Linked Accounts records its own hashed identifiers per customer, and a shared IP or browser there never links two accounts on its own.

---

## Privacy

The browser signals are hashed in the shopper's browser and the server signals are hashed on arrival; the fingerprint tables store only hashes. Two things are worth knowing:

- **Fingerprints aren't keyed per store.** They are plain SHA-256 hashes, so the same browser produces the same fingerprint on any TrustLens store. TrustLens doesn't send card-testing fingerprints off your site.
- **Velocity events keep the IP address.** Each recorded submission keeps the request's IP address and, when the checkout carried one, the customer's email hash. Velocity events are deleted after the retention window (48 hours by default, 24–168 hours configurable).

Card-testing device fingerprints aren't tied to a customer's email, so they aren't part of WordPress's personal-data export and erasure tools; the velocity events that link a customer to a device expire with the retention window.

---

## Fingerprint Collisions

It's possible for two different devices to produce the same fingerprint — two users on the same browser version, same OS, same screen, same graphics hardware. Collisions are more likely on the server fingerprint, which is shared by everyone behind one office network or carrier address running the same browser. In practice:

- Free browser fingerprint (6 signals): collisions are uncommon but occur, especially among customers on identical setups (e.g. the same iPhone model)
- Pro browser fingerprint (7 signals including 12-font): collisions are rare

The defense design accounts for occasional collisions:

- The first lockout is short (90 seconds), so a colliding legitimate customer is delayed, not blocked; longer lockouts need repeat offenses
- Any held fingerprint can be released from the Targeted now list, which also clears its strikes and taint
- VIP bypass insulates established customers from collision effects
- Allowlisting (Pro) provides an explicit override

---

## Fingerprint Visibility

The fingerprint hash is visible in several admin contexts:

- **Card-Testing Defense → Targeted now** — each held fingerprint with its strike count, when it's held until, and a Release button
- **24-hour intelligence (Pro)** — top 10 attacking fingerprints with decline counts
- **CSV export (Pro)** — the fingerprint hash on every velocity event
- **Customer Detail** — no hash, but the card-testing signal on the score when one of the customer's checkout devices was caught

The hash is opaque — there's no way to decode it back to the raw inputs.

---

## Fingerprint Inputs Are Not Filterable

The set of signals that goes into a fingerprint is fixed by the plugin and is not exposed as a filter — this is deliberate. Changing the input set would invalidate all existing fingerprint state (lockouts, strikes, attack history), because previously-stored hashes were computed against the old inputs. If you need to react to card-testing detection in custom code, hook the `trustlens/card_testing/attack_detected` action instead (see the [Hooks & Filters Reference](/docs/trustlens/developer-documentation/trustlens-hooks-and-filters/)), which fires with the fingerprint hash and gate context whenever a fingerprint is newly targeted.

---

## What Fingerprints Don't Do

Worth being explicit about what the fingerprint is not:

- **Not biometric.** No fingerprint reader, no facial recognition. "Fingerprint" here is metaphor for device-and-browser identity.
- **Not tracking.** The fingerprint isn't used to track customers across the web — it only matches against requests *to your store*.
- **Not credential-based.** The customer doesn't need to be logged in. Fingerprints work for guest checkout.
- **Not deterministic identity.** Two customers can share a fingerprint if they have very similar setups — the fingerprint is one signal among many, not a sole identity proof.
