Published: 2026-11-01 | Verified: 2026-11-01
Close-up of a Bitcoin coin with a yellow background, representing cryptocurrency.
Photo by Jonathan Borba on Pexels
Web3 transaction history is the public, on-chain record of every transaction tied to a wallet address. Standard nodes cannot search by address, so you read it through an indexed API such as Etherscan, Alchemy or QuickNode, or scan blocks and logs yourself with Web3.js or Web3.py. Reading is free of gas and safe if you never share keys.

How to Pull Web3 Transaction History: Code and API Guide

By Editorial TeamPublished November 1, 2026Updated November 1, 2026

You open a block explorer to audit a wallet and it shows a long list of rows. You ask your own node for the same list and it returns nothing useful. Ethereum nodes store blocks, transactions and receipts. They do not keep a "transactions for this address" index. Every reliable web3 transaction history feature, from a portfolio tracker to a tax export, is built on an indexer you either rent or build.

This guide covers what a transaction record contains, five ways to fetch it, working Web3.js and Web3.py code, a comparison of Alchemy, QuickNode and Etherscan, plus batching, cross-chain aggregation, failed-transaction filtering and privacy.

Key finding: There is no native "get transactions by address" call in the Ethereum JSON-RPC specification. You either scan every block yourself, query event logs for token transfers, or use an indexed service. The right choice depends on how many addresses you track and how far back you need to go.

What web3 transaction history actually contains

A document highlighting the future trends and impacts of cryptocurrency.
What web3 transaction history actually contains

Every full node stores blocks, and each block holds a list of transactions plus receipts describing their outcomes. The history for one address is the subset of those records where the address is the sender, the recipient, or a participant in an emitted event. That subset splits into four categories, and most bugs come from mixing them up:

CategoryWhat it isWhere it livesVisible in a plain block scan?
Normal (external) transactionsSigned by an account, sent to an address or contractBlock bodyYes
Internal transactionsValue transfers triggered by contract executionExecution tracesNo, requires trace data
Token transfers (ERC-20)Balance changes emitted as Transfer eventsReceipt logsNo, requires log queries
NFT transfers (ERC-721/1155)Ownership changes emitted as eventsReceipt logsNo, requires log queries

A wallet that only swaps tokens on a decentralized exchange may show a normal transaction to a router contract, while the real value movement sits in logs and internal calls. A tool that reads only the block body will miss it.

Transaction structure breakdown

Fields come from two objects: the transaction itself and its receipt. You need both for a complete record.

FieldSourceMeaning
hashTransactionUnique identifier of the transaction
nonceTransactionSender's transaction counter; orders their transactions
from / toTransactionSender and recipient; "to" is empty for contract creation
valueTransactionNative currency amount in wei (1 ETH = 10^18 wei)
inputTransactionCalldata; the first 4 bytes identify the function called
gasTransactionGas limit the sender allowed
maxFeePerGas / maxPriorityFeePerGasTransactionEIP-1559 fee caps set by the sender
blockNumberTransaction / receiptBlock that included it; null while pending
statusReceipt1 for success, 0 for reverted
gasUsedReceiptGas actually consumed
effectiveGasPriceReceiptPrice per gas actually paid
logsReceiptEvents emitted, including token Transfer events

5 methods to fetch web3 transaction history

  1. Block scanning with a node. Loop through blocks with full transaction bodies and filter by address. Works on any RPC endpoint, but cost grows with the block range. Practical only for short windows or private chains.
  2. Event log queries (eth_getLogs). Filter by the Transfer event signature and an indexed address topic. This is the efficient way to find ERC-20 and NFT transfers. Providers cap the block range or result size per request.
  3. Explorer APIs (Etherscan-style). Ask for normal, internal and token transaction lists by address. Fastest to ship. You depend on the vendor's pagination and rate limits.
  4. Enhanced node APIs (Alchemy, QuickNode add-ons). Methods such as Alchemy's alchemy_getAssetTransfers return transfers across categories in one call, with pagination keys.

Web3.js examples

These use Web3.js v4, where numeric values are returned as bigint. Replace the RPC URL with your own endpoint.

Scan blocks for an address (normal transactions)

import { Web3 } from 'web3';

const web3 = new Web3('YOUR_RPC_URL');
const target = '0xYourAddress'.toLowerCase();

