SynapCores

Fraud Detection: Machine Learning vs Graph Analytics (and Why You Need Both)

Published on October 18, 2026

Watch: Fraud Detection with Machine Learning Misses This (Graph Fix)

Machine-learning fraud detection has a blind spot built into how it works: it scores one row at a time. That's exactly right for the lone fraudster, whose payments are huge, at 3am, from abroad. It's useless against a fraud ring: five accounts that each spend like a normal customer, but share one phone and a couple of stolen card numbers.

The ring doesn't live in any row. It lives in the connections between rows. Here's a worked example, with real numbers from a demo you can run yourself.

The setup: 40 ordinary accounts, one lone fraudster, one hidden ring

  • 123 transactions. Every account makes three ordinary payments ($20–$199, daytime, domestic).
  • One lone fraudster. Account ACC-33 also makes three large 3am cross-border payments.
  • One ring. Accounts ACC-11 to ACC-15 behave exactly like everyone else, but they're linked: they share two devices and two card numbers in a chain.
  • One confirmed chargeback, on ACC-13.

No fraud labels anywhere.

Step 1: the machine learning view (it works, partly)

Train an isolation forest, an unsupervised anomaly model, on amount, hour and cross-border flag, then score every transaction:

SELECT tx_id, account_id, amount,
       ANOMALY_SCORE('recipe_ring_model', amount, hour_of_day, cross_border) AS score
FROM recipe_ring_tx
ORDER BY score DESC
LIMIT 10;

The result is what the model is good at: ACC-33's three 3am payments come out on top at ~0.82. Then the scores drop off a cliff. Every one of the 15 ring payments lands between 0.45 and 0.51, the same band as honest customers.

The model did its job. It just can't see the ring, because the ring was designed to look normal one row at a time.

Step 2: the graph view (one hop at a time)

Model the same data as a graph: accounts, devices and cards as nodes, and "used" relationships between them. Then start from the one thing you know for sure, the chargeback on ACC-13, and walk outward:

MATCH p = (s:Account {id: 'ACC-13'})-[*2..4]-(x:Account)
WHERE x.id <> 'ACC-13'
RETURN x.id AS linked_account, [n IN nodes(p) | n.id] AS via
ORDER BY length(p);

In under a millisecond it returns ACC-12 and ACC-14 (shared card and device), then ACC-11 and ACC-15 one step further out, each with the exact path that links it. A household pair that shares one device but nothing with the ring is correctly left out.

One seed, the whole ring: four accounts the model rated normal.

Step 3: one review queue

Neither signal alone is enough. Merge them: accounts the model flags plus accounts linked to a confirmed fraud. That gives the analyst six accounts to review, with the reason for each, instead of 40.

Why the "both" part matters

Anomaly model (ML) Graph traversal
Catches Unusual behaviour: amount, time, location Collusion: shared devices, cards, addresses
Misses Rings that look normal row by row Fraudsters with no links to known fraud
Needs labels? No (isolation forest) No (one seed)
Output A score per transaction The accounts and the path linking them

Most fraud stacks run these in separate systems: a feature pipeline and a model server for ML, a graph database for links, and a sync job between them. In SynapCores both run in the same engine, against the same tables: ANOMALY_SCORE() in a SQL SELECT, and the traversal in Cypher.

The honest limits

  • Graph traversal needs a seed. No confirmed fraud means nothing to start from. Shared-infrastructure counts can surface candidates, but that's evidence, not proof.
  • A link isn't guilt. Families share devices. Treat graph hits as a review queue, not an automatic block.
  • Thresholds are yours to calibrate. 0.7 worked on this data. Look at your own score distribution before you set one.

Watch it, then run it

The video above walks through every step live. To run the exact demo (about 12 minutes, free, no AI model or labels needed):

  1. Download the free Community Edition.
  2. Follow the recipe: Fraud rings your ML model misses.

Related: Neo4j vs PostgreSQL for multi-hop queries · Anomaly detection in SQL · Fraud ring detection with cycles