← Protocols
Polkadot.js API
Other Chain·Multi-chain

Polkadot.js API

01Description

Polkadot.js is the canonical JavaScript/TypeScript stack for Polkadot, Kusama, and any Substrate-based chain. `@polkadot/api` connects to a node via WebSocket, decodes SCALE-encoded state, and submits signed extrinsics; `@polkadot/extension-dapp` connects to the polkadot{.js}, Talisman, SubWallet, and Nova browser extensions.

02Best for
  • 01Polkadot / Kusama / parachain dapps
  • 02Substrate chain queries and extrinsics
  • 03Polkadot.js / Talisman / SubWallet auth
  • 04governance, staking, and XCM transfers
  • 05any FRAME-based appchain
03Install
  • pnpm add @polkadot/api @polkadot/extension-dapp @polkadot/util @polkadot/util-crypto
04Environment variables
VariableScopeDescription
NEXT_PUBLIC_POLKADOT_WS_URLClientSubstrate node WebSocket endpoint, e.g. wss://rpc.polkadot.io, wss://kusama-rpc.polkadot.io, or a parachain RPC.
NEXT_PUBLIC_POLKADOT_APP_NAMEClientHuman-readable app name shown in the wallet permission prompt (e.g. 'My Dapp').
05Prompt snippet
Use `@polkadot/api` to talk to any Substrate chain and `@polkadot/extension-dapp` for wallet connection. Open the API with `const provider = new WsProvider(NEXT_PUBLIC_POLKADOT_WS_URL); const api = await ApiPromise.create({ provider });`. Read storage via the typed `api.query.<pallet>.<storageItem>(...)` (e.g. `api.query.system.account(addr)`), subscribe with the same call passing a callback, and decode results with `result.toJSON()` / `.toHuman()`. Build extrinsics with `api.tx.<pallet>.<call>(...args)` and sign + send via `tx.signAndSend(account, { signer: injector.signer }, ({ status, events }) => { ... })` after `await web3Enable(APP_NAME); const accounts = await web3Accounts(); const injector = await web3FromAddress(accounts[0].address);`. Use `api.rpc.chain.subscribeNewHeads()` for new-block streams. SS58 address formatting differs per chain — use `encodeAddress(pubkey, ss58Prefix)` from `@polkadot/util-crypto`.
06Gotchas
  • Substrate uses SCALE codec (not JSON / RLP / BCS) — every storage value, extrinsic argument, and event is SCALE-encoded; calling `.toString()` on raw bytes gives garbage. Always use `.toJSON()` / `.toHuman()` or typed `Codec` accessors.
  • Each chain has its own SS58 address prefix (Polkadot=0, Kusama=2, generic Substrate=42); the same public key encodes to different addresses per chain, so compare on the underlying public key (`u8a` / hex), not the string.
  • Finality is two-stage: BABE produces blocks (~6s) and GRANDPA finalizes them (~12–60s). `signAndSend` reports `inBlock` quickly but for safe settlement wait for `finalized` status — confusing the two leads to reorg-sensitive UX.
  • Fees are paid in the chain's native token (DOT, KSM, parachain token) and computed via a weight + length model with multiplier — `api.tx.X.Y(...).paymentInfo(account)` returns the partial fee but the actual deducted fee can vary with the runtime's congestion multiplier.
  • Runtime upgrades (forkless) can change pallet indices and call signatures mid-session; pin `@polkadot/api` to a version that knows the current runtime and call `api.runtimeMetadata` after a known upgrade height.
  • Cross-chain (XCM) transfers are constructed via `api.tx.xcmPallet.limitedReserveTransferAssets(...)` (or `xTokens` on parachains) — wrong `MultiLocation` / `MultiAsset` encoding silently traps the message and assets are stuck until governance recovery.
07Alternatives