> For the complete documentation index, see [llms.txt](https://docs.triton.one/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.triton.one/solana/reading-account-state/best-practices.md).

# Reading account state best practices

How to read Solana account state: batch getMultipleAccounts, trim with dataSlice, filter getProgramAccounts, set minContextSlot, stream updates, handle 429s.

## Batch and trim your reads

* **Read many accounts in one `getMultipleAccounts` call** instead of many `getAccountInfo` calls. Results come back in input order, with `null` for any address not found.
* **Request only the bytes you need with `dataSlice`** (`{ offset, length }`) rather than the whole account.
* **Set `encoding` to `base64`.** The default `binary` and `base58` encodings only work when the returned data, after any `dataSlice`, is 128 bytes or fewer. Larger data returns `-32600` telling you to switch to `base64`.
* **Filter `getProgramAccounts` with `memcmp` and `dataSize`.** [Cloudbreak](/solana/reading-account-state/cloudbreak-indexed-accounts.md) creates an index for frequently used filter shapes automatically, with nothing to route or configure. Once an index matches your filter, responses up to 10 MB return in milliseconds on average ([benchmarks](/solana/reading-account-state/cloudbreak-indexed-accounts.md#benchmarks)); latency grows with the size of the result.

## Read token data the supported way

| Case                                                               | What to do                                                                                                                                                                                                                                                                                                                     |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| To list a wallet's or delegate's token accounts                    | Use `getTokenAccountsByOwner` or `getTokenAccountsByDelegate`, not a raw `getProgramAccounts` over the Token program.                                                                                                                                                                                                          |
| To list the token accounts of a mint                               | Use `getProgramAccounts` with a `memcmp` on the mint at offset `0`. `getTokenAccountsByMint` isn't available on shared endpoints and returns `-32601`.                                                                                                                                                                         |
| If you must use `getProgramAccounts` on the original Token program | Include `dataSize: 165` to select only valid token accounts.                                                                                                                                                                                                                                                                   |
| For Token-2022 (variable size)                                     | Omit `dataSize` and filter on the account-type byte instead: `memcmp` at offset `165` equal to `2` (base58 `3`). This matches only token accounts that have extensions; accounts without extensions are exactly 165 bytes. For request examples, see [Query token program](/solana/quickstart/how-tos/query-token-program.md). |
| For higher-level filtering of tokens and compressed NFTs           | Use the [Metaplex DAS API](/solana/reading-account-state/metaplex-das-api.md).                                                                                                                                                                                                                                                 |

{% hint style="warning" %}
On shared endpoints, Token and Token-2022 `getProgramAccounts` calls also need a `memcmp` with the full 32-byte owner pubkey at offset `32` or the full mint pubkey at offset `0`. Calls without one are rejected with HTTP `403`.

If `getProgramAccounts` on the Token or Token-2022 program returns `excluded from account secondary indexes; this RPC method unavailable for key`, check that your query includes the owner or mint `memcmp` filter and, for the original Token program, `dataSize: 165`. For Token-2022, include the account-type `memcmp` (offset `165` equal to `2`) instead. If errors continue, contact support.
{% endhint %}

## Get freshness right

* **Use `confirmed` or `finalized`; on Alpenglow they are the same state and both are final.** `processed` slots can be dropped during minority forks or congestion. Cloudbreak answers `processed` requests for `getProgramAccounts`, `getTokenAccountsByOwner` and `getTokenAccountsByDelegate` at `confirmed`.
* **Use `minContextSlot` to fail fast on stale data.** Pass a slot you have already seen. If the node hasn't reached it, the call fails with `-32016` rather than returning older state. It works on `getAccountInfo`, `getMultipleAccounts`, `getProgramAccounts`, `getTokenAccountsByOwner` and `getTokenAccountsByDelegate`. Not every method accepts it.
* **Use `withContext: true` on `getProgramAccounts`** when you need the slot a result corresponds to. The account, token, and balance methods already include it.

## Stream instead of polling for live data

| If you need                                                       | Use                                                                                                                                                                                                                                                                                                               |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Account or transaction changes as they happen                     | [Dragon's Mouth](/solana/real-time-streaming/dragon-s-mouth-grpc.md) (Yellowstone gRPC), not polling. Point-in-time reads answer "now"; a stream pushes updates as they occur.                                                                                                                                    |
| Live updates in a browser                                         | [WebSocket](/solana/real-time-streaming/whirligig-websockets.md). gRPC is server-to-server only and is not supported in web browsers.                                                                                                                                                                             |
| Live account state without rewriting your read code               | Account Sync. Swap in the Triton SDK's `Connection` and add an `accountSync` config, and it keeps account state live in a local buffer fed by a stream, so `getAccountInfo` stays current without polling and without changing your read code. See [Account Sync](/solana/reading-account-state/account-sync.md). |
| A workload that can't miss data (indexers, analytics, accounting) | [Fumarole](/solana/real-time-streaming/fumarole-persistent-streams.md). It persists your stream position with 4 days of retention and an at-least-once delivery guarantee, so you can disconnect, resume where you left off, and backfill anything you missed.                                                    |

## Manage client connections

* **Reuse persistent connections; don't open one per request.** Node's built-in `fetch` (undici) doesn't cap connections, so heavy concurrency opens one socket per in-flight request and can exhaust ephemeral ports, causing `fetch failed` / `ECONNRESET` / `Connect Timeout`.
* **Start with a 50-connection pool, then raise it only if all 50 are consistently in use.** For built-in `fetch`, set a global undici dispatcher with `new Agent({ connections: 50 })`. For axios, use an `https.Agent` with `keepAlive: true` and `maxSockets: 50`. Pooling also lowers load on the RPC servers. See [Web3JS socket/connection issues](/solana/faq/error-handling/web3js-socket-connection-issues.md).

## Stay within rate limits

{% hint style="warning" %}
**On HTTP `429`, pause all requests from that IP for 10 seconds before retrying.** Requests you send during the pause still count. See [Handle 429 rate-limit errors](/solana/faq/error-handling/handle-429-rate-limit-errors.md).
{% endhint %}

* **Your rate tier sets the request budget for your IP, counted over a rolling 10-second window.** See [Rate and connection limits](/using-your-endpoint/rate-and-connection-limits.md).
* **Budget expensive methods separately.** Methods such as `getProgramAccounts` can have their own caps, depending on your rate tier. See [Solana per-method limits](/using-your-endpoint/rate-and-connection-limits.md#solana-per-method-limits).
* **Watch the `X-Ratelimit-*` response headers where your endpoint returns them.**
* **Add `/ratelimits` to your endpoint URL to see your limits.** See [Check your limits](/using-your-endpoint/rate-and-connection-limits.md#check-your-limits).

{% hint style="danger" %}
**Send backend requests with a token and browser requests from an allowed origin.** Never put a token in frontend code.
{% endhint %}

***

<i class="fa-life-ring">:life-ring:</i> Contact support by clicking the chat icon in your [customer dashboard](https://customers.triton.one)\ <i class="fa-briefcase">:briefcase:</i> Sales questions? [Contact us](https://triton.one/contact)\ <i class="fa-sparkles">:sparkles:</i> AI agent? Read [llms.txt](https://docs.triton.one/llms.txt)\ <i class="fa-rss">:rss:</i> Follow updates: [Blog](https://blog.triton.one) · [X](https://x.com/triton_one) · [YouTube](https://www.youtube.com/@triton_one_ltd) · [Telegram](https://t.me/tritonone) · [GitHub](https://github.com/rpcpool)
