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

# Count Stream

> Live WebSocket stream of the KOL wallet count per token, updated as tracked wallets buy, for activity indicators and cluster detection.

A lightweight realtime counter. Every time a tracked KOL wallet buys a token, you receive the updated number of distinct KOL wallets that hold it. Use it for activity badges, heat indicators, or as a cheap trigger before pulling heavier data.

All CabalSpy streams share one WebSocket endpoint. You open a single connection, authenticate, then subscribe. This page covers the count channel.

## Endpoint

Connect to `wss://stream.cabalspy.xyz`.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const ws = new WebSocket("wss://stream.cabalspy.xyz?apiKey=YOUR_KEY");

  ws.onopen = () => {
    ws.send(JSON.stringify({ op: "subscribe", stream: "count", blockchain: "solana", token: "*" }));
  };

  ws.onmessage = (e) => {
    const msg = JSON.parse(e.data);
    if (msg.event === "wallet_count") {
      console.log(msg.data.mint, "kol count", msg.data.kol_count);
    }
  };
  ```

  ```python Python theme={null}
  import json, websocket

  def on_open(ws):
      ws.send(json.dumps({"op": "subscribe", "stream": "count", "blockchain": "solana", "token": "*"}))

  def on_message(ws, message):
      msg = json.loads(message)
      if msg.get("event") == "wallet_count":
          print(msg["data"]["mint"], msg["data"]["kol_count"])

  ws = websocket.WebSocketApp(
      "wss://stream.cabalspy.xyz?apiKey=YOUR_KEY",
      on_open=on_open, on_message=on_message,
  )
  ws.run_forever()
  ```
</CodeGroup>

## Authentication

Provide your API key as a query parameter, wss\://stream.cabalspy.xyz?apiKey=YOUR\_KEY, or as a header, Authorization: Bearer YOUR\_KEY. A connection without a valid key is closed immediately with code 1008.

## Subscribe

To start receiving counts, send a subscribe message after the connection opens.

```json Subscribe to all tokens on Solana theme={null}
{
  "op": "subscribe",
  "stream": "count",
  "blockchain": "solana",
  "token": "*"
}
```

The token field decides what you watch. Use "\*" to receive the count for every token, or a token mint or contract address to watch just one token. This stream is not split by wallet type, it always reports the KOL wallet count.

```json Watch one token theme={null}
{
  "op": "subscribe",
  "stream": "count",
  "blockchain": "solana",
  "token": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump"
}
```

<ParamField body="op" type="string" required>
  The operation. Use subscribe to start.
</ParamField>

<ParamField body="stream" type="string" required>
  Set to count for this stream.
</ParamField>

<ParamField body="blockchain" type="string" required>
  Chain. One of solana, bnb, base, eth.
</ParamField>

<ParamField body="token" type="string">
  Which token to watch. Either "\*" for all tokens, or a single token mint or contract address. Defaults to all tokens.
</ParamField>

## Unsubscribe and other operations

To stop, send the same fields with op unsubscribe.

```json Unsubscribe theme={null}
{
  "op": "unsubscribe",
  "stream": "count",
  "blockchain": "solana",
  "token": "*"
}
```

To see your active subscriptions, send op subscriptions. To check the connection is alive, send op ping and you get a pong back.

```json List your subscriptions theme={null}
{ "op": "subscriptions" }
```

## Event

<ResponseField name="success" type="boolean">
  Always true for stream events.
</ResponseField>

<ResponseField name="channel" type="string">
  The channel that produced the event, for example count.solana.
</ResponseField>

<ResponseField name="event" type="string">
  wallet\_count.
</ResponseField>

<ResponseField name="data" type="object">
  <Expandable title="data">
    <ResponseField name="blockchain" type="string">
      The chain.
    </ResponseField>

    <ResponseField name="mint" type="string">
      The token mint or contract.
    </ResponseField>

    <ResponseField name="kol_count" type="integer">
      Number of distinct KOL wallets holding the token.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json wallet_count theme={null}
  {
    "success": true,
    "channel": "count.solana",
    "event": "wallet_count",
    "data": {
      "blockchain": "solana",
      "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
      "kol_count": 5
    },
    "meta": {
      "request_id": "req_5162c7cf7f87",
      "version": "2.0.0",
      "timestamp": "2026-07-06T11:01:57Z"
    }
  }
  ```
</ResponseExample>

## Billing

Each delivered event counts against your plan, the same way a request does. A wildcard subscription on a busy chain can produce many events, so filter by token when you can.

## Heartbeat

The server sends WebSocket pings and expects pong, which standard clients answer automatically. A connection that stops answering is closed. You can also send op ping at any time.
