Fraud rings hide in relationships, so score the relationships. Build a graph of accounts, devices, cards, and beneficiaries linked by shared usage and money movement. Compute features over it, such as shared-device counts, component size, and distance to a known bad node, then feed them to the scorer you already run. That surfaces coordinated fraud a per-transaction model reads as clean.
Fraud rarely acts alone. A single mule account looks unremarkable on its own row, but it shares a device with four others, funds through the same prepaid card, and cashes out to an address three accounts already used. Per-transaction scoring reads each of those events in isolation and finds nothing worth declining. A graph reads the connections between them and finds a ring. That is the whole argument for graph methods in one paragraph: the signal is in the edges, not the rows.
The catch is that most fraud stacks are built to score rows. A model takes the transaction, joins some features about the card and the customer, and returns a number. It never asks who else touches the same phone, the same IP block, the same beneficiary. So the coordinated fraud, which is the expensive kind, walks straight through. Adding a graph layer is how you get the model to see the structure it was blind to.
What a fraud graph actually is
Before any modelling, you decide what the nodes and edges are. This is a modelling choice, and a bad one poisons everything downstream. The usual shape:
- Nodes are entities: customers, accounts, devices, cards, phone numbers, email addresses, physical and IP addresses, beneficiaries.
- Edges are shared usage or money movement: this account logged in from this device, this card funded this account, this transaction paid this beneficiary.
- Both carry timestamps, because a fraud graph is a temporal object and every edge has a moment it came into existence.
Two problems dominate at this stage. The first is entity resolution. If the same device shows up as three slightly different fingerprints, or one person’s two emails never get linked, your graph fragments and the ring falls apart into unconnected pieces. Graph fraud detection is only as good as the entity resolution underneath it, and that work usually costs more than the modelling. The second is the supernode problem. A shared corporate NAT address or a popular funding processor connects millions of legitimate accounts, and if you leave it in as an edge, everything looks related to everything. You either drop those high-degree hubs, weight them down, or split them by time window. Left unhandled, they generate false-positive rings that bury your analysts.
Graph features before graph neural networks
You do not start with a GNN. You start by computing metrics over the graph and feeding them to the scorer you already run. This gets most of the value with a fraction of the risk, and it keeps the audit trail legible.
Features that pull their weight:
- Degree and shared-attribute counts: how many accounts share this device, this beneficiary, this address, in a given window.
- Connected-component size: the ring the entity sits in, and how fast that component grew.
- Distance to a known bad node: how many hops from this account to a previously confirmed fraud entity.
- Community labels from a partition of the graph, so accounts in a dense cluster carry the cluster’s risk.
The discipline that makes or breaks this is point-in-time correctness. You have to build every feature against the graph as it stood when the transaction happened, not as it stands now. Reconstruct “shared-device count” over today’s graph and you fold in edges that only appeared after the fraud was caught, which is lookahead leakage in its purest form. The offline numbers will be spectacular and production will fall flat. Timestamp every edge, snapshot the graph at decision time, and hold an eval set that respects the same cutoff. Then measure lift over your row-based baseline honestly, because graph features are expensive to serve and they have to earn the latency they add.
Where GNNs actually help
A graph neural network learns representations by passing messages along edges: each node’s vector is updated from its neighbours’, repeatedly, so structure a few hops out gets folded into the node’s own embedding. That is genuinely more expressive than the hand-built counts above. It picks up patterns you did not think to name, and it captures the shape of a neighbourhood rather than a fixed list of aggregates. On coordinated fraud with rich connectivity, that expressiveness is real.
It also brings real costs, and I would not reach for it first.
- Labels are scarce and biased. You only have confirmed-fraud labels for the rings you already caught, so a supervised GNN learns the fraud you were already finding. Blend in unsupervised structure and treat the labels as partial.
- Temporal leakage is easier to introduce and harder to spot, because message passing pulls in neighbour information that may postdate the transaction. Your snapshotting has to be airtight.
- Explanation is harder. When a boosted tree declines a payment you can point at “shares a device with four flagged accounts.” When a GNN declines it, you owe the investigator, and eventually a regulator, a reason that holds up, so you need subgraph-level explanations wired in from the start.
- Serving is heavier. Real-time inference over a live graph is a different operational problem than a key-value feature lookup, and often the right answer is to precompute embeddings in batch and refresh them on a schedule.
The pattern that tends to hold up: run graph features through your existing scorer for the real-time decision, and run heavier graph analysis, GNN embeddings and community detection in a slower loop that feeds investigations and updates the watchlists the fast path reads from. The ring does not have to be caught on the first transaction. It has to be caught before it cashes out, and a graph is what lets you see it forming.
FAQ
Do I need a graph database to do graph fraud detection?
For investigation and link analysis, a graph database earns its keep because analysts want to traverse relationships interactively. For features that feed a scorer, you can precompute graph metrics in batch and serve them from a feature store, and many teams never run a live graph engine in the authorization path at all.
How do I build point-in-time-correct graph features?
Timestamp every edge and reconstruct the graph as it stood at the moment of the transaction you are labelling. If you compute a shared-device count over the graph as it looks today, you leak future edges into a past decision, and your offline metrics will look far better than production ever will.
When is a GNN worth it over hand-built graph features?
When the fraud pattern lives in structure your features do not name, and when you have enough confirmed labels to train on. If a handful of aggregate metrics like shared-attribute counts and component size already separate rings well, a GNN adds cost and explanation burden for little lift. Try the features first.