# Read a token's bubble map and holder clusters

> Get a Robinhood Chain token's top holders as a graph, with the funding and transfer links that group them. Real examples, with and without clusters.

Source: https://docs.crius.sh/guides/read-a-bubble-map/ · Updated 2026-10-28

Short answer

Call `GET /v1/robinhood/token/{address}/bubblemap?top=100` (Starter plan, 10 credits). `nodes` are the top holders with their share (`pct`), USD value and `tags`; `edges` are funding, shared funders and token transfers between them; `clusters` group linked holders with their total `pct`, members and the `links` that join them. Pools, lockers, hooks and burn addresses are listed under `hidden_infra`, not drawn.

[GET `/token/{address}/bubblemap`](https://docs.crius.sh/reference/wallet-graph/bubble-map/)

A bubble map shows a token’s largest holders as bubbles and draws lines between the ones that are connected, so you can see at a glance whether “the top 20 holders” are 20 people or one person with 20 wallets. Crius builds it from on-chain funding and token transfers on Robinhood Chain. It only links wallets on evidence that means something (the wallet that first funded them, transfers between them) and leaves out pools, lockers and exchanges, which touch everyone.

## Get the map in one call

Example [Starter plan · 10 credits](https://docs.crius.sh/reference/wallet-graph/bubble-map/)

### Two clusters among Rebot's top holders

Rebot (0x192b126efea71ca5e7767bc6fc53038d869fbbba) was an insider launch. Are any of its top 100 holders today the same person?

GET/v1/robinhood/token/0x192b126efea71ca5e7767bc6fc53038d869fbbba/bubblemap?top=100

 

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/token/0x192b126efea71ca5e7767bc6fc53038d869fbbba/bubblemap?top=100" \
  -H "x-api-key: $CRIUS_API_KEY"
```

**JavaScript**

```js
const res = await fetch("https://api.crius.sh/v1/robinhood/token/0x192b126efea71ca5e7767bc6fc53038d869fbbba/bubblemap?top=100", {
  headers: { "x-api-key": process.env.CRIUS_API_KEY },
});
const { data, meta } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.crius.sh/v1/robinhood/token/0x192b126efea71ca5e7767bc6fc53038d869fbbba/bubblemap?top=100",
    headers={"x-api-key": os.environ["CRIUS_API_KEY"]},
)
body = r.json()
print(body["data"])
```

**Real response 200 Captured Oct 28, 2026 · 227 lines (arrays trimmed)**

```json
{
  "data": {
    "block": null,
    "clusters": [
      {
        "id": "c_80b9b545",
        "includes_dev": false,
        "links": {
          "funding_between": 0,
          "shared_funders": [
            {
              "address": "0x795834684cdec507ea9ee240fdb7e908567dd316",
              "wallets": 2
            }
          ],
          "token_transfers": 0
        },
        "members": [
          "0xdebabd206e5a73dd81a9211533a1bd610c006d20",
          "0xf0fd2e7718ea59a6ddfe884c7e4714ae2dd5610a"
        ],
        "pct": 3.60847,
        "risk": "medium",
        "root_funder": "0x795834684cdec507ea9ee240fdb7e908567dd316",
        "wallets": 2
      },
      {
        "id": "c_377c5b",
        "includes_dev": false,
        "links": {
          "funding_between": 1,
          "shared_funders": [],
          "token_transfers": 0
        },
        "members": [
          "0x4eec10e9c115a7ea67b59eea59c3a3c777fab236",
          "0xa0686afb77ed32fbb402a39642d05158b9fa4c96"
        ],
        "pct": 2.56134,
        "risk": "low",
        "root_funder": "0xa0686afb77ed32fbb402a39642d05158b9fa4c96",
        "wallets": 2
      }
    ],
    "edges": [
      {
        "block": 78435467,
        "eth": 1.2,
        "from": "0x795834684cdec507ea9ee240fdb7e908567dd316",
        "hub": false,
        "to": "0xdebabd206e5a73dd81a9211533a1bd610c006d20",
        "type": "common_funder"
      },
      {
        "block": 9427558,
        "eth": 2,
        "from": "0xa0686afb77ed32fbb402a39642d05158b9fa4c96",
        "hub": false,
        "to": "0x4eec10e9c115a7ea67b59eea59c3a3c777fab236",
        "type": "funding"
      },
      {
        "block": 94538219,
        "eth": 2.5,
        "from": "0x795834684cdec507ea9ee240fdb7e908567dd316",
        "hub": false,
        "to": "0xf0fd2e7718ea59a6ddfe884c7e4714ae2dd5610a",
        "type": "common_funder"
      }
    ],
    "hidden_infra": [
      {
        "address": "0x8366a39cc670b4001a1121b8f6a443a643e40951",
        "label": "uniswap_v4_pool_manager",
        "pct": 70.8524,
        "tags": [
          "pool"
        ]
      },
      {
        "address": "0x267444d099b10fb5ed7c3cc7b7c767adca574952",
        "label": "pons_v2_launch_locker",
        "pct": 8.16327,
        "tags": [
          "lp_locker"
        ]
      },
      {
        "address": "0xe5e702641ea86f4ae6cc3cdaed2b886f976be044",
        "label": "pons_v2_meme_hook",
        "pct": 0.000056807,
        "tags": [
          "launchpad"
        ]
      },
      {
        "address": "0xf69cd0fe7280773bb9b7c93ab68420d07290afa9",
        "label": null,
        "pct": 0.00000391777,
        "tags": [
          "contract"
        ]
      },
      {
        "address": "0x8cc5b884c33a261fe6aa6499bc7315d5aed57c67",
        "label": null,
        "pct": 0.0000000000000000000000002,
        "tags": [
          "contract"
        ]
      },
      {
        "address": "0x8f10b468b06c6fd214b65f87778827f7d113f996",
        "label": null,
        "pct": 0.0000000000000000000000001,
        "tags": [
          "contract"
        ]
      },
      {
        "address": "0xe6eeda550918638529c6cf2ea14f9ea0572d6f88",
        "label": null,
        "pct": 0.0000000000000000000000001,
        "tags": [
          "contract"
        ]
      }
    ],
    "nodes": [
      {
        "cluster": "c_80b9b545",
        "id": "0xdebabd206e5a73dd81a9211533a1bd610c006d20",
        "label": null,
        "pct": 2.19541,
        "tags": [
          "smart_account",
          "fomo",
          "whale"
        ],
        "value_usd": 88.6343
      },
      {
        "cluster": null,
        "id": "0xb6815093cf0108d146aee2e98e53c17287c42393",
        "label": null,
        "pct": 1.86,
        "tags": [
          "whale"
        ],
        "value_usd": 75.0931
      },
      {
        "cluster": null,
        "id": "0xc3403905b4e0ffaf973663ad261639087091a5da",
        "label": null,
        "pct": 1.68482,
        "tags": [
          "smart_account",
          "fomo",
          "whale"
        ],
        "value_usd": 68.0207
      },
      {
        "cluster": "c_377c5b",
        "id": "0x4eec10e9c115a7ea67b59eea59c3a3c777fab236",
        "label": null,
        "pct": 1.46153,
        "tags": [
          "whale"
        ],
        "value_usd": 59.0056
      },
      {
        "cluster": "c_80b9b545",
        "id": "0xf0fd2e7718ea59a6ddfe884c7e4714ae2dd5610a",
        "label": null,
        "pct": 1.41306,
        "tags": [
          "smart_account",
          "whale"
        ],
        "value_usd": 57.049
      },
      {
        "cluster": "c_377c5b",
        "id": "0xa0686afb77ed32fbb402a39642d05158b9fa4c96",
        "label": null,
        "pct": 1.09981,
        "tags": [
          "whale"
        ],
        "value_usd": 44.4023
      },
      {
        "cluster": null,
        "id": "0x1795eacd1a377133002de3bca335336a19dfa2ca",
        "label": null,
        "pct": 1.03781,
        "tags": [
          "whale"
        ],
        "value_usd": 41.8992
      },
      {
        "cluster": null,
        "id": "0xa2bfbc13abbf678ed8c743e662ba43fbe18159ea",
        "label": null,
        "pct": 1,
        "tags": [
          "whale"
        ],
        "value_usd": 40.3726
      }
    ],
    "token": "0x192b126efea71ca5e7767bc6fc53038d869fbbba"
  },
  "meta": {
    "block": 100415559,
    "block_age_ms": 766,
    "block_ts": 1793225982000,
    "chain": "robinhood",
    "finalized_block": 100405028,
    "lag_ms": 31,
    "safe_block": 100408671
  }
}
```

What this tells you

-   `clusters` has two entries. The larger, `c_80b9b545`, joins `0xdebabd206e5a73dd81a9211533a1bd610c006d20` and `0xf0fd2e7718ea59a6ddfe884c7e4714ae2dd5610a`: together `pct: 3.60847` of supply, so `risk: "medium"` (over 3%).
-   Why they’re linked: `links.shared_funders` names `0x795834684cdec507ea9ee240fdb7e908567dd316`, which first funded both (`wallets: 2`). It is also the `root_funder`. The two `common_funder` edges show it sent 1.2 ETH at block 78435467 and 2.5 ETH at block 94538219.
-   The second cluster, `c_377c5b`, is a direct link: `links.funding_between: 1`. The `funding` edge shows `0xa0686afb77ed32fbb402a39642d05158b9fa4c96` sent `0x4eec10e9c115a7ea67b59eea59c3a3c777fab236` its first 2 ETH at block 9427558, so the funder is a member and the `root_funder`. Together they hold `pct: 2.56134`: `risk: "low"`.
-   All three funding edges are far older than Rebot: its launch transaction was at block 100238938. A link records how a wallet was first funded, which can tie wallets together long before they bought this token.
-   Each member node carries its cluster id (`cluster: "c_80b9b545"`), and `includes_dev: false` on both clusters: the developer isn’t among them.
-   `hidden_infra` shows where most of the supply is: the Uniswap v4 PoolManager `0x8366a39cc670b4001a1121b8f6a443a643e40951` holds 70.85% (the pool’s side) and the Pons launch locker `0x267444d099b10fb5ed7c3cc7b7c767adca574952` 8.16%. The largest real holder has 2.20%.

[Bubble map reference](https://docs.crius.sh/reference/wallet-graph/bubble-map/) [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20Two%20clusters%20among%20Rebot's%20top%20holders&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fguides%2Fread-a-bubble-map%2F%23clusters%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Ftoken%2F0x192b126efea71ca5e7767bc6fc53038d869fbbba%2Fbubblemap%3Ftop%3D100%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

Example [Starter plan · 10 credits](https://docs.crius.sh/reference/wallet-graph/bubble-map/)

### No clusters at all: sockets

Are the top 50 holders of sockets (0xddccd4690cc99cf19d2e0bdbcb390d17e913958a) connected to each other?

GET/v1/robinhood/token/0xddccd4690cc99cf19d2e0bdbcb390d17e913958a/bubblemap?top=50

 

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/token/0xddccd4690cc99cf19d2e0bdbcb390d17e913958a/bubblemap?top=50" \
  -H "x-api-key: $CRIUS_API_KEY"
```

**JavaScript**

```js
const res = await fetch("https://api.crius.sh/v1/robinhood/token/0xddccd4690cc99cf19d2e0bdbcb390d17e913958a/bubblemap?top=50", {
  headers: { "x-api-key": process.env.CRIUS_API_KEY },
});
const { data, meta } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.crius.sh/v1/robinhood/token/0xddccd4690cc99cf19d2e0bdbcb390d17e913958a/bubblemap?top=50",
    headers={"x-api-key": os.environ["CRIUS_API_KEY"]},
)
body = r.json()
print(body["data"])
```

**Real response 200 Captured Oct 28, 2026 · 138 lines (arrays trimmed)**

```json
{
  "data": {
    "block": null,
    "clusters": [],
    "edges": [],
    "hidden_infra": [
      {
        "address": "0x8366a39cc670b4001a1121b8f6a443a643e40951",
        "label": "uniswap_v4_pool_manager",
        "pct": 22.2145,
        "tags": [
          "pool"
        ]
      },
      {
        "address": "0x267444d099b10fb5ed7c3cc7b7c767adca574952",
        "label": "pons_v2_launch_locker",
        "pct": 8.16327,
        "tags": [
          "lp_locker"
        ]
      },
      {
        "address": "0xe5e702641ea86f4ae6cc3cdaed2b886f976be044",
        "label": "pons_v2_meme_hook",
        "pct": 6.06241,
        "tags": [
          "launchpad"
        ]
      },
      {
        "address": "0xbe0b139abc90723af76a89d3051f60ba1b64c8d9",
        "label": null,
        "pct": 1,
        "tags": [
          "contract"
        ]
      },
      {
        "address": "0xdead000000000000000000000000000000000000",
        "label": null,
        "pct": 0.81637,
        "tags": [
          "burn"
        ]
      },
      {
        "address": "0x0afeb98a5b40bc38e9cf5a3f202c17843a7ce553",
        "label": null,
        "pct": 0.168848,
        "tags": [
          "contract"
        ]
      }
    ],
    "nodes": [
      {
        "cluster": null,
        "id": "0xe1a5961d61200006577f2e96114d212889213cd6",
        "label": null,
        "pct": 2.82829,
        "tags": [
          "smart_account",
          "whale"
        ],
        "value_usd": 1286.54
      },
      {
        "cluster": null,
        "id": "0xa4109b8d391723d8f6bcfc5d75e6996f61062f76",
        "label": null,
        "pct": 2.70423,
        "tags": [
          "smart_account",
          "fomo",
          "whale"
        ],
        "value_usd": 1230.11
      },
      {
        "cluster": null,
        "id": "0xf2caeb616fb22a8acc00afbaeee83b24f18b354b",
        "label": null,
        "pct": 2.23269,
        "tags": [
          "smart_account",
          "fomo",
          "whale"
        ],
        "value_usd": 1015.61
      },
      {
        "cluster": null,
        "id": "0xb9b642020e216e84887ad414e067928e380bbbd5",
        "label": null,
        "pct": 1.77186,
        "tags": [
          "whale"
        ],
        "value_usd": 805.992
      },
      {
        "cluster": null,
        "id": "0xc9cafef2258a07f8455da92438360318b34848e2",
        "label": null,
        "pct": 1.73578,
        "tags": [
          "smart_account",
          "fomo",
          "whale"
        ],
        "value_usd": 789.58
      },
      {
        "cluster": null,
        "id": "0xc51c3340b898a67fed7c9f18db75b346dd04f8a0",
        "label": null,
        "pct": 1.63331,
        "tags": [
          "smart_account",
          "fomo",
          "whale"
        ],
        "value_usd": 742.968
      }
    ],
    "token": "0xddccd4690cc99cf19d2e0bdbcb390d17e913958a"
  },
  "meta": {
    "block": 100406890,
    "block_age_ms": 885,
    "block_ts": 1793225087000,
    "chain": "robinhood",
    "finalized_block": 100397649,
    "lag_ms": 30,
    "safe_block": 100401329
  }
}
```

What this tells you

-   `clusters: []` and `edges: []`: none of the top 50 holders funded each other, shared a funder or sent each other tokens. Each bubble stands alone.
-   The largest holder, `0xe1a5961d61200006577f2e96114d212889213cd6`, has `pct: 2.82829` (about $1,287, `value_usd`). The holder base is spread out.
-   `tags` say who the holders are: `whale` (1% or more of supply), `smart_account`, and `fomo` for smart accounts created by the FOMO trading app, as with `0xa4109b8d391723d8f6bcfc5d75e6996f61062f76` (2.70%).
-   `hidden_infra` lists the PoolManager (22.21%), the Pons launch locker (8.16%), the PonsV2MemeHook `0xe5e702641ea86f4ae6cc3cdaed2b886f976be044` (6.06%) and the burn address `0xdead000000000000000000000000000000000000` (0.82%). Left on the map, the PoolManager would look like the largest holder by far.

[Bubble map reference](https://docs.crius.sh/reference/wallet-graph/bubble-map/) [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20No%20clusters%20at%20all%3A%20sockets&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fguides%2Fread-a-bubble-map%2F%23clean-map%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Ftoken%2F0xddccd4690cc99cf19d2e0bdbcb390d17e913958a%2Fbubblemap%3Ftop%3D50%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

## How to read the map

**Nodes** are holders: `id`, `pct` of supply, `value_usd`, `label`, `tags` and `cluster` (`null` when unlinked). Size them by `pct` and color them by `cluster`.

**Edges** say why two bubbles are connected. Funding edges carry `from`, `to`, `type`, `eth`, `block` and `hub`:

| Edge `type` | Means |
| --- | --- |
| `funding` | One holder sent the other its first ETH (at least 0.00001 ETH), like `0xa0686afb77ed32fbb402a39642d05158b9fa4c96` → `0x4eec10e9c115a7ea67b59eea59c3a3c777fab236` above. |
| `common_funder` | An outside wallet that first funded two or more of the shown holders, like `0x795834684cdec507ea9ee240fdb7e908567dd316`. |
| `transfers` | Holders sent this token to each other. |

**Clusters** are groups of holders joined by those links:

| Field | Meaning |
| --- | --- |
| `id` | Cluster id, also set on each member node's `cluster`. |
| `wallets`, `members` | How many holders are in it, and their addresses, largest first. |
| `pct` | Share of supply the cluster holds together. |
| `risk` | `high` above 10% of supply, `medium` above 3%, else `low`. |
| `links` | Why they're one cluster: `shared_funders` (each with the number of members it funded), and counts of `funding_between` members and `token_transfers` between them. |
| `root_funder` | The funder shared by the most members, else the member that funded the most others. Never an exchange or bridge. |
| `includes_dev` | The token's developer is in the cluster. |

What doesn’t link wallets matters as much: funding from exchanges, bridges, bots and app relayers (one signer paying the same 100+ wallets again and again), funders that paid more than 500 wallets, dust sends, and lookalike addresses used for address poisoning. Pass `include=hubs` or `include=funders` to see those funders, and `edges=funding,transfers` to choose which edge types come back.

## Use it in your app

1.  **Fetch the map with a Starter key.** `top=100` is a good default; each call costs 10 credits, so cache it per token for a few minutes.
    
2.  **Draw it with any force-directed graph library.** `nodes` and `edges` map directly to nodes and links (`from` → source, `to` → target).
    
3.  **Lead with the clusters.** Show each cluster’s `pct` and `risk` next to the map, and say when `includes_dev` is `true`.
    
4.  **List `hidden_infra` separately.** Users want to know where the rest of the supply is: in the pool, locked or burned.
    

```js
// Turn a bubble map into nodes and links for a force-directed graph (d3-force, vis-network, …).
const token = "0x192b126efea71ca5e7767bc6fc53038d869fbbba"; // Rebot
const res = await fetch(`https://api.crius.sh/v1/robinhood/token/${token}/bubblemap?top=100`, {
  headers: { "x-api-key": process.env.CRIUS_API_KEY },
});
const { data } = await res.json();

