How Transaction Network Analysis Catches Laundering Patterns that Rule-Based Systems Miss
Last Updated on June 3, 2026 by Editorial Team
Author(s): Bhavesh Awalkar
Originally published on Towards AI.
How Transaction Network Analysis Catches Laundering Patterns that Rule-Based Systems Miss
Money laundering moves an estimated $800 billion to $2 trillion
through the global financial system every year. In the United
States, financial institutions are required under the Bank Secrecy
Act to detect and report suspicious activity — but most transaction
monitoring systems rely on static rules that generate false positive
rates of 90–95%, burying compliance teams in alerts while
sophisticated laundering patterns go undetected.
The core problem: money laundering is a network phenomenon. Funds
move through chains of accounts, split across multiple individuals,
and cycle back through shell entities. A rule that looks at one
transaction at a time cannot see this structure.
Graph analytics can.
In this article I’ll show how to build a transaction network from
raw data and apply three graph-based detection methods — structuring
ring detection, layering chain analysis, and centrality scoring —
using Python and the open-source aml-analytics toolkit.
What is graph-based AML detection?
Traditional transaction monitoring treats each transaction in
isolation: if amount > $9,000 and channel = cash, flag it. This
works for simple patterns but misses anything that requires
connecting the dots across multiple accounts and time periods.
Graph-based detection reframes the problem. Instead of asking
“is this transaction suspicious?” we ask “is this account’s
position in the transaction network suspicious?”
We model the financial system as a directed graph:
– Nodes = accounts
– Edges = transactions (with amount, timestamp, and channel as attributes)
Three patterns become visible in this representation that are
invisible at the transaction level:
- Structuring rings — one account sending multiple sub-threshold
amounts to different receivers in a short window - Layering chains — funds flowing A→B→C→D through a sequence
of accounts to create distance from the original crime - Funnel accounts — accounts with high betweenness centrality
that sit at the center of many transaction flows, consistent
with accounts used to consolidate and redistribute illicit funds
Setup and data
We’ll use the aml-analytics toolkit which is installable via pip:
pip install aml-analytics
The toolkit includes a synthetic transaction generator that produces
realistic labeled data — no real transaction data needed. It generates
transactions with four labels: normal, structuring, layering, and
smurfing — so you can validate detection logic against known patterns.
from aml.synthetic import generate_transactions, get_summary
from aml.graph import build_network, detect_structuring, detect_layering, centrality_score
# Generate 1,000 synthetic transactions with labeled AML scenarios
df = generate_transactions(n=1000, seed=42)
get_summary(df)
Expected Output
Total transactions : 1,000
Unique senders : 50
Unique receivers : 50
Date range : 2023-01-01 → 2023-12-30
Label breakdown:
normal 820
structuring 50
layering 80
smurfing 30
Building the transaction network
Building the network is straightforward — each unique account
becomes a node, each transaction becomes a directed edge with
amount, timestamp, and channel stored as edge attributes:
G = build_network(df)
print(f"Nodes (accounts) : {G.number_of_nodes()}")
print(f"Edges (transactions): {G.number_of_edges()}")
Now visualize the top 30 most connected accounts to see the
network structure:
import matplotlib.pyplot as plt
import networkx as nx
top_nodes = sorted(G.degree(), key=lambda x: x[1], reverse=True)[:30]
top_node_ids = [n[0] for n in top_nodes]
subgraph = G.subgraph(top_node_ids)
plt.figure(figsize=(12, 8))
pos = nx.spring_layout(subgraph, seed=42)
degrees = dict(subgraph.degree())
node_sizes = [degrees[n] * 200 for n in subgraph.nodes()]
nx.draw_networkx(
subgraph, pos=pos,
node_size=node_sizes,
node_color="steelblue",
edge_color="gray",
alpha=0.8,
with_labels=True,
font_size=7,
)
plt.title("Transaction Network — Top 30 Most Connected Accounts")
plt.axis("off")
plt.show()
Already you can see structure — some accounts have far more
connections than others. These high-degree nodes are worth
investigating further. But degree alone isn’t enough — an account
could have many connections simply because it’s a high-volume
legitimate account. We need to look at the pattern of those
connections, not just the count.