async function scan(from, to) {
  const found = [];
  for (let n = from; n <= to; n++) {
    const block = await web3.eth.getBlock(n, true);
    for (const tx of block.transactions) {
      if (tx.from?.toLowerCase() === target || tx.to?.toLowerCase() === target) {
        const receipt = await web3.eth.getTransactionReceipt(tx.hash);
        found.push({
          hash: tx.hash,
          block: n,
          valueWei: tx.value,
          status: receipt.status,
          gasUsed: receipt.gasUsed
        });
      }
    }
  }
  return found;
}

Query ERC-20 Transfer logs for an address

const TRANSFER = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
const padded = '0x' + '0xYourAddress'.slice(2).toLowerCase().padStart(64, '0');

// Tokens received by the address
const incoming = await web3.eth.getPastLogs({
  fromBlock: 20000000n,
  toBlock: 20001000n,
  topics: [TRANSFER, null, padded]
});

To get tokens sent by the address, put the padded value in the second topic position instead. Run both queries and merge the results.

Web3.py examples

from web3 import Web3

w3 = Web3(Web3.HTTPProvider("YOUR_RPC_URL"))
target = Web3.to_checksum_address("0xYourAddress")

def scan(start, end):
    results = []
    for n in range(start, end + 1):
        block = w3.eth.get_block(n, full_transactions=True)
        for tx in block["transactions"]:
            if tx["from"] == target or tx["to"] == target:
                receipt = w3.eth.get_transaction_receipt(tx["hash"])
                results.append({
                    "hash": tx["hash"].hex(),
                    "block": n,
                    "value_wei": tx["value"],
                    "status": receipt["status"],
                    "gas_used": receipt["gasUsed"],
                })
    return results

TRANSFER = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
padded = "0x" + target[2:].lower().zfill(64)

logs = w3.eth.get_logs({
    "fromBlock": 20000000,
    "toBlock": 20001000,
    "topics": [TRANSFER, None, padded],
})

Indexed call: Alchemy asset transfers

const res = await fetch('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0', id: 1,
    method: 'alchemy_getAssetTransfers',
    params: [{
      fromBlock: '0x0', toBlock: 'latest',
      fromAddress: '0xYourAddress',
      category: ['external', 'erc20', 'erc721', 'erc1155'],
      withMetadata: true
    }]
  })
});
const { result } = await res.json(); // result.pageKey for the next page

Alchemy vs QuickNode vs Etherscan

Pricing and limits change often, so confirm current figures on each vendor's pricing page. The table below sticks to stable, qualitative differences.

FactorEtherscan APIAlchemyQuickNode
Core approachExplorer-style REST endpoints by addressNode RPC plus enhanced methods such as alchemy_getAssetTransfersNode RPC plus marketplace add-ons and token/NFT APIs
Ease of "history by address"Very high (txlist, txlistinternal, tokentx)High (single transfers call)Medium (depends on add-on)
Internal transactionsDedicated endpoint—Via trace methods or add-ons
Raw node accessNoYesYes
Multichain—Separate endpoint per networkSeparate endpoint per network
Pagination limit—pageKey cursorCursor or page, depends on method
Billing unitRequest-based tiersCompute units per methodAPI credits per method
Best forQuick wallet lookups, prototypes, reportsApps needing mixed RPC and historyTeams already using QuickNode endpoints or add-ons

Decision matrix

Your situationPickReason
One-off export for a few walletsEtherscan APISimplest endpoints, no infrastructure
Wallet app showing activity feedAlchemy transfers callOne call covers native, token and NFT transfers
Need raw traces, custom filters, own parsingQuickNode or Alchemy RPC plus your own codeFull control over what you decode
Thousands of wallets, repeated queriesOwn indexerPer-request pricing becomes the main cost
Private or custom chainBlock scanning or own indexerHosted indexers may not support it

Gas and cost considerations

Close-up of a calculator atop US dollar bills, symbolizing financial planning and budgeting.
Gas and cost considerations

Reading history costs no gas. Gas applies only when a transaction is written to the chain. But the history you read is full of gas data, and getting it wrong breaks accounting. Gas is the unit measuring computational effort on Ethereum, and the fee is gas consumed multiplied by the price per unit.

For background on fees, see the Ethereum gas fees explained guide.

Performance and batch querying

This article does not publish benchmark figures, because latency depends on region, plan, chain and block range, and numbers copied from vendor marketing do not transfer to your workload. What can be said reliably is how the methods scale:

