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

# Holders

Query token balances by Spark address using the `SparkReadonlyClient`. Public queries respect [privacy mode](/wallets/privacy): if a wallet is private, unauthenticated requests return empty results.

<Frame className="chill">
  <img className="block dark:hidden" src="https://mintcdn.com/lightspark/OQ3nooAPVcDN2i7X/images/issuance/token-balances-light.png?fit=max&auto=format&n=OQ3nooAPVcDN2i7X&q=85&s=1a25583a6cd066d28ce3a9c6727a4b5e" alt="Holders" width="3840" height="2160" data-path="images/issuance/token-balances-light.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/lightspark/OQ3nooAPVcDN2i7X/images/issuance/token-balances.png?fit=max&auto=format&n=OQ3nooAPVcDN2i7X&q=85&s=f631bd99eeeb4b76230c40dab40ae85c" alt="Holders" width="3840" height="2160" data-path="images/issuance/token-balances.png" />
</Frame>

## Your Balance

Check how many tokens you hold:

```typescript theme={null}
const balances = await wallet.getIssuerTokenBalances();
for (const { tokenIdentifier, balance } of balances) {
  if (!tokenIdentifier) continue;
  console.log(tokenIdentifier, balance);
}
```

## Check Any Address

Pass an address to check someone else's balance:

```typescript theme={null}
import { SparkReadonlyClient } from "@buildonspark/spark-sdk";

const client = SparkReadonlyClient.createPublic({ network: "MAINNET" });

const [tokenIdentifier] = await wallet.getIssuerTokenIdentifiers();
if (!tokenIdentifier) throw new Error("No token identifiers found for this issuer");

const holderBalances = await client.getTokenBalance("spark1abc...", [tokenIdentifier]);
const info = holderBalances.get(tokenIdentifier);

console.log("User balance:", info?.ownedBalance);
```

## Display Amounts

Convert base units to human-readable format:

```typescript theme={null}
const holderBalances = await client.getTokenBalance("spark1abc...", [tokenIdentifier]);
const info = holderBalances.get(tokenIdentifier);
if (!info) throw new Error("No balance found (zero balance, unknown token, or privacy mode)");

function formatUnits(amount: bigint, decimals: number): string {
  const negative = amount < 0n;
  const value = negative ? -amount : amount;
  const base = 10n ** BigInt(decimals);
  const whole = value / base;
  const fraction = value % base;

  const fractionStr = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
  const out = fractionStr ? `${whole.toString()}.${fractionStr}` : whole.toString();
  return negative ? `-${out}` : out;
}

console.log(`${formatUnits(info.ownedBalance, info.tokenMetadata.decimals)} ${info.tokenMetadata.tokenTicker}`);
```

## All Token Balances

Get all token balances for an address:

```typescript theme={null}
const tokenBalances = await client.getTokenBalance("spark1abc...");

function formatUnits(amount: bigint, decimals: number): string {
  const negative = amount < 0n;
  const value = negative ? -amount : amount;
  const base = 10n ** BigInt(decimals);
  const whole = value / base;
  const fraction = value % base;

  const fractionStr = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
  const out = fractionStr ? `${whole.toString()}.${fractionStr}` : whole.toString();
  return negative ? `-${out}` : out;
}

for (const [tokenId, info] of tokenBalances) {
  console.log(`${info.tokenMetadata.tokenTicker}: ${formatUnits(info.ownedBalance, info.tokenMetadata.decimals)}`);
}
```

## Listen for Changes

Get notified when balances change:

```typescript theme={null}
wallet.on("transfer:claimed", async (transferId, newBalance) => {
  console.log("Transfer received:", transferId);
  
  const updated = await wallet.getBalance();
  console.log("New balance:", updated.balance);
});
```
