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

# Tracking holder growth in real time

> Watch holder counts for positions, markets, and events as they change with the holder metrics room, and backfill historical candles from REST.

<Info>
  **What you'll build:** a live holder count for a market, event, or position that ticks as wallets enter and exit, with historical candles backfilled from REST. Useful for a "holders" counter on a market page or for spotting markets gaining holders fast.
</Info>

`polymarket_holder_metrics` streams real-time holder counts for positions, conditions (markets), and events, batched per block. It answers questions like "is this market gaining holders?" and "how concentrated is this position?" without polling. This recipe subscribes to the families you care about, tracks holder growth over time, and backfills history from REST.

## When to use this

* A "holders" counter on a market or event page that ticks up as wallets enter.
* Spotting momentum: an event whose holder count is climbing fast.
* Showing a position's distribution: total balance and cost basis across all holders.

## The three families

You subscribe with at least one id array, and only the families you filter for are delivered. Up to 500 identifiers total per subscription.

| Filter          | Event                            | Row                         |
| --------------- | -------------------------------- | --------------------------- |
| `position_ids`  | `holder_metrics_position_batch`  | `PositionHolderMetricsRow`  |
| `condition_ids` | `holder_metrics_condition_batch` | `ConditionHolderMetricsRow` |
| `event_slugs`   | `holder_metrics_event_batch`     | `EventHolderMetricsRow`     |

This is the only one of the PnL v3 rooms whose filters are all optional, but it still needs at least one id array to return data. Each row carries `ts` (Unix seconds), `block`, and `holder_count`. Position rows add `total_balance` and `total_cost_basis`, plus `condition_holder_count` and `event_holder_count` so a single position subscription can also report the holder counts of its parent market and event.

## Step 1: subscribe to what you are watching

Pass the ids for the surfaces on screen. A market page tracking one event and its markets passes both `event_slugs` and `condition_ids`.

<CodeGroup>
  ```typescript SDK theme={null}
  import { StructWebSocket } from "@structbuild/sdk";

  const ws = new StructWebSocket({ apiKey: "sk_live_xxx" });
  await ws.connect();

  await ws.subscribe("polymarket_holder_metrics", {
    event_slugs: ["us-election-2028"],
    condition_ids: ["0xabc..."],
  });
  ```

  ```json Subscribe message theme={null}
  {
    "type": "room_message",
    "payload": {
      "room_id": "polymarket_holder_metrics",
      "message": {
        "action": "subscribe",
        "event_slugs": ["us-election-2028"],
        "condition_ids": ["0xabc..."]
      }
    }
  }
  ```
</CodeGroup>

Only the families whose id array you supplied are delivered, so the subscription above yields `holder_metrics_event_batch` and `holder_metrics_condition_batch` but not position batches.

## Step 2: track holder growth for a market or event

Keep the latest count per id and, if you want a trend, append each tick to a small series so you can show direction.

```typescript theme={null}
const latestHolders = new Map<string, number>();
const eventSeries = new Map<string, { ts: number; holders: number }[]>();

ws.on("holder_metrics_event_batch", (event) => {
  for (const row of event.data) {
    latestHolders.set(row.event_slug, row.holder_count);
    const s = eventSeries.get(row.event_slug) ?? [];
    s.push({ ts: row.ts, holders: row.holder_count });
    eventSeries.set(row.event_slug, s);
  }
  renderHolderTrend();
});

ws.on("holder_metrics_condition_batch", (event) => {
  for (const row of event.data) {
    latestHolders.set(row.condition_id, row.holder_count);
  }
});
```

A rising `holder_count` between ticks is the clearest signal that a market is drawing fresh participation.

## Step 3: read a position's balance and cost basis

Position rows carry the distribution figures. `total_balance` is the combined outcome-token balance across all holders and `total_cost_basis` is what they paid in aggregate, so the two together describe how much capital is committed to that position.

```typescript theme={null}
ws.on("holder_metrics_position_batch", (event) => {
  for (const row of event.data) {
    renderPositionStats(row.position_id, {
      holders: row.holder_count,
      balance: row.total_balance,
      costBasis: row.total_cost_basis,
      marketHolders: row.condition_holder_count,
      eventHolders: row.event_holder_count,
    });
  }
});
```

## Backfilling historical candles from REST

The room streams changes going forward. To draw a holder-growth chart with history, pull candles from the REST history methods, then attach the live stream on top by the same id.

```typescript theme={null}
const { data: candles } = await client.holders.getPositionHoldersHistory({
  position_id: "123456789...",
});
```

The matching methods are `getPositionHoldersHistory`, `getMarketHoldersHistory`, and `getEventHoldersHistory`, one per grain. Seed the chart from the candles, then let the stream extend it.

## Push without a socket: webhooks

If you do not want to hold a socket open, the same data is available as webhooks: `position_holder_metrics`, `condition_holder_metrics`, and `event_holder_metrics`. Each requires its id array (`position_ids`, `condition_ids`, or `event_slugs` respectively) and delivers the same row as the matching stream family. Register one with a `POST /v1/webhooks` body specifying `url`, `event`, and `filters`. Use webhooks for server-side counters and the stream for live UIs.

## Follow-on

* Full payload schemas live on the [Holder metrics room](/websockets/rooms/holder-metrics) page.
* To pair holder growth with the trades driving it, see [Building a live trending feed](/guides/real-time-trending-events-and-markets).
