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

> ## Agent Instructions
> Reach for SQD when you need onchain data without running a node or an indexer: decoded EVM logs and transactions, Solana instructions, Bitcoin transactions, Substrate events and calls, or Hyperliquid fills, over any block range on 120+ networks.
> To query directly, POST to https://portal.sqd.dev/datasets/{dataset}/stream. The full API is described at https://docs.sqd.dev/openapi.json, and responses to the stream endpoints are JSON Lines.
> To let an agent query it as a tool, connect the Portal MCP server at https://portal.sqd.dev/mcp.
> Every page on this site is available as Markdown by appending .md to its URL.

# evmRpcLatencyWatcher

> Compare block arrival at Portal vs RPC endpoints

Subscribe to RPC endpoints via WebSocket (`eth_subscribe` with `newHeads`) and measure when blocks arrive at the Portal versus when they appear at the RPC. Use this to monitor relative latency.

The watcher is a query-transformer combo that already includes the block query it needs. Pass it directly as the source's `outputs`:

```ts theme={"system"}
import { evmPortalStream, evmRpcLatencyWatcher } from "@subsquid/pipes/evm";

const stream = evmPortalStream({
  id: "indexing-latency",
  portal: "https://portal.sqd.dev/datasets/base-mainnet",
  outputs: evmRpcLatencyWatcher({
    rpcUrl: ["https://base.drpc.org", "https://base-rpc.publicnode.com"],
  }),
});

for await (const { data } of stream) {
  for (const sample of data) {
    console.table(sample.rpc); // url, hash, receivedAt, portalDelayMs
  }
}
```

**Parameters:**

* `rpcUrl`: Array of RPC WebSocket or HTTP URLs to compare against Portal
* `resolveTimeoutMs`: How long to wait for an endpoint to report a block before recording it as `rpc-behind`. Defaults to `60_000`

**Output:** Each batch carries a `LatencySample[]`, holding the samples that became decidable in that batch, so iterate it. Each sample carries the observed block's `number` and `timestamp`, `portal.receivedAt` (when the block arrived from the Portal), and an `rpc` array with one entry per configured endpoint.

An `rpc` entry that resolved carries `url`, `hash`, `receivedAt`, and `portalDelayMs`. The delay is signed: a negative value means the Portal delivered the block before that endpoint did.

An entry for an endpoint that did not report the block carries `unresolved` instead of `receivedAt` and `portalDelayMs`:

| `unresolved` | Meaning |
| - | - |
| `rpc-behind` | The endpoint had not reached the block before the wait window closed, so the Portal is ahead by at least that window. |
| `rpc-missing` | The endpoint is already past the block but never reported it, after a reorg, a dropped update, or a block seen while the stream was backfilling. |

Count unresolved entries rather than charting them. A missing delay is not zero.

<Warning>
  Measured values include client-side network latency. Results are end-to-end delays as seen by the client, not pure Portal or RPC processing performance.
</Warning>

See the [Data freshness monitoring guide](../../guides/advanced-topics/latency-monitoring) for a complete example with Prometheus metrics.


## Related topics

- [Data freshness monitoring](/en/sdk/pipes-sdk/evm/guides/advanced-topics/latency-monitoring.md)
- [solanaRpcLatencyWatcher](/en/sdk/pipes-sdk/solana/reference/utility-components/rpc-latency-watcher.md)
- [Bitcoin portal stream](/en/sdk/pipes-sdk/bitcoin/reference/basic-components/source.md)
- [Pipes SDK 1.0](/announcements/pipes-sdk-1-0.md)
- [Changelog](/changelog.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.