Node size represents degree centrality — larger nodes have
more transaction connections. High-degree nodes warrant
priority investigation as potential funnel accounts.
Structuring detection
Structuring — breaking up large cash amounts into multiple
transactions just below the $10,000 Currency Transaction Report
(CTR) threshold — is one of the most common money laundering
techniques and is explicitly prohibited under 31 U.S.C. 5324.
In the transaction network, structuring appears as one account
sending multiple sub-threshold cash transactions within a short
time window. The detect_structuring() function identifies these
patterns:
alerts = detect_structuring(G, threshold=9_000, max_gap_hours=48)
print(f"Structuring alerts: {len(alerts)}")
for alert in alerts[:3]:
print(f"\nAccount : {alert['sender_id']}")
print(f"Txn count: {alert['transaction_count']}")
print(f"Total : ${alert['total_amount']:,.2f}")
print(f"Window : {alert['time_window_hours']:.1f} hours")
The algorithm groups transactions by sender, filters for amounts
below the threshold, and flags any sender with 2 or more qualifying
transactions within the time window. Each alert includes the full
edge list so investigators can pull the specific transactions for
SAR documentation.
The key advantage over a simple rule: by operating on the network
we can see the full picture of an account’s behavior across all
its counterparties simultaneously — not just one transaction at a time.
One important caveat: thresholds calibrated on synthetic data will
be optimistic compared to real transaction noise. In production,
calibrate the threshold and window parameters against your
institution’s actual transaction distribution before deploying.
Layering detection
Layering is the second stage of money laundering — moving funds
rapidly through multiple accounts to create distance from the
original crime. A classic layering pattern looks like:
Account A → Account B → Account C → Account D
Each hop makes the funds harder to trace. In a transaction
network, layering appears as directed paths of 3 or more hops.
The detect_layering() function finds these chains:
Layering is the second stage of money laundering — moving funds
rapidly through multiple accounts to create distance from the
original crime. A classic layering pattern looks like:
Account A → Account B → Account C → Account D
Each hop makes the funds harder to trace. In a transaction
network, layering appears as directed paths of 3 or more hops.
The detect_layering() function finds these chains:
The function uses depth-limited path search from each source
node, flagging any path meeting the minimum hop threshold.
Longer chains are weighted higher in risk scoring because they
suggest more deliberate obfuscation.
Two things make this approach powerful for compliance teams:
First, it surfaces the full chain — not just the first and last
account. SAR narratives require investigators to document the
movement of funds, and the chain output gives them exactly that
structure to work from.
Second, it works on the actual transaction timestamps. A chain
where funds move A→B→C→D within 6 hours is far more suspicious
than the same chain spread over 6 months. You can extend the
detection to filter by time window across the chain for even
higher precision alerts.
Centrality scoring — identifying funnel accounts
The most powerful application of graph analytics for AML is
centrality scoring — identifying accounts that play a structural
role in the transaction network consistent with money laundering.
Three centrality measures are particularly relevant:
Degree centrality — how many direct connections an account has.
High degree accounts are active in many transactions, which could
indicate legitimate high-volume activity or a hub in a laundering
network.
Betweenness centrality — how often an account sits on the shortest
path between other accounts. This is the key indicator for funnel
accounts — accounts used to consolidate illicit funds from multiple
sources before redistribution. A legitimate account rarely needs
to sit between many unrelated counterparties.
In-degree centrality — the ratio of incoming to total transactions.
Accounts receiving from many senders but sending to few are
consistent with consolidation accounts in layering schemes.
scores = centrality_score(G)
print("Top 10 highest risk accounts:")
print(scores[['node_id', 'degree_centrality',
'betweenness_centrality',
'risk_score']].head(10).to_string(index=False))
The combined risk score weights betweenness centrality most
heavily (0.5) since it is the strongest indicator of funnel
account behavior, with degree centrality (0.3) and in-degree
(0.2) as supporting signals.

