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

# Tutorial: Creating an Indexer

> This tutorial will guide you through building an indexer using the NEAR Indexer Framework. The indexer will listen for FunctionCalls on a specific contract and log the details of each call.

export const Github = ({url, start, end, fname, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchCode(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const startLine = start ? Number(start) : 1;
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="rounded-[0.625rem] border border-[#d0d7de] dark:border-[#30363d] overflow-hidden my-5 text-[0.8125rem] font-mono shadow-sm dark:shadow-[0_4px_24px_rgba(0,0,0,0.18)]">

      {}
      <div className="flex items-center justify-between py-2 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-b border-[#d0d7de] dark:border-[#30363d]">
        <div className="flex items-center gap-2 text-[#656d76] dark:text-[#8b949e]">
          <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
          </svg>
          <span className="text-xs font-medium text-[#1f2328] dark:text-[#e6edf3]">
            {fileName}
          </span>
        </div>
        {start && end && <span className="text-[0.6875rem] text-[#656d76] dark:text-[#8b949e] bg-[#eaeef2] dark:bg-[#21262d] border border-[#d0d7de] dark:border-[#30363d] rounded-full py-0.5 px-2">
            Lines {start}–{end}
          </span>}
      </div>

      {}
      <div className="overflow-auto max-h-[480px] bg-white dark:bg-[#0d1117] [&_tr]:border-b-0 [&_td]:border-b-0">
        {code === null ? <div className="py-5 px-4 text-xs text-[#656d76] dark:text-[#6e7681]">
            Loading...
          </div> : <table className="w-full border-collapse leading-[1.6]">
            <tbody>
              {code.split('\n').map((line, i) => <tr key={i} className="align-top border-0">
                  <td style={{
    minWidth: '60px'
  }} className="select-none pl-2 pr-3 text-right text-[0.7rem] text-[#8c959f] dark:text-[#3d444d] w-[1%] whitespace-nowrap border-r border-0 border-r-[#d0d7de] dark:border-r-[#21262d]">
                    {startLine + i}
                  </td>
                  <td className="pl-4 pr-6 text-[0.8125rem] text-[#1f2328] dark:text-[#e6edf3] whitespace-pre">
                    {line || ' '}
                  </td>
                </tr>)}
            </tbody>
          </table>}
      </div>

      {}
      {withSourceLink && <div className="flex justify-end py-1.5 px-[0.875rem] bg-[#f6f8fa] dark:bg-[#161b22] border-t border-[#d0d7de] dark:border-[#21262d]">
          <a href={sourceUrl} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] dark:text-[#8b949e] no-underline flex items-center gap-[0.3rem] hover:text-[#1f2328] dark:hover:text-[#e6edf3] transition-colors">
            View on GitHub
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
              <polyline points="15 3 21 3 21 9" />
              <line x1="10" y1="14" x2="21" y2="3" />
            </svg>
          </a>
        </div>}
    </div>;
};

In this tutorial, we will build an indexer using the NEAR Indexer Framework. The indexer will listen realtime blocks data from NEAR blockchain.

To get our indexer up and running we will need two steps:

1. To [initialize](#initialization) the indexer
2. To [start it](#starting-the-indexer)

The full source code for the indexer example is available in the [GitHub repository](https://github.com/near/nearcore/tree/master/tools/indexer/example).

<Note>
  Source code link is for `nearcore` repository, as the Indexer Framework is part of the `nearcore` codebase. We provide the link to `master` branch. If you want to use **the latest stable release version** you should check the [releases page](https://github.com/near/nearcore/releases) and checkout the corresponding tag.
</Note>

<Danger>
  NEAR Indexer Framework only works on **`Linux x86`**, it does **not** support Windows or MacOS
</Danger>

***

## Prerequisites

### Install Rust

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

### Install developer tools

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
apt update
apt install -y git binutils-dev libcurl4-openssl-dev zlib1g-dev libdw-dev libiberty-dev cmake gcc g++ python docker.io protobuf-compiler libssl-dev pkg-config clang llvm cargo awscli
```

<Danger>
  NEAR Indexer Framework only works on **`Linux x86`**, it does **not** support Windows or MacOS
</Danger>

### Clone nearcore repository

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
git clone git@github.com:near/nearcore.git
```

***

## Initialization

In order for our indexer to process blocks it needs to join the NEAR network as a node. To do that, we need first to initialize it, which will download the blockchain `genesis` config, and create a `key` for our node to communicate with other nodes.

Go to the `nearcore/tools/indexer/example` folder and build the indexer:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
cd nearcore/tools/indexer/example && cargo build --release
```

Then, run the following command to initialize the network configuration:

<Tabs>
  <Tab title="Localnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
      cargo run --release -- --home-dir ~/.near/localnet init
    ```
  </Tab>

  <Tab title="Testnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
      cargo run --release -- --home-dir ~/.near/testnet init --chain-id testnet --download-config rpc --download-genesis
    ```
  </Tab>

  <Tab title="Mainnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
      cargo run --release -- --home-dir ~/.near/mainnet init --chain-id mainnet --download-config rpc --download-genesis
    ```
  </Tab>
</Tabs>

Depending on the network we want to connect, the keys will be created in different folders (`~/.near/<network>`).

#### Config File

A configuration file (`~/.near/<network>/config.json`) is created automatically, whoever, it is recommended to replace with one of the following ones, intended for RPC nodes:

* [testnet config.json](https://s3-us-west-1.amazonaws.com/build.nearprotocol.com/nearcore-deploy/testnet/rpc/config.json)
* [mainnet config.json](https://s3-us-west-1.amazonaws.com/build.nearprotocol.com/nearcore-deploy/mainnet/rpc/config.json)

<Note>
  **Configuration Options**

  See the [Custom Configuration](#custom-configuration) section below to learn more about further configuration options.
</Note>

***

## Starting the Indexer

After we finish initializing the indexer, and configuring it, we can start it by running the following command:

<Tabs>
  <Tab title="Localnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
      cargo run --release -- --home-dir ~/.near/localnet
    ```
  </Tab>

  <Tab title="Testnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
      cargo run --release -- --home-dir ~/.near/testnet run
    ```
  </Tab>

  <Tab title="Mainnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
      cargo run --release -- --home-dir ~/.near/mainnet run
    ```
  </Tab>
</Tabs>

<Accordion title="How it works">
  * The command initializes the indexer's configuration: home directory, sync mode, streaming mode, finality, etc.
  * Creates a Tokio runtime on a dedicated thread.
  * Creates an instance of the Indexer using the provided configuration, starts it, and streams blocks to our handler. Within the handler (`listen_blocks` method), there is an infinite loop that parses block data for each new block received.

  <Github fname="main.rs" language="rust" url="https://github.com/near/nearcore/blob/master/tools/indexer/example/src/main.rs" start="271" end="289" />
</Accordion>

#### Run into an Error?

* If your indexer cannot find `boot nodes`, check the [boot nodes](#boot-nodes) section

***

## Parsing the Block Data

Within the `listen_blocks` method, we can parse the block data as it flows from the stream. From the block data, we can access the transactions, their receipts, and actions. See the code below for an example of how to parse the block data:

<Github fname="main.rs" language="rust" url="https://github.com/near/nearcore/blob/master/tools/indexer/example/src/main.rs" start="10" end="254" />

***

## Custom Configuration

By default, nearcore is configured to do as little work as possible while still operating on an up-to-date state. Indexers may have different requirements, so you might need to tweak the configuration based on yours.

### Shards/Accounts to Track

We need to ensure that NEAR Indexer follows all the necessary shards, so by default the `"tracked_shards_config"` is set to `"AllShards"`. The most common tweak you might need to apply is listing to specific shards; to do that, lists all the shard UIDs you want to track in the `"tracked_shards_config"` section (`~/.near/<network>/config.json` file):

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
...
"tracked_shards_config": {
       "Shards": [
              "s3.v3",
              "s4.v3"
       ]
},
...
```

Or, if you want to track specific accounts:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
...
"tracked_shards_config": {
       "Accounts": [
              "account_a",
              "account_b"
       ]
},
...
```

### Sync Mode

You can choose Indexer Framework sync mode by setting what to stream:

* LatestSynced - Real-time syncing, always taking the latest finalized block to stream
* FromInterruption - Starts syncing from the block NEAR Indexer was interrupted last time
* BlockHeight(u64) - Specific block height to start syncing from.

<Github fname="main.rs" language="rust" url="https://github.com/near/nearcore/blob/master/tools/indexer/example/src/main.rs" start="274" end="274" />

### Streaming Mode

You can choose Indexer Framework streaming mode by setting what to stream:

* StreamWhileSyncing - Stream while node is syncing
* WaitForFullSync - Don't stream until the node is fully synced

<Github fname="main.rs" language="rust" url="https://github.com/near/nearcore/blob/master/tools/indexer/example/src/main.rs" start="275" end="275" />

### Finality

You can choose finality level at which blocks are streamed:

* None - `optimistic`, a block that (though unlikely) might be skipped
* DoomSlug - `near-final`, a block that is irreversible, unless at least one block producer is slashed
* Final - `final`, the block is final and irreversible.

<Github fname="main.rs" language="rust" url="https://github.com/near/nearcore/blob/master/tools/indexer/example/src/main.rs" start="276" end="276" />

### Boot Nodes

If your node can't find any peers to connect to, you can manually specify some boot nodes in the `config.json` file. You can get a list of active peers for your network by running the following command:

<Tabs>
  <Tab title="Testnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST https://rpc.testnet.near.org \
      -H "Content-Type: application/json" \
      -d '{
            "jsonrpc": "2.0",
            "method": "network_info",
            "params": [],
            "id": "dontcare"
          }' | \
    jq '.result.active_peers as $list1 | .result.known_producers as $list2 |
    $list1[] as $active_peer | $list2[] |
    select(.peer_id == $active_peer.id) |
    "\(.peer_id)@\($active_peer.addr)"' |\
    awk 'NR>2 {print ","} length($0) {print p} {p=$0}' ORS="" | sed 's/"//g'
    ```
  </Tab>

  <Tab title="Mainnet">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST https://rpc.mainnet.near.org \
      -H "Content-Type: application/json" \
      -d '{
            "jsonrpc": "2.0",
            "method": "network_info",
            "params": [],
            "id": "dontcare"
          }' | \
    jq '.result.active_peers as $list1 | .result.known_producers as $list2 |
    $list1[] as $active_peer | $list2[] |
    select(.peer_id == $active_peer.id) |
    "\(.peer_id)@\($active_peer.addr)"' |\
    awk 'NR>2 {print ","} length($0) {print p} {p=$0}' ORS="" | sed 's/"//g'
    ```
  </Tab>
</Tabs>

And then add the output to the `boot_nodes` section of your `config.json` file as a string:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
...
"network": {
    "addr": "0.0.0.0:24567",
    "boot_nodes": "ed25519:8oVENgBp6zJfnwXFe...",
    ...
},
...
```

### Historical Data

Indexer Framework also exposes access to the internal APIs (see Indexer::client\_actors method), so you can fetch data about any block, transaction, etc, yet by default, nearcore is configured to remove old data (garbage collection), so querying the data that was observed a few epochs before may return an error saying that the data is not found. If you only need blocks streaming, you don't need this tweak, but if you need access to the historical data right from your Indexer, consider updating "archive" setting in config.json to true:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
...
"archive": true,
...
```

***

## Using NEAR Indexer in your Project

You can also use NEAR Indexer Framework as a dependency in your own Rust project. To do that, add the following to your `Cargo.toml` file (replace `2.8.0` with the latest stable release version):

```toml theme={"theme":{"light":"github-light","dark":"github-dark"}}
[dependencies]
near-indexer = { git = "https://github.com/near/nearcore", tag = "2.9.1" }
near-indexer-primitives = { git = "https://github.com/near/nearcore", tag = "2.9.1" }
near-config-utils = { git = "https://github.com/near/nearcore", tag = "2.9.1" }
near-o11y = { git = "https://github.com/near/nearcore", tag = "2.9.1" }
near-primitives = { git = "https://github.com/near/nearcore", tag = "2.9.1" }
```
