> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ethereum logs tutorial series: Logs and filters

> Master Ethereum event logs and filters with practical examples covering eth_getLogs, topics encoding, and smart contract event monitoring on Chainstack.

**TLDR**

* Explains how Ethereum logs provide an immutable record of on-chain events, while filters allow targeted retrieval of these logs based on addresses, topics, or block ranges.
* Demonstrates retrieving historical logs with getPastLogs for one-time queries, and real-time subscription to new logs with eth\_subscribe for reactive DApps.
* Highlights best practices such as indexing event parameters, breaking large block ranges, caching, and throttling requests.
* Concludes that logs + filters combine to power event-driven, scalable Ethereum applications.

## Introduction

Alright, so why do programmers never get lost in the woods?! Because they always follow the trail of logs they've left behind (ba-dum-tss).

In the world of software development, logs are an indispensable tool for understanding and troubleshooting the behavior of applications. By acting as a detailed journal of system events, errors, and other relevant information, logs provide developers with crucial insights into the inner workings of their programs. As applications continue to grow more complex and interconnected, the importance of logs becomes increasingly apparent.

In Ethereum, logs take on a distinct role compared to those in traditional software development. They provide a mechanism to store and access data generated by smart contracts during their execution. These logs, which are stored as immutable entries within transaction receipts, provide insights into events, state changes, and data storage related to smart contracts. Now, the utilization of the said information is only possible through convenient means of access to these logs. This is where filters come in.

Filters are mechanisms that allow external applications, developers, and users to efficiently search, access, and monitor logs generated by the Ethereum blockchain. By applying specific criteria to filter logs, they enable targeted retrieval of relevant information from the vast amount of data stored in the form of logs.

One can think of Ethereum logs as newspaper articles. They contain recorded information about specific events, stories, or data, just as logs hold information about events and data generated by smart contracts. Newspapers provide a means of communication and record-keeping, much like logs in the Ethereum ecosystem.

On the other hand, filters can be compared to search engines that help users find relevant articles or information from newspapers based on specific criteria or keywords. Filters in Ethereum allow developers and DApps to efficiently access specific data from logs or other aspects of the blockchain without having to go through the entire blockchain, just as search engines enable users to find the exact information they are looking for without reading all available newspapers.

Now, what follows is an in-depth analysis of Ethereum logs, filters, and their working. Whether you're a seasoned Ethereum developer or just getting started with the platform, this in-depth analysis will provide you with the knowledge you need to make the most of Ethereum logs and filters. Let's get started!

## Analyzing Ethereum logs

Ethereum logs are data structures created as a result of events emitted by smart contracts during their execution. The key difference between logs and events is that events are a programming feature in Solidity that enables smart contracts to communicate and interact with external applications, while logs are the data structures generated by the Ethereum Virtual Machine (EVM) when events are emitted. Smart contracts can emit events to indicate specific occurrences or state changes, which are logged and stored as part of transaction receipts.

Ethereum logs primarily serve two main purposes: event logging and data storage. Developers and DApps can access these logs to trigger further actions or to track important events. Additionally, logs offer a cost-effective way to store data off-chain while maintaining a reference on the blockchain, reducing gas costs and enhancing efficiency.

<Info>
  To get a more in-depth idea about event logs, check out [Tracking some Bored Apes: The Ethereum event logs tutorial](/docs/tracking-some-bored-apes-the-ethereum-event-logs-tutorial)
</Info>

To understand the basic components of an Ethereum log, let's consider a simple example of a token transfer event log.

The `Transfer` event is used in a simple token smart contract to record and communicate token transfers between addresses:

<CodeGroup>
  ```javascript Javascript theme={"system"}
  /**
   * @dev Emitted when `value` tokens are moved from one account (`from`)
   * to another (`to`).
   * Note that `value` may be zero.
   */
  event Transfer(address indexed from, address indexed to, uint256 value);
  ```
</CodeGroup>

