Free preview

Velocity and Signals

In one line: the signal is almost never in the transaction itself — it is in how this transaction compares to the last hour, and that comparison has to include the transaction being scored.

Why a single transaction tells you little

A £200 purchase from a London address on a Visa card is unremarkable. It is unremarkable whether it is the customer's first purchase this year or their fifteenth in ten minutes.

Nearly all fraud signal is relational: relative to this account's history, relative to this card's recent activity, relative to what else this device has done. A transaction in isolation is close to uninformative, which is why a model trained only on transaction attributes performs poorly no matter the architecture.

Velocity features

Counts and sums over recent windows, computed across several entities.

EntityExample
CardAttempts in the last 10 minutes, distinct merchants in an hour
AccountTransactions today versus the 30-day average
DeviceDistinct accounts used in 24 hours
IP or subnetDistinct cards seen in an hour
Shipping addressDistinct accounts shipping here this week
Email domainNew signups in an hour

Some of these are the whole game. "How many distinct cards has this device attempted in the last hour" is close to a definition of card testing, and no per-transaction attribute captures it.

The requirement that shapes everything

The current transaction must be inside its own windows.

If an attacker makes a hundred attempts in sixty seconds, the hundredth is only detectable if the count includes the ninety-nine before it — including those from the last few seconds. A feature store refreshed every five minutes returns zero for all hundred, and the attack completes inside the staleness window.

This is the single most important architectural consequence in the chapter, and it is what makes fraud features different from recommendation features. A recommender's stale feature costs some relevance. A fraud system's stale velocity feature is the difference between catching an attack and not seeing it at all.

How that gets built

Three approaches, and most systems use all three at once.

Streaming aggregation. Events flow through a stream processor maintaining windowed counts in a fast store. The current event is written and read within the request. Good freshness, and it needs the write to land before the read — which is a real ordering constraint in a distributed system, not a detail.

In-request computation. Read the recent event log for these entities and aggregate on the fly. Perfectly fresh by construction, and the cost is a read per entity per request, which limits how many windows you can afford.

Sketches for the expensive ones. Distinct-count questions — how many unique cards has this IP seen — are memory-hungry exactly. A HyperLogLog sketch answers them approximately in constant space, and approximate is fine because the decision boundary is "unusually many" rather than a specific number.

The usual split: streaming aggregation for the standard windows, in-request computation for the few entities where absolute freshness matters most, and sketches for high-cardinality distinct counts.

Choosing windows

Multiple windows per entity, because attacks have different timescales.

Minutes catch bursts — card testing, credential stuffing. Hours catch a session-scale campaign. Days and weeks establish what normal looks like for this account, which is what makes a deviation meaningful.

The most useful features are usually ratios between windows rather than raw counts: this hour's activity divided by the trailing weekly average. A raw count of ten is meaningless without knowing whether this account normally does one or a hundred, and the ratio carries that normalisation for free.

Device and behavioural signals

The other family, and it is the one that survives when the transaction attributes are all legitimate.

Device fingerprinting — a stable identifier assembled from browser, hardware and network characteristics. Valuable because a fraudster reuses infrastructure across many attempts. Fragile, because it can be spoofed and it degrades as browsers restrict the signals available.

Behavioural biometrics — typing rhythm, mouse movement, how the form was filled, whether the card number was typed or pasted. Excellent for account takeover, because it distinguishes this person from someone with the correct credentials. A field completed by paste when this user always types is a genuine signal.

Network signals — proxy or VPN indicators, hosting-provider address ranges, mismatches between claimed and inferred location.

The reason these matter: in account takeover every transaction attribute is legitimate. Right account, right password, plausible purchase. The only thing that differs is how the session behaves, so behavioural signal is the whole detection.

The signals that are traps

Three, and avoiding them is a fairness point as much as an accuracy one.

Raw geography. Blocking by country is crude, correlates with legitimate customers, and is trivially bypassed with a proxy. A location mismatch is a signal; a location is not.

Anything strongly correlated with a protected characteristic. Name patterns, address neighbourhoods, inferred demographics. Beyond the legal exposure, these are proxies rather than causes, so they generalise badly and fail the moment fraud shifts population.

Attributes the fraudster chooses freely. Email address format, stated name, self-declared details. These are costless to change, so any pattern you learn is one the attacker can step around immediately. The durable signals are the ones that are expensive for the attacker to vary — device, network infrastructure, behavioural habit, the pattern across many attempts.

That last criterion is the useful filter, and it is worth stating as a principle: prefer signals the attacker cannot cheaply change. It explains why velocity and graph structure survive while string patterns do not.

Key takeaway

Fraud signal is relational, so the features are velocity counts over windows — and the transaction being scored must be inside its own windows, which rules out a batch feature store for this part of the design. Prefer ratios between windows over raw counts, and prefer signals that are expensive for the attacker to vary: device, network and behaviour survive, while anything the fraudster types is a pattern they can step around the day you deploy it.

Next: what else shares this identifier.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue