> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://v3.viem.sh/api/mcp` to find what you need.

# Creating an Event Filter

## Overview

Use [`contract.createEventFilter.<event>`](#contractcreateeventfilter) to create a provider-side filter for one event in the contract's ABI.

The instance supplies `abi`, `address`, and `eventName` to [`Actions.contract.createEventFilter`](/docs/actions/public/contract/createEventFilter).

Poll the filter for changes, then uninstall it when you finish.

## Recipes

### Manage the Filter Lifecycle

Creating a filter allocates state on the RPC provider. Poll the same filter handle, then uninstall it in a `finally` block.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })

const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})

const filter = await contract.createEventFilter.Transfer({ // [!code focus]
  args: { from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e' }, // [!code focus]
}) // [!code focus]

try {
  const logs = await Actions.filter.getChanges(client, { filter }) // [!code focus]
  console.log(logs)
} finally {
  await Actions.filter.uninstall(client, { filter }) // [!code focus]
}
```

### Bound the Filter Range

Pass `fromBlock` and `toBlock` to limit the inclusive block range.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })
const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})

const filter = await contract.createEventFilter.Transfer({
  fromBlock: 20_000_000n, // [!code focus]
  toBlock: 20_000_100n, // [!code focus]
})

await Actions.filter.uninstall(client, { filter })
```

### Require Strict Event Matching

Set `strict: true` when returned logs must conform to the selected event and argument filter.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })
const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})

const filter = await contract.createEventFilter.Transfer({
  args: { // [!code focus]
    from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
  }, // [!code focus]
  strict: true, // [!code focus]
})

try {
  const logs = await Actions.filter.getChanges(client, { filter })
} finally {
  await Actions.filter.uninstall(client, { filter })
}
```

## `contract.createEventFilter`

Creates a typed provider filter for an event from the contract ABI.

### Usage

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })

const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})

const filter = await contract.createEventFilter.Transfer()

filter.type
// @log: 'event'

await Actions.filter.uninstall(client, { filter })
```

### Parameters

The instance supplies `abi`, `address`, and `eventName`. Use options to match indexed arguments,
choose block bounds, or require strict decoding.

#### options.args

* **Type:** Inferred from the selected ABI event
* **Optional**

Indexed argument values to match. Only indexed fields from the selected event are accepted.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })
const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})
// ---cut---
const filter = await contract.createEventFilter.Transfer({
  args: { // [!code focus]
    from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
  }, // [!code focus]
})

await Actions.filter.uninstall(client, { filter })
```

#### options.fromBlock

* **Type:** `bigint | BlockTag`
* **Optional**

The inclusive block number or tag at which the filter starts.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })
const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})
// ---cut---
const filter = await contract.createEventFilter.Transfer({
  fromBlock: 20_000_000n, // [!code focus]
})

await Actions.filter.uninstall(client, { filter })
```

#### options.strict

* **Type:** `boolean`
* **Default:** `false`

Whether logs must match all indexed and non-indexed event arguments.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })
const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})
// ---cut---
const filter = await contract.createEventFilter.Transfer({
  strict: true, // [!code focus]
})

await Actions.filter.uninstall(client, { filter })
```

#### options.toBlock

* **Type:** `bigint | BlockTag`
* **Optional**

The inclusive block number or tag at which the filter ends.

```ts twoslash
import { Actions, Client, Contract, http } from 'viem'
import { mainnet } from 'viem/chains'
import { Abis } from 'viem/utils'

const client = Client.create({ chain: mainnet, transport: http() })
const contract = Contract.from({
  abi: Abis.erc20,
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  client,
})
// ---cut---
const filter = await contract.createEventFilter.Transfer({
  toBlock: 'latest', // [!code focus]
})

await Actions.filter.uninstall(client, { filter })
```

### Return Value

`Promise<Actions.contract.createEventFilter.ReturnType>`

An event filter whose decoded log type is inferred from the selected ABI event.

The filter's `request` function is scoped to the originating [Transport](/docs/transports). Later requests reach the node that owns the filter ID.

### Errors

| Error | Description |
| --- | --- |
| `AbiItem.NotFoundError` | The selected event is missing from the runtime ABI. |
| `AbiEvent.FilterTypeNotSupportedError` | `args` includes an indexed tuple or array, which event topic filters do not support. |
| `AbiParameters.InvalidTypeError` | `args` includes an indexed ABI type that the topic encoder does not support. |
| `Address.InvalidAddressError` | `args` includes an invalid indexed address. |
| `Hex.IntegerOutOfRangeError` | `args` includes an indexed integer outside the supported 256-bit range. |
| `Hex.SizeExceedsPaddingSizeError` | An indexed fixed-bytes value exceeds the 32-byte topic size. |
