A successful receipt tells you almost nothing about what a transaction actually did. The token moved, but through which contracts? The call succeeded, but which internal transfer carried the value? Logs record what contracts chose to emit; everything between calls is invisible to eth_getTransactionReceipt. The Parity trace namespace was built for exactly that gap, and two of its methods do most of the work: trace_transaction for a single transaction's full internal-call tree, and trace_filter for scanning ranges of blocks. We operate RPC across 75+ chains and probe trace support weekly (it's part of our method-support matrix), so this comes with current availability data, not folklore.
trace_transaction: one transaction, fully unpacked
Here's a real response for a fresh Sonic transaction, captured through our endpoint while writing this:
// trace_transaction("0xe3bb52bf…") on Sonic →
[
{
"action": {
"callType": "call",
"from": "0x1fc056…",
"to": "0xf87af5…",
"value": "0x0",
"gas": "0x10e78",
"input": "0xe17e76e3…"
},
"blockNumber": 78366386,
"result": { "gasUsed": "0x1201d", "output": "0x…0001" },
"subtraces": 0,
"traceAddress": [],
"transactionHash": "0xe3bb52bf…",
"transactionPosition": 0,
"type": "call"
}
]
Each entry is one step of execution. The fields that matter:
-
action— who called whom (from/to), with whatvalue,callType(call,delegatecall,staticcall), or for othertypes:create(contract deployment) andsuicide. -
traceAddress— this step's position in the call tree.[]is the top-level call;[2]is the third sub-call of the top level;[2,0]is its first child. That array is how you reconstruct the whole tree. -
subtraces— how many children this step spawned. -
result— gas used and return data at this level, separately from the transaction-level receipt.
A DEX swap through a router, two pools, and a recipient ends up as a dozen or more of these entries — the exact path the value traveled. That reconstruction is what accounting tools, forensic dashboards, and internal-transfer indexers are actually built on. For the cost side of tracing (and why you should never loop these calls casually), see our earlier piece on debug_traceTransaction.
trace_filter: the indexer's range scan
trace_transaction answers "what did this hash do?" trace_filter answers "what happened across these blocks?" — scans a block range and returns every trace matching your filter:
// trace_filter over three recent Ethereum blocks →
// 7,276 traces returned
[
{
"action": {
"from": "0x835033…",
"callType": "call",
"to": "0x933339…",
"value": "0x214e8348c4f0000", // 0.15 ETH
"input": "0x",
"gas": "0x13498"
},
"blockNumber": 25859102,
"subtraces": 0,
"traceAddress": [],
"transactionHash": "0x49bcbd…",
"type": "call"
}
]
The filter object accepts fromBlock, toBlock, plus optional address and topics constraints. Indexers use it the way Safe's Transaction Service does for non-L2 deployments — their infrastructure docs list the trace methods among the indexer's RPC requirements, with trace_filter doing the discovery work. Note the volume in that sample: roughly 2,400 internal actions per Ethereum block. That number explains everything in the next section.
The param gotcha we hit today
Some implementations reject block tags in the filter and demand numeric blocks. The same query, "fromBlock": "latest" versus "0x18a9c1d":
{"code":-32602,"message":"Invalid params","data":"invalid value: string \"latest\", expected a 8 byte hex string at line 1 column 21"}
Fetch eth_blockNumber and pass hex numbers — it works everywhere the method works at all. -32602 here is good news, by the way: the method exists and parsed your request. That ambiguity between "fix your params" and "method missing" is the same taxonomy we covered in yesterday's error-code field guide.
Where traces actually work in 2026
The trace namespace comes from the Parity client lineage. Geth never implemented it, which means most L2s and geth-fork chains simply don't have it — and among chains whose software could serve traces, providers frequently gate them because they're expensive. This week's probe across the 54 EVM chains we serve:
| Capability | Chains serving it |
|---|---|
trace_filter |
11 of 54 |
trace_transaction |
11 of 54 |
| Both (full indexer suite) | 8 of 54 — Ethereum, Gnosis, Sonic, Berachain, Fraxtal, Plasma, PulseChain, Soneium |
OP Stack chains and most zk chains return clean rejections — the namespace is gone there by design. And even where a chain supports tracing, the upstream provider can gate it. A real response from a Base request, via a popular public endpoint:
{"code":-32602,"message":"Archive requests require a personal token. Get one at: https://www.allnodes.com/publicnode"}
That's policy, not capability — which is why per-chain claims need probing rather than reading someone's feature page. The live, re-probed breakdown is on our trace_filter and trace_transaction pages, column-by-column for every chain.
Working with traces in practice
-
Reconstructing internal transfers: filter by
toorfromaddress over a block range, keep entries withtype: "call"and non-zerovalue— that's the ETH that moved between contracts, invisible to receipt-based accounting. -
Post-mortem debugging: when a transaction "succeeded" but balances don't add up,
trace_transactionshows every internal hop. Pair with state proofs when you need to verify, not just inspect. -
Historical tracing requires archive access: traces are state-dependent, so scanning old ranges routes through archive nodes — on SwiftNodes that's
&archive=1, included on paid plans. - Respect the volume: thousands of traces per block means wide filters are heavy. Narrow your block range, filter by address where you can, and cache aggressively. Same discipline as getLogs range caps.
Check any endpoint yourself
npx rpc-doctor <url> probes method support — including the trace pair — and reports what an endpoint actually serves, for any endpoint, yours or anyone's. It's open source.
And if you want traces where they exist and honest answers where they don't: our routing spreads load across upstreams that genuinely serve the namespace, and the method-support matrix is re-probed weekly through the same path your requests take — free tier included.
Originally published on the SwiftNodes blog. SwiftNodes provides flat-rate multi-chain RPC endpoints — HTTP + WebSocket, 75+ chains, no per-request metering. Grab a free key.
Top comments (0)