Docs

state_getKeysPaged - Kusama RPC Method

Enumerate storage keys with pagination on Kusama. Iterate over storage maps like accounts, validators, and assets efficiently with cursor-based pagination.

Returns storage keys matching a prefix with cursor-based pagination on Kusama. This is the standard way to iterate over storage maps (like System.Account, Staking.Validators, or any pallet storage map) without loading all keys into memory at once.

Why Kusama? Build on Polkadot's canary network for real-world testing with live economic conditions with 7-day governance cycles (vs 1 month on Polkadot), lower bonding requirements, live KSM token economy, and first-to-market feature testing.

When to Use This Method

state_getKeysPaged is essential for experimental dApp developers, parachain teams, and early adopters validating new features:

  • Storage Map Iteration -- Enumerate all entries in a storage map (accounts, balances, staking data) on Kusama
  • Data Export and Indexing -- Bulk export on-chain state for analytics, indexers, and data pipelines for parachain experimentation, early feature deployment, and production-grade testing with real value
  • Account Enumeration -- List all accounts that have balances, staking positions, or other on-chain state
  • State Migration Tooling -- Iterate storage for runtime upgrades, audits, or cross-chain migration

Code Examples

Common Use Cases

1. Enumerate All Accounts

List all accounts with on-chain state and fetch their balances:

JavaScript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function enumerateAccounts(api, pageSize = 200) {
  const prefix = api.query.system.account.keyPrefix();
  const allKeys = [];
  let startKey;

  // Paginate through all account keys
  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    if (keys.length === 0) break;
    allKeys.push(...keys);
    startKey = keys[keys.length - 1];
  }

  console.log(`Found ${allKeys.length} accounts`);

  // Fetch balances in batches using queryStorageAt
  const batchSize = 100;
  for (let i = 0; i < allKeys.length; i += batchSize) {
    const batch = allKeys.slice(i, i + batchSize);
    const results = await api.rpc.state.queryStorageAt(batch);

    results[0].changes.forEach(([key, value]) => {
      if (value) {
        const accountInfo = api.createType('AccountInfo', value);
        console.log(`  Free: ${accountInfo.data.free.toHuman()}`);
      }
    });
  }
}

2. Export Storage Map for Analysis

Export all entries of a specific storage map for offline analysis:

JavaScript
async function exportStorageMap(api, palletName, storageName) {
  const prefix = api.query[palletName][storageName].keyPrefix();
  const entries = [];
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 500, startKey);
    if (keys.length === 0) break;

    const values = await api.rpc.state.queryStorageAt(keys);

    for (const [key, value] of values[0].changes) {
      entries.push({
        key: key.toHex(),
        value: value ? value.toHex() : null
      });
    }

    startKey = keys[keys.length - 1];
    console.log(`Exported ${entries.length} entries...`);
  }

  return entries;
}

// Export all System.Account entries
const accounts = await exportStorageMap(api, 'system', 'account');

3. Count Storage Items by Prefix

Get a count of entries in any storage map without fetching values:

JavaScript
async function countStorageKeys(api, prefix) {
  let count = 0;
  let startKey;

  while (true) {
    const keys = await api.rpc.state.getKeysPaged(prefix, 1000, startKey);
    if (keys.length === 0) break;
    count += keys.length;
    startKey = keys[keys.length - 1];
  }

  return count;
}

// Count total accounts
const accountPrefix = api.query.system.account.keyPrefix();
const totalAccounts = await countStorageKeys(api, accountPrefix);
console.log(`Total accounts on chain: ${totalAccounts}`);

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32603Internal errorVerify the prefix is a valid hex string; reduce count if the request is too large
-32602Invalid paramsEnsure prefix and startKey are properly hex-encoded with 0x prefix
-32005Rate limit exceededReduce page size or add delays between pagination requests
State prunedHistorical state unavailableUse an archive node for queries at old block hashes
TimeoutResponse too slowReduce count parameter (try 100 instead of 1000)