Manage risk

Fraud detection on a graph

Individually, every account in a fraud ring looks fine. The fraud is only visible in what they share — a card, a device fingerprint, a delivery address — and 'what do these accounts share' is a graph question.

The model

The shape of the problem

Accounts connect to cards, devices, addresses and sessions. A legitimate customer's neighbourhood is small and stable. A ring is the opposite: many accounts fanning into a few shared identifiers. In a relational schema, finding that pattern means self-joining the accounts table through every identifier type — a query that gets slower with each hop. As a graph, it's a two-hop pattern match that returns in milliseconds.

Find what accounts share, at write time

When a new account arrives, one query walks from it through its card, device and address nodes to every other account touching them. If that neighbourhood already carries flagged accounts, you know before the first transaction settles — not in tomorrow's batch job.

Follow the money through arbitrary depth

Layered transfers exist to exhaust join depth. Variable-length paths ([:TRANSFER*1..6]) and shortestPath make the number of hops part of the query, not a rewrite — trace a transfer chain as far as it actually goes.

Score in the transaction path

A single instance answers point lookups and short traversals fast enough to sit in a decision flow, and per-second billing means a dedicated risk graph doesn't have to justify a cluster's price tag.

Accounts within two hops of a flagged account, via anything they share.cypher
MATCH (flagged:Account {status: 'flagged'})
MATCH (flagged)-[:USED_CARD|USED_DEVICE|SHIPS_TO]->(id)
      <-[:USED_CARD|USED_DEVICE|SHIPS_TO]-(suspect:Account)
WHERE suspect <> flagged
RETURN suspect.id,
       collect(DISTINCT labels(id)[0]) AS shared,
       count(DISTINCT id)              AS links
ORDER BY links DESC

Questions

Fraud detection, asked directly.

Why is fraud detection a graph problem?

Because the signal is relational. A fraudulent account rarely looks wrong on its own row — it looks wrong in context: five accounts sharing one device, a payout address two hops from a known mule. Graph queries express 'what does this connect to' directly, where SQL needs a self-join per hop.

Can CognoDB score transactions in real time?

The pattern is a lookup plus a short traversal, which a running instance answers in the low milliseconds. Whether that fits your decision budget depends on your data shape and sizing — the free tier is a realistic way to measure it against your own graph.

How do I get transaction data into the graph?

Import from where it already lands: Kafka for streams, S3, GCS or Azure Blob for files, BigQuery, Snowflake or Postgres for warehouse copies. MERGE keeps the graph idempotent under replays.

Do I need machine learning for this to be useful?

No. The highest-value fraud queries are deterministic: shared identifiers, path depth to a flagged node, velocity per device. If you later add a model, the same traversals become its features.

Does this replace my existing rules engine?

It usually sits beside it. Rules that were awkward in SQL — anything phrased as 'connected to', 'within N hops', 'shares an attribute with' — move to the graph; the rest stay put.

How large can the graph get?

Instances scale from 256 MB to 512 GB of memory with storage to 4 TiB, resized without changing the connection URI. Many risk teams also run one graph per market or product line rather than one giant graph — instances are cheap enough to make that reasonable.

Start now

~98.7%

token efficiency at 2,000 entities — see the footnotes above

Put your first graph up in a minute.

A free instance takes about a minute and no card. Write two MERGE statements, read them back, and you have a living graph — with provenance on every fact.

First-graph path

Live
  1. Create a free instance

    No card. Ready in about a minute.

  2. Connect your driver

    bolt+ssc:// URI into the driver you already use.

  3. Write two MERGEs

    That's the entire shape of agent memory.

  4. Point an agent at it

    One MCP config block. No integration code.