> ## 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.

# Trade Feed widgets

> Embed a + Trade Feed button on trader profiles and the signed-in user's live Trade Feed on any page, with one script tag and your instance's public client_id. Includes the browser API behind them.

Two widgets bring the [Trade Feed](https://docs.cabalspy.xyz/cabalspy-id/trade-feed.md) into your pages without a backend. Both come from the same `widget.js` as the [login button](https://docs.cabalspy.xyz/cabalspy-id/login-button.md) and the [thesis widget](https://docs.cabalspy.xyz/cabalspy-id/theses.md#path-1-the-widget):

* **+ Trade Feed button** for one trader: adds the trader to the signed-in user's Trade Feed, or removes them. Shows in how many Trade Feeds the trader is.
* **Trade Feed**: the signed-in user's feed, live, with filters for buys, sells and theses.

```html theme={null}
<div data-csid-trade-feed-button data-client-id="csid_..." data-trader="MazeCCC"></div>
<div data-csid-trade-feed data-client-id="csid_..."></div>
<script src="https://id.cabalspy.xyz/widget.js" async></script>
```

> [!NOTE]
>
> `data-client-id` is your instance's public client\_id (Instance ID, `csid_...`), shown in the [API Dashboard](https://apidashboard.cabalspy.xyz) under **CabalSpy ID**, **Instances**. It is not the API key and not a secret. If it is missing, `widget.js` uses the client id of a `data-csid-login` button on the same page. The widgets only load on your instance's sites, the same as the thesis widget, see [Client ID](https://docs.cabalspy.xyz/cabalspy-id/theses-browser-api.md#client-id).

## + Trade Feed button

Put it next to a trader's name or on their profile page.

```html theme={null}
<div data-csid-trade-feed-button data-client-id="csid_..." data-trader="MazeCCC" data-size="md"></div>
```

* Signed out, a click opens the sign-in (see [Sign-in](#sign-in)) and adds the trader right after.
* In the Trade Feed, the button shows **In Trade Feed ✓**. A click asks **Remove from Trade Feed?** and a second click within 4 seconds removes the trader.
* For traders who keep their trading private, and on the user's own profile, the button is disabled.
* With `data-show-count`, it shows "in N Trade Feeds" next to the button.

`data-trader` takes a handle (with or without @) or a csid\_id.

## Trade Feed

```html theme={null}
<div data-csid-trade-feed data-client-id="csid_..." data-filter="all" data-max-height="640"></div>
```

Shows the signed-in user's Trade Feed with the same items as the [Data API](https://docs.cabalspy.xyz/cabalspy-id/trade-feed-api.md#get-the-feed): trades with labels, amounts, PnL of sells, wallet and transaction links, and theses. New items appear at the top within a few seconds, and **Load more** pages back. Signed out, it shows **Sign in to see your Trade Feed**.

The footer links to the user's Trade Feed settings on CabalSpy ID, where they manage traders and alert filters. Instances with **No CabalSpy ID branding** on do not show this link.

## Attributes

The widgets use the design you saved for your instance's thesis widget on the [Theses](https://docs.cabalspy.xyz/cabalspy-id/dashboard.md#theses) tab. Every attribute overrides it for that one embed.

| Attribute | Widget | Values |
| - | - | - |
| `data-client-id` | Both | Required. Your Instance ID. Falls back to the client id of a `data-csid-login` button on the page. |
| `data-trader` | Button | Required. Handle (with or without @) or csid\_id. |
| `data-size` | Button | `sm`, `md` (default) or `lg`. |
| `data-show-count` | Button | `true` (default) or `false`. |
| `data-width` | Button | Width in pixels. Default 290, or 170 without the count. |
| `data-filter` | Feed | Starting filter: `all` (default), `buys`, `sells` or `theses`. |
| `data-show-header` | Feed | `true` (default) or `false`. The header shows "Trade Feed" and the user's handle and number of traders. |
| `data-show-filters` | Feed | `true` (default) or `false`, the All / Buys / Sells / Theses switch. |
| `data-theme` | Both | `dark` or `light`. |
| `data-font` | Both | `system`, `inter`, `mono` or `serif`. |
| `data-radius` | Both | Corner radius, 0 to 24. |
| `data-bg`, `data-card`, `data-text`, `data-muted`, `data-border`, `data-accent`, `data-accent-text`, `data-bull`, `data-bear` | Both | Colours as hex, for example `#3ddc84`. |
| `data-frameless` | Both | `true`: no frame of its own, for use inside your own card. |
| `data-height` | Both | Starting height in pixels. The widget then grows with its content. |
| `data-max-height` | Feed | Height cap in pixels. Beyond it, the feed scrolls. |

## Sign-in

The widgets share their sign-in with the thesis widget. Who is signed in comes from, in this order:

* **The login button.** With the [login button](https://docs.cabalspy.xyz/cabalspy-id/login-button.md) on the page and the scope requested, for example `data-scope="openid profile trade_feed"`, the widgets are signed in right after the user signs in. The access token must carry the scope `trade_feed`.

* **Your own token.** Server apps, or pages with their own session, pass the user's CabalSpy ID access token (scope `trade_feed`) themselves:

  ```javascript theme={null}
  CSID.tradeFeed.setAccessToken(accessToken);  // after your sign-in, or when you refresh tokens
  CSID.tradeFeed.clear();                       // on sign-out
  ```

* **Your own sign-in flow.** `CSID.tradeFeed.setSignInHandler(fn)` takes over the widgets' sign-in buttons, exactly as [for the thesis widget](https://docs.cabalspy.xyz/cabalspy-id/theses.md#your-own-sign-in): `fn` fetches a token for the user, calls `CSID.tradeFeed.setAccessToken(token)` and resolves `true`, or resolves `false` when nobody is signed in.

* **The popup.** Without any of these, the user signs in with CabalSpy ID in a popup.

`CSID.tradeFeed` and `CSID.thesis` are the same object, so one call signs in both kinds of widgets. A token without the scope `trade_feed` is refused with `scope_missing`.

## Browser API

The widgets run on a small public API on id.cabalspy.xyz. Client-side apps can use it directly to build their own Trade Feed UI, without a backend and without an API key. It works like the thesis [browser API](https://docs.cabalspy.xyz/cabalspy-id/theses-browser-api.md): every call carries your public client\_id as the `X-CSID-Client-Id` header or the `client_id` query parameter, and browser calls are only answered from your instance's sites.

```text theme={null}
https://id.cabalspy.xyz/trade-feed/v1
```

Calls marked Bearer need the user's token as `Authorization: Bearer <token>`: a CabalSpy ID access token of your instance with the scope `trade_feed`, or a widget token from the session exchange.

| Method | Path | Auth | Description |
| - | - | - | - |
| GET | `/traders/{trader}` | Optional | `trader`, `trading_public`, `in_trade_feeds`, and with a token `signed_in`, `is_self` and `in_trade_feed`. |
| POST | `/traders/{trader}` | Bearer | Add the trader to the user's Trade Feed. 201 when added, 200 when already there. Returns `in_trade_feed`, `created`, `trader` and `in_trade_feeds`. |
| DELETE | `/traders/{trader}` | Bearer | Remove the trader. Returns `in_trade_feed: false`, `removed` and `in_trade_feeds`. |
| GET | `/feed?filter=&limit=&cursor=&after=` | Bearer | The user's Trade Feed as in the [Data API](https://docs.cabalspy.xyz/cabalspy-id/trade-feed-api.md#get-the-feed). `next_cursor` is at the top level of the response. `after` (an item's `cursor`) returns only newer items, oldest first, for live updates. |
| GET | `/me` | Bearer | `user` (csid\_id, username, name, image\_url), `traders` (Trade Feed size), `max_traders` and `manage_url`. |
| POST | `/session/exchange` | Bearer | Swap an access token for a widget token valid for 2 hours: `token` and `expires_in`. |

`{trader}` is a handle or csid\_id. Responses are `{"success": true, "data": ...}` or `{"success": false, "error": {"code", "message"}}`.

```javascript theme={null}
const H = { "X-CSID-Client-Id": "csid_...", Authorization: "Bearer " + accessToken };
const base = "https://id.cabalspy.xyz/trade-feed/v1";

await fetch(`${base}/traders/MazeCCC`, { method: "POST", headers: H });   // + Trade Feed
const feed = await (await fetch(`${base}/feed?limit=20&filter=buys`, { headers: H })).json();
feed.data.forEach(it => console.log(it.trader.username, it.trade.symbol, it.trade.label));
```

| Code | Status | Meaning |
| - | - | - |
| [client\_id\_required](https://docs.cabalspy.xyz/cabalspy-id/errors.md#client_id_required) | 401 | No client\_id was sent. |
| [invalid\_client](https://docs.cabalspy.xyz/cabalspy-id/errors.md#invalid_client) | 401 | Unknown, suspended or deleted instance. |
| [origin\_not\_allowed](https://docs.cabalspy.xyz/cabalspy-id/errors.md#origin_not_allowed) | 403 | The page is not one of your instance's sites. |
| [sign\_in\_required](https://docs.cabalspy.xyz/cabalspy-id/errors.md#sign_in_required) | 401 | No token was sent. |
| [invalid\_token](https://docs.cabalspy.xyz/cabalspy-id/errors.md#invalid_token) | 401 | Token invalid or expired, access revoked, or the account is not active. |
| [scope\_missing](https://docs.cabalspy.xyz/cabalspy-id/errors.md#scope_missing) | 403 | The access token lacks the scope `trade_feed`. |
| [plan\_user\_limit](https://docs.cabalspy.xyz/cabalspy-id/errors.md#plan_user_limit) | 403 | The user signed in beyond your plan's user limit. |
| [sandbox\_user](https://docs.cabalspy.xyz/cabalspy-id/errors.md#sandbox_user) | 403 | Sandbox test users have no Trade Feed. |
| [trader\_not\_found](https://docs.cabalspy.xyz/cabalspy-id/errors.md#trader_not_found), [trading\_private](https://docs.cabalspy.xyz/cabalspy-id/errors.md#trading_private), [cannot\_add\_self](https://docs.cabalspy.xyz/cabalspy-id/errors.md#cannot_add_self), [trade\_feed\_full](https://docs.cabalspy.xyz/cabalspy-id/errors.md#trade_feed_full) | 404, 403, 400, 409 | As in the [Data API](https://docs.cabalspy.xyz/cabalspy-id/trade-feed-api.md#add-a-trader). |
| [rate\_limited](https://docs.cabalspy.xyz/cabalspy-id/errors.md#rate_limited) | 429 | Too many Trade Feed changes for this user, or too many session requests from one IP address. |

To manage Trade Feeds from your server with your API key, use the [Trade Feed API](https://docs.cabalspy.xyz/cabalspy-id/trade-feed-api.md) instead.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.