const nodes = data.nodes.map((n) => ({ id: n.id, radius: 4 + Math.sqrt(n.pct ?? 0) * 6, group: n.cluster ?? n.id }));
const ids = new Set(nodes.map((n) => n.id));
for (const e of data.edges) for (const a of [e.from, e.to]) if (!ids.has(a)) ids.add(a) && nodes.push({ id: a, radius: 3, group: "funder" });
const links = data.edges.map((e) => ({ source: e.from, target: e.to, kind: e.type }));
for (const c of data.clusters) console.log(`cluster ${c.id}: ${c.wallets} wallets, ${c.pct}% (${c.risk})`);
console.log(`not on the map: ${data.hidden_infra.map((h) => `${h.label ?? h.tags[0]} ${h.pct}%`).join(", ")}`);
```

Clusters at launch

The bubble map links today’s top holders. To see whether the launch buyers were linked, which matters even after they sold, use [`/bundles`](https://docs.crius.sh/guides/detect-bundles-and-snipers/): it builds the same kind of clusters over the first 300 blocks of trading.

## Frequently asked questions

**What is a bubble map?**

A picture of a token's top holders where each holder is a bubble sized by how much it holds, and lines connect holders that are linked: one funded the other, they were funded by the same wallet, or they moved the token between them. A big group of connected bubbles is one owner spread over many wallets.

**Why isn't the liquidity pool on the bubble map?**

Because it isn't a holder. Pools, the Uniswap v4 PoolManager, LP lockers, hooks, burn addresses, routers, other contracts and exchanges are moved to `hidden_infra` with their share of supply. Everyone trades through them, so drawing them would link unrelated wallets. Add `include=infra` to draw them; they still never join a cluster.

**Why are two wallets funded by the same exchange not in one cluster?**

Exchanges, bridges, bots and app relayers fund thousands of unrelated people, so they never link wallets. A funder that paid more than 500 wallets is treated the same way. `include=hubs` shows those funding edges, marked `hub: true`, without using them for clusters.

**Can I see a bubble map from the past?**

Yes: pass `block` and the map uses holder balances at that block, for example to see who held a token at its peak.

**How many holders can the map show?**

`top` sets how many holders become nodes: 100 by default, up to 500. Infrastructure doesn't use up places, so you always get `top` real holders when the token has that many.

## Related

[Guide **Detect bundles & snipers** Find out who bought a Robinhood Chain token's launch, how much of the supply snipers and bundles took and whether they still hold it, with a real insider launch that fell 97%. Read](https://docs.crius.sh/guides/detect-bundles-and-snipers/) [Guide **Token holders** Robinhood Chain token holders API: get any token's top holders in one call, with balance, share of supply, USD value, labels, holder count and top-10 share. Read](https://docs.crius.sh/guides/get-token-holders/) [Guide **Connected wallets** Find who funded a Robinhood Chain wallet, which wallets it funded, who it swaps tokens with and who shares its funder, to spot alt wallets, dev links, sybils. Read](https://docs.crius.sh/guides/find-connected-wallets/) [Concept **Holder classes** How the Crius API tells real holders from pools, the PoolManager, lockers and contracts, and how it tags devs, snipers, whales and smart accounts. Read](https://docs.crius.sh/concepts/holder-classes/) [Concept **Launch risk** How Crius spots insider control of a Robinhood Chain token with a clean contract (snipers, wallet farms, uniform holders, LP control) and the thresholds it uses. Read](https://docs.crius.sh/concepts/launch-risk/) [API reference **Bubble map API** The top holders (top, up to 500) as nodes and the links between them as edges: funding between holders, token transfers between holders, and funders shared by two or more of them. Read](https://docs.crius.sh/reference/wallet-graph/bubble-map/)