The event takes three parameters: the sender's address, the recipient's address, and the transferred token value. When the `transfer` function is called within the smart contract, the `Transfer` event is emitted, generating the following Ethereum log entry:

<CodeGroup>
  ```javascript Javascript theme={"system"}
  {
      address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      topics: [
        '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        '0x00000000000000000000000037b2b98ea5d620a4064fc954e9f374c8a28e2125',
        '0x000000000000000000000000dc412bbc1875e588166211defa9c84ac195094cf'
      ],
      data: '0x0000000000000000000000000000000000000000000000000000000047868c00',
      blockNumber: 14673517,
      transactionHash: '0x63aff25171e502638926200a480fbd0365ca0c76d036acaa866f8af5d26e9a61',
      transactionIndex: 311,
      blockHash: '0xfa470ae2ccbe4d1a83b2ab039e300b4fc6d2904db80f8f8a0f4ab890f4240a09',
      logIndex: 531,
      removed: false,
      id: 'log_3cd63a01'
    }
  ```
</CodeGroup>

The basic components of the given Ethereum log include:

1. `address` — the address of the contract that generated this log.
2. `topics` — an array of topics associated with the log. Topics are indexed event parameters that can be used to filter logs.
3. `data` — the log data as a hexadecimal string. This contains the non-indexed event parameters.
4. `blockNumber` — the number of the block in which the log was created.
5. `transactionHash` — the hash of the transaction that generated this log.
6. `transactionIndex` — the index of the transaction within the block.
7. `blockHash` — the hash of the block that contains this log.
8. `logIndex` — the index of the log within the block. In this case, the log index is `531`.
9. `removed` — a boolean value that indicates whether the log was removed due to a chain reorganization.
10. `id` — a unique identifier for this log entry.

<Info>
  Find more explanations and examples in the [Chainstack API reference | eth\_getLogs](/reference/ethereum-getlogs).
</Info>

## Understanding filters

Ethereum filters are essential tools for developers when working with Ethereum-based applications. They facilitate real-time monitoring and interaction with the Ethereum blockchain, offering developers the ability to listen for specific events, state changes, or transactions. Filters help create responsive, event-driven applications that continuously adapt to changes on the blockchain.

There are three primary types of filters in Ethereum:

<CardGroup>
  <Card title="Log filters" href="/reference/ethereum-newfilter" icon="angle-right" horizontal />

  <Card title="Block filters" href="/reference/ethereum-newblockfilter" icon="angle-right" horizontal />

  <Card title="Pending transaction filters" href="/reference/ethereum-newpendingtransactionfilter" icon="angle-right" horizontal />
</CardGroup>

### Log filters

Log filters are essential for monitoring and reacting to events generated by smart contracts on the Ethereum blockchain. These events can include but are not limited to, transferring tokens, updating contract states, or invoking specific contract functions. Log filters allow developers to fetch logs based on certain conditions, such as:

* **Contract address**: Monitor events emitted by a specific smart contract.
* **Event signature**: Filter logs by the event's unique signature, which is the Keccak-256 hash of the event definition (e.g., `Transfer(address,address,uint256)`).
* **Block range**: Limit the logs fetched to a specific range of blocks.
* **Indexed event parameters**: Filter logs based on specific indexed event parameters, which are used to narrow down the logs relevant to the application's needs.

Logs contain valuable information, including the event signature, contract address, block number, transaction hash, and event parameters. By utilizing log filters, developers can track contract events and update their applications accordingly.

### Block filters

Block filters focus on monitoring newly generated blocks on the Ethereum blockchain. These filters are useful for applications that need to react to new blocks, such as:

* Fetching the latest gas prices
* Verifying transactions included in a block
* Analyzing block data, such as miner rewards, difficulty, and uncle blocks

Block filters provide developers with real time updates on new blocks mined, allowing them to retrieve block header data. This data includes the block number, miner, timestamp, parent hash, and other pertinent information. By monitoring new blocks, developers can ensure their applications stay up-to-date with the latest blockchain data.