accounts scoring above the high-risk threshold — these are
priority candidates for SAR review based on their structural
position in the transaction network.
Combining the signals
The real power emerges when you combine all three methods.
An account that appears in structuring alerts AND scores in
the top decile for betweenness centrality AND sits in a
detected layering chain is a very high confidence SAR candidate.
structuring_accounts = {a['sender_id'] for a in alerts}
layering_accounts = {n for c in chains for n in c['chain']}
high_centrality = set(
scores[scores['risk_score'] >
scores['risk_score'].quantile(0.9)]['node_id']
)
# Accounts flagged by all three methods
high_confidence = (
structuring_accounts &
layering_accounts &
high_centrality
)
print(f"High confidence SAR candidates: {len(high_confidence)}")
This intersection approach directly addresses the false positive
problem. Each detection method has its own false positive rate —
but requiring agreement across three independent methods with
different underlying logic reduces the combined false positive
rate dramatically.
In practice this translates to a smaller, higher-quality alert
queue — exactly what compliance teams need. Instead of reviewing
hundreds of single-signal alerts, investigators focus on the
accounts where multiple independent methods converged on the
same conclusion.
This is the core argument for combining graph analytics with
rules-based monitoring rather than replacing one with the other.
Rules provide breadth and regulatory defensibility. Graph
analytics provides depth and the ability to detect coordinated
multi-account patterns. Together they cover the full spectrum
of laundering sophistication.
Conclusion
Graph analytics doesn’t replace rules-based transaction monitoring
— it complements it. Rules catch known patterns quickly and
provide the audit trail examiners need. Graph analytics catches
the coordinated, multi-account patterns that rules miss entirely.
The three methods covered in this article — structuring ring
detection, layering chain analysis, and centrality scoring — each
address a different dimension of laundering behavior:
– Structuring detection catches threshold avoidance at the
account level
– Layering detection catches fund movement patterns across
the network
– Centrality scoring catches structural anomalies in how
accounts relate to each other
The combination — rules for breadth, graph analytics for depth —
is how modern AML programs are moving beyond the 90%+ false
positive rates that plague legacy monitoring systems.
Smaller financial institutions often lack the analytics
infrastructure to implement these approaches. The aml-analytics
toolkit is an attempt to lower that barrier — providing
open, reusable, regulatory-grounded building blocks that any
compliance or data team can deploy.
The full toolkit including velocity analysis, anomaly scoring,
SAR pattern matching, and Oracle/PostgreSQL SQL libraries is
available at:
GitHub: github.com/Bhavesh0205/aml-analytics
PyPI: pip install aml-analytics
Feedback and contributions from compliance practitioners and
data professionals are welcome — especially on typology coverage
and threshold calibration for real transaction data.
The author is a financial crimes analytics professional at a
major U.S. financial institution, specializing in AML detection
systems, transaction monitoring, and compliance data infrastructure.
Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.
Published via Towards AI
Towards AI Academy
We Build Enterprise-Grade AI. We'll Teach You to Master It Too.
15 engineers. 100,000+ students. Towards AI Academy teaches what actually survives production.
Start free — no commitment:
→ 6-Day Agentic AI Engineering Email Guide — one practical lesson per day
→ Agents Architecture Cheatsheet — 3 years of architecture decisions in 6 pages
Our courses:
→ AI Engineering Certification — 90+ lessons from project selection to deployed product. The most comprehensive practical LLM course out there.
→ Agent Engineering Course — Hands on with production agent architectures, memory, routing, and eval frameworks — built from real enterprise engagements.
→ AI for Work — Understand, evaluate, and apply AI for complex work tasks.
Note: Article content contains the views of the contributing authors and not Towards AI.