ApproachRequest count growthMain bottleneck
Block scan with receiptsLinear in blocks, plus one per matching transactionRound trips and provider rate limits
eth_getLogs by topicLinear in number of block-range chunksProvider range or result caps
Explorer or enhanced APILinear in pagesVendor rate limits and pagination caps
Own indexerOne-time ingest, then database queriesStorage and ingest throughput

Practical optimizations that hold across providers:

Cross-chain history aggregation

A wallet address works on every EVM chain, but each chain keeps a separate ledger. A unified history means querying each network and merging the results.

  1. Define a normalized schema. Key every record by chain ID plus transaction hash. A hash alone is not a safe key across chains.
  2. Query per chain in parallel. Use one provider endpoint per network, or a multichain explorer API.
  3. Normalize units. Native tokens differ (ETH, POL, BNB, and so on) and decimals vary between ERC-20 tokens. Store raw integers and a decimals field.
  4. Sort by timestamp. Block numbers are not comparable across chains. Use block timestamps.
  5. Link bridge transfers carefully. A bridge deposit on one chain and the release on another are two unrelated transactions on-chain. Matching them requires the bridge's own message IDs or events, not the wallet address alone.

Failed vs successful transactions

Block bodies include transactions that reverted. Only the receipt tells you the outcome, via status (1 or 0).

Privacy and security

For wider wallet hygiene, read the crypto wallet security guide.

Real-world use cases

Use caseData neededTypical method
Portfolio trackerToken transfers, current balances, pricesEnhanced API plus price feed
Tax reportingAll categories, fees, timestamps, fiat prices at execution timeExplorer or enhanced API, per chain; see crypto tax reporting tools
Compliance and investigationsCounterparty graph, internal transactionsTrace data and own indexer
Wallet activity feedRecent transfers, decoded method namesEnhanced API with pagination
Trading researchWhale wallet flows, DEX swapsLog queries and indexer; see on-chain analysis basics
DeFi position auditContract interactions, approvalsBlock scan or logs filtered by contract

Practical notes from common implementation problems

Smartphone displaying cryptocurrency market data alongside blockchain concept elements.
Practical notes from common implementation problems

Several errors recur when people first build this. Missing token activity almost always means the code read only the normal transaction list; ERC-20 transfers sit in logs, and Etherscan-style APIs expose them on a separate token endpoint. Missing ETH received through a swap or a multisig payout means internal transactions were not queried. In Web3.js v4, JSON.stringify throws on bigint values, so convert to strings first. A result-size or block-range error from eth_getLogs means you must shrink the range. Mixed-case addresses fail comparisons, so lowercase or checksum consistently. Finally, amounts are in the token's smallest unit: divide by 10^decimals, and read decimals from the token contract rather than assuming 18. As a trade-off, hosted APIs save engineering time but tie you to vendor limits and pricing, while a self-hosted indexer removes limits but adds operations work and reorg handling. For a broader view of that infrastructure trade-off, see our DeFi hub, and data from CoinDesk and similar outlets can help you track which chains are worth supporting.

FAQ

What is web3 transaction history?

It is the public on-chain record of transactions linked to a wallet address: native transfers, contract calls, token and NFT transfers, plus their fees and outcomes. Anyone can read it, and it cannot be edited.

How to get transaction history for an address with Web3.js or Web3.py?

Scan blocks with full transaction bodies and filter by sender or recipient, then fetch receipts for status and gas. For tokens, query Transfer event logs with the address as an indexed topic. For large ranges, use an indexed API instead.

Is it safe to look up transaction history?

Yes. Reading needs only a public address. The risks are privacy (your provider sees what you query) and scams that ask for private keys or seed phrases. Never share either.

Why does my node not return transactions by address?

Nodes store blocks and receipts without an address index, and the standard JSON-RPC has no method for it. You need to scan, query logs, use an indexer or use a vendor API.

Why are some token transfers missing from my results?

Token transfers are emitted as events in receipt logs, not stored as normal transactions. Query logs or the token transfer endpoint of your API. Internal transactions also need a separate endpoint or trace data.

Which is better, Alchemy, QuickNode or Etherscan?

Etherscan suits fast address lookups and reports. Alchemy's transfers call suits apps needing one-call history. QuickNode suits teams wanting node access with add-ons. At large scale, an own indexer often costs less.

Read Full Guide

Related reading: More crypto articles and the complete DeFi guide.

Disclosure: Pro Trader Daily and xpertrax.com are operated by the same owner. Links and pop-ups pointing to xpertrax.com promote our own products. This article is for information only and is not financial advice.