### Pending transaction filters

Pending transaction filters are designed to monitor and track pending transactions in the Ethereum network. These filters are beneficial for applications that require information about unconfirmed transactions, such as:

* Displaying pending transactions in a user's wallet
* Analyzing transaction behavior, like gas price bidding or transaction propagation
* Estimating transaction confirmation times

Pending transaction filters notify developers when a new transaction enters the pending state, providing the transaction hash. Developers can then fetch the transaction data using the hash, which includes the sender, recipient, value, gas price, and other relevant transaction details.

## Accessing logs using filters

### Prerequisites

Access an Ethereum node:

1. [Head over to Chainstack](https://console.chainstack.com/user/account/create) and create an account.
2. [Deploy an Ethereum Mainnet node](/docs/manage-your-networks) in Chainstack.

Set up a Node project:

1. Install the following dependencies in your system:

   * [Node (version ≥ 16)](https://nodejs.org/en/download) and the corresponding npm
   * A code editor (VS Code, preferably)

   Once you have everything, the next step is to set up a Node project and install the web.js library.

2. Create a new directory.

3. Open a terminal in the directory.

4. Use the following command to initialize a Node project:

   <CodeGroup>
     ```shell Shell theme={"system"}
     npm init -y
     ```
   </CodeGroup>

5. Once the project is initialized, use the following command to install the web.js package:

   <CodeGroup>
     ```shell Shell theme={"system"}
     npm install web3
     ```
   </CodeGroup>

6. Within the project, create a new JavaScript file, `fetchLogs.js`, and add the following lines of code:

   <CodeGroup>
     ```javascript fetchLogs.js theme={"system"}
     const Web3 = require('web3');

     // Add your Chainstack node endpoint (HTTPS)
     const chainstackRpcUrl = 'YOUR_CHAINSTACK_ENDPOINT';
     const web3 = new Web3(new Web3.providers.HttpProvider(chainstackRpcUrl));

     // USDC token contract address on Ethereum mainnet
     const usdcContractAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';

     // The Transfer event signature for ERC20 tokens (keccak256 hash of "Transfer(address,address,uint256)")
     const transferEventSignature = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

     // Define the filter options for fetching USDC transfer logs
     const filterOptions = {
       fromBlock: 'latest', // Start from the genesis block
       address: usdcContractAddress,
       topics: [transferEventSignature],
     };

     // Fetch logs using the filter options
     web3.eth.getPastLogs(filterOptions).then(logs => {
       // Define the Transfer event ABI
       const transferEventInputs = [
         { type: 'address', name: 'from', indexed: true },
         { type: 'address', name: 'to', indexed: true },
         { type: 'uint256', name: 'value', indexed: false },
       ];

       // Process each log
       logs.forEach(log => {
         // Decode the log data
         const decodedLog = web3.eth.abi.decodeLog(transferEventInputs, log.data, log.topics.slice(1));

         // Log the decoded transfer event data
         console.log('USDC Transfer:');
         console.log('  From:', decodedLog.from);
         console.log('  To:', decodedLog.to);
     		console.log('  Value (in USDC):', parseInt(decodedLog.value) / 1e6);
       });
     }).catch(error => {
       console.error('Error:', error);
     });
     ```
   </CodeGroup>

   In this code example, we demonstrate how to fetch USDC token transfer event logs using log filters in web3.js. The purpose of this code is to provide a clear and concise example for developers to understand how to interact with the Ethereum blockchain and obtain event logs, specifically for the USDC stablecoin. This information can be useful for applications that need to track token transfers or analyze token transaction history.

The code starts by importing the `Web3` library, which is the primary library for interacting with Ethereum nodes. We then provide the Chainstack node endpoint, which is used to connect to the Ethereum Mainnet. The USDC token contract address and the `Transfer` event signature are defined to be used in the log filter.

We create a `filterOptions` object, which contains the necessary filter parameters, such as the starting and ending blocks (`fromBlock` and `toBlock`), the contract address, and the event signature. This object is used as input for the `web3.eth.getPastLogs()` method, which fetches logs matching the filter options.

Upon successful retrieval of the logs, the function iterates through each log entry, decoding the log data using the `Transfer` event ABI. The decoded log information is then printed to the console, showing the sender, recipient, and value of each USDC transfer.

### Using raw JSON-RPC

If you're not using a high-level library, you can call the JSON-RPC methods directly. Three methods cover the common cases: `eth_getLogs` for one-shot reads, `eth_newFilter` + `eth_getFilterLogs` for filter-based reads.

#### eth\_getLogs

Retrieve logs matching a filter in a single call:

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST 'https://ethereum-mainnet.core.chainstack.com/AUTH_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "eth_getLogs",
      "params": [{
        "fromBlock": "0xCD0E64",
        "toBlock": "latest",
        "address": "0x514910771af9ca656af840dff83e8264ecf986ca",
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
        ]
      }]
    }'
  ```
</CodeGroup>

This example reads all ERC-20 `Transfer` events for the [Chainlink (LINK) token contract](https://etherscan.io/token/0x514910771af9ca656af840dff83e8264ecf986ca) starting at [block 13,438,564](https://etherscan.io/block/13438564) (`0xCD0E64` in hex). The topic hash `0xddf2…3b3ef` is the Keccak-256 of `Transfer(address,address,uint256)`.

Block numbers must be hex with a `0x` prefix, or the tags `latest`, `earliest`, `pending`, `safe`, `finalized`.

#### eth\_newFilter + eth\_getFilterLogs

When you want to register a filter once and read it back later (or repeatedly with `eth_getFilterChanges`), create the filter first:

<CodeGroup>
  ```bash Create the filter theme={"system"}
  curl -X POST 'https://ethereum-mainnet.core.chainstack.com/AUTH_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "eth_newFilter",
      "params": [{
        "fromBlock": "0xCD0E64",
        "toBlock": "latest",
        "address": "0x514910771af9ca656af840dff83e8264ecf986ca",
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
        ]
      }]
    }'
  # → {"jsonrpc":"2.0","id":1,"result":"0xb85dcf61893301a80392d3551aebbfa6"}
  ```
</CodeGroup>

The response `result` is your filter ID. Use it with `eth_getFilterLogs` to get all matching logs in one shot:

<CodeGroup>
  ```bash Read filter logs theme={"system"}
  curl -X POST 'https://ethereum-mainnet.core.chainstack.com/AUTH_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "eth_getFilterLogs",
      "params": ["0xb85dcf61893301a80392d3551aebbfa6"]
    }'
  ```
</CodeGroup>

Filters expire after \~5 minutes of inactivity — see [Fix Ethereum's filter not found error](/docs/understanding-ethereums-filter-not-found-error-and-how-to-fix-it) for the recovery pattern.

## Subscribing to logs

In the above-given code, we use the `web3.eth.getPastLogs()` to perform a one-time query to the Ethereum node to retrieve logs matching the given filters. The result is a collection of logs from the specified block range that match the filter criteria. This approach is useful for obtaining historical event data or performing a one-time analysis of contract events.

To monitor the logs in real time, we need to use the `web3.eth.subscribe()` method. When we use the `subscribe` method, we create an ongoing subscription to a specific event, such as logs, new block headers, or pending transactions. The Ethereum node pushes new data to the subscriber in real time whenever the subscribed event occurs.

This approach is useful for building event-driven applications that need to react to changes on the blockchain as they happen. To use the `subscribe` function, we need to get the WSS endpoint of your Chainstack node.

<Info>
  You can find more examples and explanations about the subscriptions method in the [Chainstack API reference](/reference/ethereum-web3js-subscriptions-methods).
</Info>

Once you fetch the endpoint, use the following code to *subscribe* to event logs:

<CodeGroup>
  ```javascript Javascript theme={"system"}
  const Web3 = require('web3');

  // Add your Chainstack node endpoint (WSS)
  const chainstackRpcUrl = 'YOUR_CHAINSTACK_ENDPOINT';

  // Configure reconnect options for WebsocketProvider
  const websocketOptions = {
    clientConfig: {
      reconnect: {
        auto: true, // Automatically attempt to reconnect
        delay: 5000, // Reconnect after 5 seconds
        maxRetries: 10, // Max number of retries
      },
    },
  };

  const web3 = new Web3(new Web3.providers.WebsocketProvider(chainstackRpcUrl, websocketOptions));

  // USDC token contract address on Ethereum mainnet
  const usdcContractAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';

  // The Transfer event signature for ERC20 tokens (keccak256 hash of "Transfer(address,address,uint256)")
  const transferEventSignature = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

  // Define the filter options for fetching USDC transfer logs
  const filterOptions = {
    address: usdcContractAddress,
    topics: [transferEventSignature],
  };

  // Subscribe to logs and process USDC transfer events
  web3.eth.subscribe('logs', filterOptions, (error, log) => {
    if (error) {
      console.error('Error:', error);
      return;
    }

    // Define the Transfer event ABI
    const transferEventInputs = [
      { type: 'address', name: 'from', indexed: true },
      { type: 'address', name: 'to', indexed: true },
      { type: 'uint256', name: 'value', indexed: false },
    ];

    // Decode the log data
    const decodedLog = web3.eth.abi.decodeLog(transferEventInputs, log.data, log.topics.slice(1));

    // Log the decoded transfer event data
    console.log('USDC Transfer:');
    console.log('  From:', decodedLog.from);
    console.log('  To:', decodedLog.to);
    console.log('  Value (in USDC):', parseInt(decodedLog.value) / 1e6);
  });
  ```
</CodeGroup>

The given code leverages the `subscribe` method available in the web3.js library to enable real-time monitoring of logs. The `subscribe` method sets up a WebSocket connection with the Ethereum node, allowing for efficient and continuous updates on new events without the need for polling. In this specific example, the code creates a subscription to the 'logs' event, applying a filter to focus on the USDC token contract's `Transfer` events. Upon receiving a new log event matching the filter criteria, the callback function is triggered, processing and decoding the event data to extract valuable information about the USDC transfers occurring on the Ethereum network.

The code is also designed to automatically reconnect to the Ethereum node if the WebSocket connection is lost or interrupted. This is important to ensure that the script continues to monitor USDC transfers without manual intervention in case of connection issues.

The reconnection logic is implemented using the `clientConfig` option when creating a new instance of`Web3.providers.WebsocketProvider`. This option allows you to customize the behavior of the WebSocket client, allowing automatic reconnection attempts following the delay and maximum retries specified in the `websocketOptions`.

## Making the best out of Ethereum logs and filters

When developing Ethereum applications, it's important to ensure that your code is efficient, secure, and scalable. To help you build reliable and performant applications, we have compiled a list of best practices for retrieving and using event logs and filters in Ethereum. These recommendations cover various aspects of development, such as safe block range, optimal coding practices, and more. By following these guidelines, you can improve your application's performance and ensure seamless interactions with the Ethereum network. Here are a few best practices that you can follow while using Ethereum logs and filters:

1. **Use the latest version of web3.js**. Make sure to always use the most recent version of the web3.js library, as it includes the latest features, optimizations, and security fixes.
2. **Choose a safe block range**. When retrieving event logs, it is essential to choose a reasonable block range. Requesting too large a range may lead to timeouts and slow response times. If you need to retrieve logs from a wide range, consider breaking the request into smaller chunks. Chainstack does not impose strict limitations on the block range you can query. However, for optimal performance, on the Ethereum network, we suggest keeping the block range within 5,000 blocks.
3. **Filter events by indexed parameters**. Using indexed parameters in your event filters can significantly improve efficiency by allowing you to target specific logs. Make use of indexed event parameters whenever possible.
4. **Monitor for new events**. Use the web3.js library's built-in event subscription feature to monitor new events in real-time. This can help you avoid the need to constantly poll for updates.
5. **Throttle your requests**. To avoid overwhelming your Ethereum provider, throttle your requests to a reasonable rate. You can use libraries like `lodash` to implement request throttling easily.
6. **Use the `fromBlock` parameter wisely**. When retrieving historical event logs, be mindful of the `fromBlock` parameter. It is often more efficient to start from a block that you know contains relevant events rather than querying from the genesis block.
7. **Cache logs locally**. Cache event logs locally to minimize the need for frequent API calls. This can improve your application's performance and reduce the load on your Ethereum provider.
8. **Monitor gas usage**. Keep track of gas usage for your contract interactions. Optimizing your contract's gas consumption can save your users money and improve the overall user experience.
9. **Secure your Ethereum provider**. For higher security, ensure that you use properly secure connections with API keys and other security measures in your Chainstack nodes.

## Conclusion

In conclusion, logs and filters are essential components of Ethereum-based applications. Logs provide valuable information about contract events, while filters allow developers to monitor and interact with the blockchain in real time. By leveraging these tools, developers can build event-driven applications that respond to changes on the blockchain and provide a seamless user experience. It's important to follow best practices when working with logs and filters to ensure that your code is efficient, secure, and scalable. By keeping these recommendations in mind, you can improve your application's performance and provide reliable interactions with the Ethereum network.

<Info>
  ### See also

  <CardGroup>
    <Card title="Tracking some Bored Apes: The Ethereum event logs tutorial" href="/docs/tracking-some-bored-apes-the-ethereum-event-logs-tutorial" icon="angle-right" horizontal />

    <Card title="Uncovering the power of eth\_getBlockReceipts" href="/docs/uncovering-the-power-of-ethgetblockreceipts" icon="angle-right" horizontal />

    <Card title="Expanding your blockchain horizons: The eth\_getBlockReceipts emulator" href="/docs/expanding-your-blockchain-horizons-the-eth_getblockreceipts-emulator" icon="angle-right" horizontal />

    <Card title="Deep dive into Merkle proofs and eth\_getProof" href="/docs/deep-dive-into-merkle-proofs-and-eth-getproof-ethereum-rpc-method" icon="angle-right" horizontal />

    <Card title="Geth vs Erigon: Deep dive into RPC methods on Ethereum clients" href="/docs/geth-vs-erigon-deep-dive-into-rpc-methods-on-ethereum-clients" icon="angle-right" horizontal />
  </CardGroup>
</Info>

### About the author

<CardGroup>
  <Card title="Sethu Raman Omanakuttan">
    <img src="https://mintcdn.com/chainstack/UN3rP7zhB69idvnC/images/docs/u/44131280.png?fit=max&auto=format&n=UN3rP7zhB69idvnC&q=85&s=a94536fa650a30812be2fef8e02ed093" alt="Sethu Raman Omanakuttan" style={{width: '80px', height: '80px', borderRadius: '50%', objectFit: 'cover', display: 'block', margin: '0 auto'}} noZoom width="250" height="250" data-path="images/docs/u/44131280.png" />

    <Icon icon="code" iconType="solid" /> Developer Advocate @ Chainstack
    <br /><Icon icon="screwdriver-wrench" iconType="solid" /> BUIDLs on Ethereum, NEAR, Graph Protocol and Oasis
    <br /><Icon icon="laptop" iconType="solid" /> Majored in computer science and technology

    <div style={{display: "flex", justifyContent: "center", gap: "12px"}}>
      <a href="https://github.com/SethuRamanOmanakuttan" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="github" iconType="brands" />
      </a>

      <a href="https://twitter.com/Sethu_Raman_O" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="twitter" iconType="brands" />
      </a>

      <a href="https://www.linkedin.com/in/sethuraman-omanakuttan" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="linkedin" iconType="brands" />
      </a>
    </div>
  </Card>
</CardGroup>
