# Documentation (/)
buzzabout exposes two programmatic surfaces: a public **REST API** and
an **MCP server**. Both are backed by the same primitives that power
the web app — datasets, dataset runs, mentions, audience datasets,
audience profiles, tracking agents, pattern detections, custom
parameters, and an AI assistant.
## Where to start [#where-to-start]
Five minutes from API key to your first dataset and mentions list.
Dataset, run, mention, audience dataset, profile, pattern — the
words that come up everywhere.
Wire buzzabout into Claude, Cursor, ChatGPT, or your own agent.
REST endpoints, response envelope, errors, and pagination.
Three chargeable categories — all per-result, all reservation-based.
## What's here [#whats-here]
* **Getting started** — quickstart, concepts, authentication, pricing.
* **Tutorials** — task-shaped walkthroughs combining multiple endpoints
(one today: an end-to-end dataset + audience + assistant flow).
* **MCP** — wire buzzabout into your assistant (Claude, Cursor, ChatGPT)
in a few clicks.
* **API reference** — every endpoint with an integrated playground.
If you're new, start with the [quickstart](/getting-started/quickstart).
If you're integrating buzzabout into an LLM workflow, jump straight to
[MCP overview](/mcp/overview).
## Next steps [#next-steps]
* [Quickstart](/getting-started/quickstart) — five minutes from a fresh
key to your first dataset and mentions list.
* [Concepts](/getting-started/concepts) — the handful of terms that
show up everywhere.
* [Pricing](/getting-started/pricing) — what each call costs.
# Run your first analysis (/api/first-analysis)
This is the API / SDK walkthrough. Prefer the no-code path? [Run your
first research](/tutorials/run-your-first-research) covers the same
flow inside the app.
This tutorial assumes you've finished the
[quickstart](/getting-started/quickstart) and have an API key. We'll
chain five steps into a single workflow, all in Python:
1. Create a dataset and trigger a Reddit run.
2. Wait for it to complete.
3. Create an audience dataset, kick off a profile-collection run from
the source dataset, and wait for it.
4. Read the audience profiles.
5. (Optional) Hand the dataset to the AI assistant.
The whole flow takes 5–15 minutes depending on platform speed.
## Setup [#setup]
```bash
export BUZZABOUT_KEY="bz_live_abcdef1234567890abcdef1234567890"
pip install httpx
```
```python title="first_analysis.py"
import os
import time
import httpx
BUZZABOUT_KEY = os.environ["BUZZABOUT_KEY"]
client = httpx.Client(
base_url="https://api.buzzabout.ai",
headers={"x-api-key": BUZZABOUT_KEY},
timeout=30.0,
)
def wait_for_run(url: str, interval: float = 10.0) -> dict:
"""Poll a run resource until it transitions out of pending/working."""
while True:
body = client.get(url).raise_for_status().json()["data"]
status_type = body["status"]["type"]
print(f" {url} status: {status_type}")
if status_type in ("completed", "failed"):
return body
time.sleep(interval)
```
## Walkthrough [#walkthrough]
### Create the source dataset [#create-the-source-dataset]
```python
dataset = client.post(
"/v1/datasets",
json={"name": "cold brew"},
).raise_for_status().json()["data"]
dataset_id = dataset["id"]
```
### Trigger a run [#trigger-a-run]
```python
run = client.post(
f"/v1/datasets/{dataset_id}/runs",
json={
"search_query": {
"type": "prompt",
"sources": ["reddit"],
"search_query": "cold brew",
},
"count": 200,
"num_comments_per_post": 5,
"content_analysis_actions": ["sentiment", "hook", "cta"],
},
).raise_for_status().json()["data"]
run_id = run["id"]
```
### Wait for the dataset run to complete [#wait-for-the-dataset-run-to-complete]
```python
wait_for_run(f"/v1/datasets/{dataset_id}/runs/{run_id}")
```
A 200-post Reddit run with sentiment + hook + CTA analysis typically
finishes in 1–3 minutes.
### List the top mentions [#list-the-top-mentions]
```python
top = client.post(
"/v1/mentions",
json={
"dataset_ids": [dataset_id],
"limit": 5,
"sort": "engagement_rate",
"order": "desc",
"filters": [[{"type": "sentiment", "values": ["positive"]}]],
},
).raise_for_status().json()["data"]
for m in top:
print(f"{m['num_likes']:6,} likes {m['url']}\n {m['text'][:100]}")
```
Each row has `text`, `url`, the `author` block, engagement counts, and
the analysis fields you opted in to.
### Create an audience dataset [#create-an-audience-dataset]
```python
audience = client.post(
"/v1/audience_datasets",
json={"name": "cold brew creators"},
).raise_for_status().json()["data"]
audience_dataset_id = audience["id"]
```
### Kick off the audience run [#kick-off-the-audience-run]
```python
audience_run = client.post(
f"/v1/audience_datasets/{audience_dataset_id}/runs",
json={
"source_dataset_id": dataset_id,
"total_profile_count": 200,
},
).raise_for_status().json()["data"]
audience_run_id = audience_run["id"]
```
The audience pipeline reads the source dataset's posts (across every
completed run, deduped, top by `created_at DESC`), walks authors plus
commenters, and stops when 200 profiles are collected.
### Wait for the audience run [#wait-for-the-audience-run]
```python
wait_for_run(
f"/v1/audience_datasets/{audience_dataset_id}/runs/{audience_run_id}",
interval=15.0,
)
```
Audience runs are slower than dataset runs because each profile is
scraped + LLM-enriched. A 200-profile run typically takes 5–10
minutes.
### Read the audience profiles [#read-the-audience-profiles]
```python
profiles = client.post(
"/v1/audience_profiles",
json={
"audience_dataset_ids": [audience_dataset_id],
"sort": "follower_count",
"order": "desc",
"limit": 10,
},
).raise_for_status().json()["data"]
for p in profiles:
print(
f"{p['follower_count']:8,} @{p['handle']:24} {p['creator_tier']}"
)
```
Each row is a creator/commenter profile with platform metadata,
audience metrics, and an LLM-derived layer (`creator_tier`,
`content_niche`, `interest_clusters`, `summary`, etc.).
### Hand it to the AI assistant [#hand-it-to-the-ai-assistant]
The assistant returns markdown plus a typed `references[]` list. The
turn is asynchronous: the POST returns 202, then you poll until
`status == "completed"`.
```python
ask = client.post(
"/v1/ask",
json={
"message": (
"In this dataset, what are the top three hooks pulling "
"on Reddit? Cite specific posts."
),
"context": {"dataset_ids": [dataset_id]},
},
).raise_for_status().json()["data"]
chat_id = ask["chat_id"]
message_id = ask["message_id"]
while True:
msg = client.get(
f"/v1/chats/{chat_id}/messages/{message_id}",
).raise_for_status().json()["data"]
if msg["status"] in ("completed", "failed"):
break
time.sleep(2)
print(msg["text"])
for ref in msg["references"]:
print(f" -> {ref['type']} {ref['id']}")
```
Citations appear inline in `text` as `[label](post:reddit:t3_...)`
markdown links. See [Reference types](/api/reference-types) for the
resolution scheme.
Already wired buzzabout into Claude / Cursor / ChatGPT?
[Use the MCP path instead](/mcp/use-in-your-agent) — your assistant
calls `buzzabout__ask` directly and you skip the polling boilerplate.
Audience datasets persist independently of the source dataset. Once
the audience run completes, the profiles stay accessible even if you
later soft-delete the source dataset (though new audience runs
can no longer target it).
## Next steps [#next-steps]
* [API / Datasets](/api/endpoints/datasets) — the full parameter
reference for the dataset run.
* [API / Mentions](/api/endpoints/mentions) — every filter and sort
option for the mentions read.
* [MCP / Tools reference](/mcp/tools/reference) — every tool the host
LLM can call, including `buzzabout__ask`.
# API overview (/api/overview)
The buzzabout REST API is a thin layer over the same primitives the
web app uses. Everything you can do in the product, you can do
through this API.
The API is stable for `datasets`, `mentions`, `audience_datasets`,
and `audience_profiles`. Newer endpoints (tracking agents, pattern
detections, custom parameters, ask, chats, me) may change. We'll
bump the URL prefix from `/v1` to `/v2` before any breaking change.
## Base URL [#base-url]
```text
https://api.buzzabout.ai
```
All endpoints live under `/v1`. Examples in these docs use absolute
URLs so they're easy to copy.
## OpenAPI spec [#openapi-spec]
The full machine-readable spec is published at
[`https://api.buzzabout.ai/openapi.json`](https://api.buzzabout.ai/openapi.json) —
this is the same document that powers the playground on every endpoint
page in these docs. Codegen-friendly; rebuilt on each release.
A hosted Swagger UI lives at
[`https://api.buzzabout.ai/docs`](https://api.buzzabout.ai/docs) for
quick exploration outside the docs site.
## Authentication [#authentication]
Every request needs an `x-api-key` header:
```http
x-api-key: bz_live_abcdef1234567890abcdef1234567890
```
See [authentication](/getting-started/auth) for key lifecycle and team
semantics.
## Content type [#content-type]
JSON in, JSON out. Send `Content-Type: application/json` on any
request that has a body.
## Response envelope [#response-envelope]
Every response is wrapped in a discriminated envelope. The top-level
`status` field tells you which shape you got:
```json title="success — single resource"
{
"status": "success",
"data": { "...": "..." }
}
```
```json title="success — paginated list"
{
"status": "success",
"data": [ { "...": "..." }, { "...": "..." } ],
"has_next": true,
"cursor": "eyJjcmVhdGVkX2F0IjogMTcxNDU2NDg5MCwgImlkIjogImRzXzAxSCJ9"
}
```
```json title="error"
{
"status": "client_error",
"error_code": "dataset_not_found",
"detail": "Dataset not found",
"transient": false
}
```
`status` collapses the HTTP status class:
| HTTP class | `status` |
| ---------- | -------------- |
| 1xx | `info` |
| 2xx | `success` |
| 3xx | `redirect` |
| 4xx | `client_error` |
| 5xx | `server_error` |
Successful 2xx responses always carry a `data` field. Error responses
carry `error_code`, `detail`, and `transient` (when `true`, retrying
the same request later may succeed).
A `204 No Content` returns an empty body — used for soft-deletes,
pause/resume, and other no-content writes.
## Pagination [#pagination]
List endpoints use cursor-based pagination. Pass `limit` and `cursor`:
| Parameter | Type | Default | Notes |
| --------- | ------- | ------------------------------------------------------------------------ | ------------------------------------------------------- |
| `limit` | integer | `10` for resources, `20` for mentions / profiles, `25` for chat messages | 1–100. |
| `cursor` | string | `null` | Opaque base64url. From `cursor` in a previous response. |
| `order` | enum | `desc` | `asc` or `desc` (where supported). |
The response includes `has_next: bool` and `cursor: string \| null`.
When `has_next` is `false`, the cursor is `null` and the page is the
last one.
Cursors are sort-aware on `mentions` / `audience_profiles`. If you
change the `sort` field between calls, request a fresh page (don't pass
the old cursor — it'll fail validation).
## Errors [#errors]
| HTTP | `error_code` examples | What it means |
| ---- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| 400 | `bad_request`, `source_dataset_has_no_completed_run` | Bad request semantics or insufficient state. |
| 401 | `unauthorized` | Missing or invalid `x-api-key`. |
| 402 | `insufficient_credits` | Account has no credits left for this operation. See [Pricing](/getting-started/pricing). |
| 404 | `dataset_not_found`, `pattern_not_found`, `chat_not_found` | Resource doesn't exist or isn't owned by the key. |
| 409 | `audience_dataset_run_already_in_flight` | A pending / working run blocks a new one. |
| 422 | `unprocessable_entity` | Body or query parameters are malformed. |
| 429 | `too_many_requests` | See [rate limits](/api/rate-limits). |
| 5xx | `internal_server_error` | Something on our end. Often paired with `transient: true`. |
The `error_code` is stable — match on it, not on the human-readable
`detail`.
## Account scoping [#account-scoping]
Every API key carries an `account_id` (shared with the rest of the
team) plus a `user_id` (the acting seat):
* Account-shared resources — datasets, mentions, audience datasets,
audience profiles, tracking agents, pattern detections, custom
parameters — are visible to every key on the account.
* **Chats are user-owned**: only the seat that created a chat can
read it. Cross-seat lookups return `404`. See
[Chats](/api/endpoints/chats).
* Resource ids on inputs must reference resources owned by the calling
account — otherwise the endpoint returns `404` instead of `403`
(existence is hidden).
* Global mentions and audience-profiles endpoints implicitly scope to
your account; passing `dataset_ids` / `audience_dataset_ids` only
narrows further.
## Endpoint groups [#endpoint-groups]
Container CRUD plus async scraping runs.
Scheduled re-scraping with drift alerts.
Profile collection from a source dataset.
Global filterable mention search.
Global filterable profile search.
Cross-mention narrative clustering.
Bespoke LLM-extracted per-mention fields.
Assistant turns plus chat history reads.
`me`, usage history, current credit prices.
## Next steps [#next-steps]
* [Reference types](/api/reference-types) — how assistant `references[]`
and inline post links resolve.
* [Rate limits](/api/rate-limits) — the per-route quotas.
* [Pricing](/getting-started/pricing) — per-result credit costs.
# Rate limits and quotas (/api/rate-limits)
buzzabout regulates traffic through three mechanisms: a per-API-key
request-rate limit, credit-based pre-checks on chargeable operations,
and a per-audience-dataset concurrency cap. Build for all three in
your client.
## Per-API-key request limit [#per-api-key-request-limit]
Every authenticated public endpoint — REST (`/v1/...`) **and** MCP
(`/mcp/...`) — is limited to **5 requests per second per API key**,
shared across both surfaces. Identity is keyed on the SHA-256 digest
of your API key, so a single key has one rate budget regardless of
how you call the platform.
Exceeding the cap returns `429`:
```json title="429 body"
{
"status": "client_error",
"error_code": "too_many_requests",
"detail": "Too many requests. Please slow down.",
"transient": true,
"retry_after_seconds": 0.832
}
```
The `transient: true` flag is the signal that retrying after a delay
should succeed. `retry_after_seconds` is the precise wait time the
limiter measured; the standard `Retry-After` HTTP header carries the
same value rounded up to whole seconds.
Three informational response headers are emitted on **every**
authenticated request — not just `429`s — so a well-behaved client can
adapt its send-rate before being throttled:
| Header | Meaning |
| --------------------- | ---------------------------------------- |
| `RateLimit-Limit` | The cap (5 today). |
| `RateLimit-Remaining` | Calls left in the current second-window. |
| `RateLimit-Reset` | Seconds until the bucket fully resets. |
The recommended client behaviour is exponential backoff with jitter,
preferring the server's `Retry-After` hint when present:
```python title="retry.py"
import random
import time
import httpx
def call_with_backoff(
client: httpx.Client,
method: str,
url: str,
*,
max_attempts: int = 5,
**kwargs,
) -> httpx.Response:
for attempt in range(max_attempts):
resp = client.request(method, url, **kwargs)
if resp.status_code != 429 or attempt == max_attempts - 1:
return resp
delay = float(resp.headers.get("Retry-After", "1"))
delay = min(60.0, delay + random.random() * 0.25)
time.sleep(delay)
return resp
```
If your integration legitimately needs more than 5 req/s sustained,
mail [support@buzzabout.ai](mailto:support@buzzabout.ai). Enterprise
plans are eligible for a higher per-key rate without a code change
on your side.
## Credit-based pre-checks (402) [#credit-based-pre-checks-402]
Runs (`POST /v1/datasets/{id}/runs`, `POST /v1/audience_datasets/{id}/runs`,
`POST /v1/pattern_detections`, `POST /v1/custom_parameters/{id}/runs`)
all pre-check the account's credit balance. When it would be exceeded
the response is `402` with a structured `detail` block telling you
exactly how many credits the call needs and how many you have:
```json title="402 body"
{
"status": "client_error",
"error_code": "insufficient_credits",
"detail": {
"message": "Insufficient credits to start this run.",
"required": "20",
"available": "0",
"top_up_url": "https://app.buzzabout.ai/settings/billing"
},
"transient": false
}
```
Surface `required - available` in your UI so the user knows exactly
how many credits to top up. Top up via the web app or upgrade your
plan; in-flight requests are never partially charged. See
[Pricing](/getting-started/pricing#reservation-based-charging) for
how the up-front reservation works.
## Per-audience-dataset concurrency (409) [#per-audience-dataset-concurrency-409]
A single audience dataset only allows one in-flight run. A second
`POST /v1/audience_datasets/{id}/runs` while another is pending or
working returns `409`:
```json
{
"status": "client_error",
"error_code": "audience_dataset_run_already_in_flight",
"detail": "Another run for this audience dataset is already pending or working. Wait for it to finish before starting a new one.",
"transient": false
}
```
Poll `GET /v1/audience_datasets/{id}/runs/{run_id}` until the existing
run terminates, then retry. Regular datasets do not have this
restriction — multiple runs can be in flight concurrently against the
same dataset.
## Next steps [#next-steps]
* [Pricing](/getting-started/pricing) — per-result credit costs and
reservation-based charging.
* [API overview](/api/overview) — response envelope, errors, and
pagination model.
# Reference types (/api/reference-types)
Assistant messages and tracking-agent alerts return text alongside a
**`references[]`** array — a flat list of typed pointers into buzzabout
resources. Six entries point to entities the assistant produced or
referenced (datasets, patterns, …); a seventh, **`post`**, captures
every inline post citation in the assistant's prose.
This page enumerates both shapes and the endpoint you call to resolve
each one.
## Entity references [#entity-references]
Each entity entry in `references[]` is:
```json
{
"type": "",
"id": ""
}
```
No inline payload — clients fetch the underlying resource on demand. In
practice an assistant turn returns ≤3 entity references; the round-trip
cost is negligible and the contract stays stable as the underlying
resources grow.
| `type` | Resolution endpoint |
| ----------------------- | -------------------------------------------------------------------------------------------- |
| `pattern` | [`GET /v1/patterns/{pattern_id}`](/api/endpoints/patterns) |
| `research_preview` | `GET /v1/research_previews/{preview_id}` (hidden; resolved via the assistant directly) |
| `dataset` | [`GET /v1/datasets/{dataset_id}`](/api/endpoints/datasets) |
| `audience_dataset` | [`GET /v1/audience_datasets/{audience_dataset_id}`](/api/endpoints/audience-datasets) |
| `custom_parameter_run` | [`GET /v1/custom_parameters/{parameter_id}/runs/{run_id}`](/api/endpoints/custom-parameters) |
| `pattern_detection_run` | [`GET /v1/pattern_detections/{run_id}`](/api/endpoints/pattern-detections) |
`research_preview` is the working pointer to an in-progress assistant
investigation — the assistant resolves it for you in subsequent turns,
so most clients never need to expand it directly.
## Post references [#post-references]
Every **unique** post the assistant cites surfaces as a structured
`post` entry in `references[]` — **not** as inline markdown:
```json
{
"type": "post",
"source": "tiktok",
"id": "7392184932",
"citation": 1,
"start_index": 4,
"end_index": 7
}
```
In the returned `text`, each `[label](post:source:id)` markdown link
is rewritten to a bracketed numeric marker — `[1]`, `[2]`, … —
academic-citation style. Numbering is **per-message** and assigned
in first-appearance order over unique `(source, id)` tuples: the
first unique post cited gets `1`, the second unique post gets `2`,
and so on. **Re-citing the same post in the same message re-uses its
number** — every occurrence of that post in the prose shows the same
`[N]` marker, and the post appears once in `references[]`.
The half-open `start_index` / `end_index` pair points at the **first**
`[N]` occurrence in the rewritten `text`: slicing
`text[start_index:end_index]` returns exactly `f"[{citation}]"`
(e.g. `"[1]"`). To locate every occurrence of a citation, string-search
the text for the literal bracketed marker.
Example: an assistant turn that cites a TikTok post twice and a
Reddit post once produces this shape:
```text
text: "See [1] and [2]. As [1] also notes…"
references: [
{ "type": "post", "source": "tiktok", "id": "7392184932", "citation": 1, "start_index": 4, "end_index": 7 },
{ "type": "post", "source": "reddit", "id": "t3_1oqliu8", "citation": 2, "start_index": 12, "end_index": 15 }
]
```
To resolve `(source, id)` back to a full mention payload, call
[`POST /v1/mentions`](/api/endpoints/mentions) with `post_refs`:
```json
{
"post_refs": [
{ "source": "tiktok", "id": "7392184932" },
{ "source": "reddit", "id": "t3_1oqliu8" }
]
}
```
The response carries the same `Mention` shape as a standard list query.
The same `(source, id)` cited twice in a message produces **one**
`post` reference with **one** `citation` number; both occurrences
in the rewritten text use the same `[N]` marker. Offsets on the ref
point at the first occurrence — search the text for `[N]` to find
every reference site.
Posts can appear dozens of times in a single answer; rendering them
as full entity records would balloon the response. Surfacing each
unique post as a slim `{source, id, citation, start_index, end_index}`
ref keeps the payload small while letting clients render every
citation as a precise link without parsing markdown themselves.
## Where this surface appears [#where-this-surface-appears]
* **`POST /v1/ask`** (and the same surface via MCP) — assistant turns.
The reply text and `references[]` come back via
[`GET /v1/chats/{chat_id}/messages/{message_id}`](/api/endpoints/chats)
once the turn settles.
* **`GET /v1/chats/{id}/messages`** — historical assistant messages
carry the same shape per row.
* **`GET /v1/tracking_agents/{id}/messages`** — alerts produced by a
running tracking agent. Each alert's `text` carries inline post
citations as `post` references and, for cross-dataset patterns, a
`pattern` entity reference.
`tracking_agent` is **not** a reference type — agents are entities you
manage, not citations the assistant produces.
## Next steps [#next-steps]
* [Mentions](/api/endpoints/mentions) — `post_refs` lookup path for
resolving cited posts back to the full mention shape.
* [Patterns](/api/endpoints/patterns) — what's behind a `pattern`
reference once you expand it.
* [POST /v1/ask](/api/endpoints/ask) — where references first appear
in a typical agent loop.
# Authentication (/getting-started/auth)
buzzabout authenticates REST and MCP requests with the same primitive:
a long-lived **API key** sent in the `x-api-key` header. Interactive
assistants (Claude) can additionally exchange an OAuth flow for a JWT
on the MCP surface — see [MCP / Authentication](/mcp/auth) for that
path. The REST API is api-key only.
## API keys [#api-keys]
API keys live under **Settings → API keys** in the web app. Click
*New key*, name it, copy the value — it's shown once.
Keys look like `bz_live_<32 hex>` (for example,
`bz_live_abcdef1234567890abcdef1234567890`). They're tied to one
buzzabout account; every request the key makes is scoped to that
account's resources.
buzzabout stores only the **SHA-256 digest** of your key, not the
key itself. Once you close the *New key* dialog the raw value
cannot be retrieved — not by you, not by buzzabout support, not
even with database access. If you lose it, revoke the lost key and
mint a new one. Treat the dialog as a one-shot prompt: copy the
value into your secret manager before dismissing it.
### Sending the key [#sending-the-key]
```http
GET /v1/datasets HTTP/1.1
Host: api.buzzabout.ai
x-api-key: bz_live_abcdef1234567890abcdef1234567890
```
```bash title="cURL"
curl "https://api.buzzabout.ai/v1/datasets" \
-H "x-api-key: $BUZZABOUT_KEY"
```
### Verifying a key [#verifying-a-key]
Hit `GET /v1/datasets` with `limit=1`. A 200 means the key is valid.
A 401 means it's missing or revoked.
```bash
curl -s -o /dev/null -w "%{http_code}\n" \
"https://api.buzzabout.ai/v1/datasets?limit=1" \
-H "x-api-key: $BUZZABOUT_KEY"
```
### Rotation [#rotation]
There's no built-in expiration. Rotate by:
1. Creating a new key under **Settings → API keys**.
2. Updating your environment / secret store.
3. Revoking the old key.
Revoked keys return `401` immediately on the next call — there's no
grace period.
## Team-member semantics [#team-member-semantics]
Most resources (datasets, mentions, audience datasets, audience
profiles, tracking agents, pattern detections, custom parameters) are
**account-shared** — visible to every key on the same account
regardless of which seat minted them.
The one exception: **chats are per-seat**. A chat is only readable by
the seat that created it; other team members get a `404` from
[`GET /v1/chats/{id}`](/api/endpoints/chats). If you revoke a seat,
their keys are deleted with them — plan to rotate any
service-account-style integrations through a seat you keep.
## Using API keys with MCP [#using-api-keys-with-mcp]
The MCP server accepts the same `x-api-key` header as the REST API.
Headless agents — your own SDK-built integration, a server-side LLM
pipeline — authenticate this way without going through OAuth.
See [MCP / Authentication](/mcp/auth) for the headless wiring and the
OAuth-for-interactive-hosts path.
## Next steps [#next-steps]
* [Quickstart](/getting-started/quickstart) — first dataset, first
mentions.
* [MCP authentication](/mcp/auth) — `x-api-key` and OAuth/JWT paths
for the MCP server.
* [Pricing](/getting-started/pricing) — what each authenticated call
costs.
# Concepts (/getting-started/concepts)
A handful of terms come up everywhere in the product, the API, and the
MCP server. Knowing them makes the rest of the docs much shorter to
read.
## Dataset [#dataset]
A **dataset** is a named container of mentions. You create one, kick
off one or more runs against it, and the runs populate it with posts.
The same dataset can hold posts from many runs over time.
```json
{
"id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1",
"name": "cold brew",
"mentions_count": 1247,
"created_at": "2026-05-01T12:00:00Z",
"url": "https://app.buzzabout.ai/datasets/ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1"
}
```
## Dataset run [#dataset-run]
A **dataset run** is one snapshot of post collection: a search query
(or list of URLs), a target post count, optional date range, and the
analysis steps to apply. Runs are asynchronous — they return `pending`
and transition through `working` to `completed` (or `failed`).
```json
{
"id": "dr_2NK4ZG2BqkAxK1nT0RZyZbBmZHN",
"dataset_id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1",
"status": {
"type": "completed",
"steps": [
{ "name": "scraping", "completed_at": 1714564890 },
{ "name": "analysis", "completed_at": 1714565010 }
]
},
"params": {
"search_query": {
"type": "prompt",
"sources": ["reddit"],
"search_query": "cold brew"
},
"count": 200
},
"mentions_count": 200
}
```
## Mention [#mention]
A **mention** is a single post in a dataset — a Reddit thread, a TikTok
video, a YouTube video, an Instagram reel, a LinkedIn post. The same
post can appear in multiple datasets (the `datasets` field on each
mention enumerates them).
Each mention carries author metadata, engagement counts (views, likes,
comments, shares), the original URL, attached media, and a structured
content-analysis layer (sentiment, emotions, hook, CTA, tone of voice,
content topics, mentioned brands, entities, and more) when those
analyses ran on the parent run.
## Audience dataset [#audience-dataset]
An **audience dataset** is a name-only container for audience runs —
runs that collect creator and commenter profiles from the posts in a
source dataset. Different audience runs in the same container can
target different source datasets over time.
```json
{
"id": "ad_2NK4ahFr1tJgX9Lp2dQ5mWvNcR8",
"name": "cold brew creators",
"profile_count": 300
}
```
## Audience profile [#audience-profile]
A **profile** is one creator or commenter from one audience run. It
captures the platform-specific account metadata (username, display
name, avatar, verification, follower / following / content counts, bio,
external link), an LLM-derived audience layer (creator tier, niche,
interest clusters, brand affinities, communication tone, OCEAN
personality scores, summary), and a normalised authenticity / engagement
profile.
## Pattern [#pattern]
A **pattern** is a recurring shape across mentions — a hook framing, a
narrative arc, a visual motif. Patterns are produced by
[pattern-detection runs](/api/endpoints/pattern-detections) and by
[tracking agents](/api/endpoints/tracking-agents); the resulting
`pattern_id` is retrievable via
[`GET /v1/patterns/{id}`](/api/endpoints/patterns).
## Next steps [#next-steps]
* [API / Datasets](/api/endpoints/datasets) — the API equivalents of
every concept on this page.
* [Quickstart](/getting-started/quickstart) — five minutes from zero
to a finished dataset.
# Pricing (/getting-started/pricing)
buzzabout charges credits per result, not per request. The four public
categories below cover every chargeable endpoint and MCP tool. Asking the
assistant (`POST /v1/ask` and the `buzzabout__ask` MCP tool) is free. A
**credit** is the smallest billable unit; one US dollar buys 1,000 of
them on the standard plan (your exact rate is on
[buzzabout.ai/pricing](https://buzzabout.ai/pricing)).
## Categories [#categories]
| Category | Credits | When | Reservation-based? |
| -------------------- | ------- | --------------------------------------------------------------------------------------- | ------------------ |
| `mention` | 1 | per mention collected (dataset run or tracking-agent re-scrape — unified for clients) | yes |
| `audience_profile` | 3 | per profile collected by an audience-dataset run | yes |
| `post_processing` | 0.5 | per post processed by a custom-parameter run or pattern-detection run | yes |
| `preview_generation` | 1 | per source in a research preview (`url` previews refund profiles that returned no data) | yes |
Custom-parameter `preview` is free, and so is asking the assistant
(`POST /v1/ask` / `buzzabout__ask`).
## Reservation-based charging [#reservation-based-charging]
Every chargeable category on the public surface is **reservation-based**.
The endpoint reserves credits up-front based on the upper-bound result
count (e.g. the requested `count` on a dataset run, the source dataset's
mention count for a custom-parameter or pattern-detection run), then
refunds any unused credits when the run completes. A run that asked for
500 mentions and returned 412 leaves you charged for 412 — the remaining
88 credits go back to your balance.
A [research preview](/api/endpoints/research-previews) reserves 1 credit
per source; `url` previews refund any source that returned no data
(private, non-existing, or failed to retrieve).
If a run **fails** before it can produce results, the full reservation
is refunded.
Endpoints that would exceed your balance return `402 insufficient_credits`
before any work starts. Top up via the web app or upgrade your plan;
in-flight requests are never partially charged.
## Programmatic access [#programmatic-access]
The current price table is available without authentication at
[`GET /v1/credit_prices`](/api/endpoints/credit-prices):
```bash
curl https://api.buzzabout.ai/v1/credit_prices
```
```json
{
"status": "success",
"data": {
"mention": 1,
"audience_profile": 3,
"post_processing": 0.5,
"preview_generation": 1
}
}
```
Use this to build cost dashboards, pre-flight budget checks, or to
ground a cost-conscious agent's reasoning. The shape is flat and the
keys are stable — new categories ship as additive fields.
## Usage history [#usage-history]
`GET /v1/me/usage_history` returns a paginated feed of charges and
refunds against your account. Each item carries the category, the
endpoint that produced it, and the delta in credits. See
[`/v1/me`](/api/endpoints/me).
The feed may include legacy category strings (`ai_assistant`, `REPORT`,
`AUDIENCE_RESEARCH`, `TRACKING`) for charges that pre-date this surface —
those endpoints aren't part of the public API but their history shows
up on the same feed. In particular, `ai_assistant` belongs to the
assistant in the previous version of the app; asking the assistant
today (`POST /v1/ask` / `buzzabout__ask`) is free, so the category
appears only on old rows.
## Next steps [#next-steps]
* [`GET /v1/credit_prices`](/api/endpoints/credit-prices) — programmatic
price lookup.
* [`GET /v1/me`](/api/endpoints/me) — current balance + usage history.
* [API overview](/api/overview) — once you know what each call costs.
# Quickstart (/getting-started/quickstart)
Spin up your first dataset in five minutes. By the end you'll have an
API key, a dataset populated with real social-media posts, and a list
of mentions you can work with.
This guide uses **Python with `httpx`**. The same calls work from any
language — pick the request library you prefer. Every example URL,
header, and body shape is identical.
## Prerequisites [#prerequisites]
* A buzzabout account ([sign up](https://buzzabout.ai/?signup) — the
free tier is enough for this walkthrough).
* Python 3.10+ and `httpx` (`pip install httpx`).
Paste this whole page (or [`https://docs.buzzabout.ai/llms-full.txt`](https://docs.buzzabout.ai/llms-full.txt))
into Claude Code, Cursor, or any coding assistant and ask it to wire
buzzabout into your project. The docs are written to be agent-readable.
## Walkthrough [#walkthrough]
### Get an API key [#get-an-api-key]
Open **Settings → API keys** in the web app and click *New key*. Copy
the value (it starts with `bz_live_`) somewhere safe — you'll see it
once.
```bash
export BUZZABOUT_KEY="bz_live_abcdef1234567890abcdef1234567890"
```
buzzabout only stores the SHA-256 digest of your key, not the key
itself. Once you close the "New key" dialog the raw value is gone —
if you lose it, mint a new one. See
[authentication](/getting-started/auth) for the full lifecycle.
If you're integrating buzzabout with Claude, Cursor, ChatGPT, or
another assistant instead of calling the API yourself, skip ahead to
[Use in your agent](/mcp/use-in-your-agent). You'll wire the buzzabout
MCP server into your assistant and let it drive the same workflow.
### Set up the client [#set-up-the-client]
A tiny helper to keep the rest of the code clean:
```python title="quickstart.py"
import os
import time
import httpx
BUZZABOUT_KEY = os.environ["BUZZABOUT_KEY"]
BASE_URL = "https://api.buzzabout.ai"
client = httpx.Client(
base_url=BASE_URL,
headers={"x-api-key": BUZZABOUT_KEY},
timeout=30.0,
)
```
### Create a dataset [#create-a-dataset]
A **dataset** is a named container for the mentions you'll collect.
```python title="quickstart.py (continued)"
response = client.post("/v1/datasets", json={"name": "cold brew"})
response.raise_for_status()
dataset = response.json()["data"]
dataset_id = dataset["id"]
print(f"Created dataset {dataset_id}: {dataset['name']}")
```
```json title="201 Created"
{
"status": "success",
"data": {
"id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1",
"name": "cold brew",
"created_at": "2026-05-01T12:00:00Z"
}
}
```
### Trigger a dataset run [#trigger-a-dataset-run]
A **run** is what actually collects posts from social platforms. The
call is asynchronous — it returns `202 Accepted` immediately with a run
in `pending` state.
```python title="quickstart.py (continued)"
response = client.post(
f"/v1/datasets/{dataset_id}/runs",
json={
"search_query": {
"type": "prompt",
"sources": ["reddit", "tiktok"],
"search_query": "cold brew coffee",
},
"count": 200,
},
)
response.raise_for_status()
run = response.json()["data"]
run_id = run["id"]
print(f"Queued run {run_id} — status: {run['status']['type']}")
```
```json title="202 Accepted"
{
"status": "success",
"data": {
"id": "dr_2NK4ZG2BqkAxK1nT0RZyZbBmZHN",
"dataset_id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1",
"status": { "type": "pending", "steps": [] },
"created_at": "2026-05-01T12:00:30Z"
}
}
```
### Poll until completed [#poll-until-completed]
```python title="quickstart.py (continued)"
while True:
response = client.get(f"/v1/datasets/{dataset_id}/runs/{run_id}")
response.raise_for_status()
status = response.json()["data"]["status"]["type"]
print(f" status: {status}")
if status in ("completed", "failed"):
break
time.sleep(10)
```
A 200-post run typically takes 1–3 minutes.
```json title="200 OK (completed)"
{
"status": "success",
"data": {
"id": "dr_2NK4ZG2BqkAxK1nT0RZyZbBmZHN",
"dataset_id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1",
"status": {
"type": "completed",
"steps": [
{ "name": "scraping", "completed_at": 1714564890 },
{ "name": "analysis", "completed_at": 1714565010 }
]
},
"mentions_count": 200,
"created_at": "2026-05-01T12:00:30Z",
"updated_at": "2026-05-01T12:03:30Z"
}
}
```
### List mentions [#list-mentions]
Mentions are global — `POST /v1/mentions` returns all the mentions
across every dataset you own. Pass `dataset_ids` to scope the search.
```python title="quickstart.py (continued)"
response = client.post(
"/v1/mentions",
json={
"dataset_ids": [dataset_id],
"limit": 5,
"sort": "engagement_rate",
"order": "desc",
},
)
response.raise_for_status()
mentions = response.json()["data"]
for m in mentions:
print(f" {m['source']:9} {m['num_likes']:6,} likes {m['url']}")
```
```json title="200 OK"
{
"status": "success",
"data": [
{
"source": "reddit",
"id": "t3_1oqliu8",
"author": {
"title": "u/sipdaily",
"url": "https://www.reddit.com/user/sipdaily/",
"follower_count": 1240
},
"text": "Nobody tells you that nitro cold brew tastes...",
"url": "https://www.reddit.com/r/coffee/comments/1oqliu8/",
"num_views": 12400,
"num_likes": 248,
"engagement_rate": "0.020",
"datasets": [
{ "id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1", "name": "cold brew" }
]
}
],
"has_next": true,
"cursor": "eyJzb3J0X3ZhbHVlIjogIjAuMDIwIiwgImlkIjogInQzXzFvcWxpdTgifQ=="
}
```
## Next steps [#next-steps]
* [Run your first analysis](/api/first-analysis) — end-to-end
walkthrough including audience scraping and the AI assistant.
* [MCP overview](/mcp/overview) — drive the same workflow from an
MCP-capable assistant (Claude, Cursor, ChatGPT, your own SDK).
* [API / Datasets](/api/endpoints/datasets) — the full reference for
the calls we just made.
# Authentication (/mcp/auth)
The buzzabout MCP server accepts two ways to authenticate on the same
URL. Which one you use depends on your client — both end up as the same
buzzabout account, and every tool (including `ask`) works either way.
| Your client | Use | What you do |
| --------------------------------------------- | --------------- | ------------------------------------------------------ |
| **Claude Desktop, Claude.ai, ChatGPT** | **OAuth** | Click **Connect** / sign in — nothing to copy or store |
| **Claude Code, Codex, Cursor**, custom agents | **`x-api-key`** | Paste a key into the client's MCP config |
Standard interactive assistants ship an OAuth flow, so use that — there's
no reason to manage an API key for them. The CLI / IDE agents (Claude
Code, Codex, Cursor) don't have a built-in OAuth flow for custom MCP
servers, so they use an API key.
Per-client setup snippets are on
[Use in your agent](/mcp/use-in-your-agent); this page is just the auth
choice and how to supply a key.
## Endpoint [#endpoint]
```text
https://mcp.buzzabout.ai/mcp/
```
Streamable HTTP. The trailing slash is required.
## OAuth — standard assistants [#oauth--standard-assistants]
Claude Desktop, Claude.ai, and ChatGPT handle OAuth for you. Add the
server URL in the client's connector settings and **Connect** / sign in
with your buzzabout account; the client stores the token and replays it
on every call. You don't configure anything else, and you don't need an
API key. The per-client steps are on
[Use in your agent](/mcp/use-in-your-agent).
## `x-api-key` — Claude Code, Codex, Cursor, custom [#x-api-key--claude-code-codex-cursor-custom]
Mint a key in the web app under `Settings → API keys → New key`. Copy
the value (`bz_live_...`) once — it's hashed and can't be retrieved
again. (Lifecycle and rotation: [REST authentication](/getting-started/auth).)
Then add it to your client's MCP config as an `x-api-key` header — see
[Use in your agent](/mcp/use-in-your-agent) for the exact config per
client. For a custom agent, send the header on every request:
```http
POST /mcp/ HTTP/1.1
Host: mcp.buzzabout.ai
x-api-key: bz_live_...
Content-Type: application/json
Accept: application/json,text/event-stream
```
```python title="agent.py"
import asyncio
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main() -> None:
headers = {"x-api-key": os.environ["BUZZABOUT_KEY"]}
async with streamablehttp_client(
"https://mcp.buzzabout.ai/mcp/",
headers=headers,
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
for tool in tools.tools:
print(tool.name)
asyncio.run(main())
```
```ts title="agent.ts"
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("https://mcp.buzzabout.ai/mcp/"),
{
requestInit: {
headers: { "x-api-key": process.env.BUZZABOUT_KEY! },
},
},
);
const client = new Client({ name: "my-agent", version: "0.1.0" });
await client.connect(transport);
```
```bash
curl -X POST https://mcp.buzzabout.ai/mcp/ \
-H "x-api-key: $BUZZABOUT_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json,text/event-stream" \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'
```
## Tool errors [#tool-errors]
Tool errors come back inside the result as a structured JSON payload —
the same `error_code` taxonomy as the REST API:
```json
{
"error": {
"code": "dataset_not_found",
"message": "Dataset not found",
"status": 404
}
}
```
Match on `code` (stable); show `message` to humans. `status` mirrors the
HTTP status the equivalent REST call would return.
Transport errors (`401`, `429`) come back as MCP transport errors, not
tool-level errors — handle them at the SDK transport layer.
## Next steps [#next-steps]
* [Use in your agent](/mcp/use-in-your-agent) — per-client setup.
* [Tools reference](/mcp/tools/reference) — every tool, with parameters.
* [REST authentication](/getting-started/auth) — the same `bz_live_...`
key works for `https://api.buzzabout.ai/v1/*`.
# MCP overview (/mcp/overview)
The buzzabout **MCP server** lets any [Model Context Protocol](https://modelcontextprotocol.io/)
client — Claude Desktop, Claude.ai, Claude Code, Codex, Cursor, ChatGPT,
your own SDK agent — drive buzzabout from inside the conversation. You
ask a research question; the assistant collects and analyses the posts
and returns the answer in the chat, often as an interactive widget.
## Transport [#transport]
```text
https://mcp.buzzabout.ai/mcp/
```
Streamable HTTP — one URL handles tool listing, tool calls, and OAuth
discovery (no separate SSE endpoint).
Use `https://mcp.buzzabout.ai/mcp/` (with trailing slash). The
unslashed `/mcp` returns a `307` redirect that strips the request body
in many MCP clients, which surfaces as silent connection failures or
empty tool lists.
See [Use in your agent](/mcp/use-in-your-agent) for per-host wiring.
## Authentication [#authentication]
Two paths on the same URL, chosen by client:
* **OAuth** — standard assistants (Claude Desktop, Claude.ai, ChatGPT)
handle it; just sign in.
* **`x-api-key`** — CLI / IDE agents (Claude Code, Codex, Cursor) and
custom agents paste a key.
Both resolve to the same buzzabout account. Full details on
[Authentication](/mcp/auth).
## What's exposed [#whats-exposed]
**15 tools**, in two kinds:
* **The assistant flow — `ask` → `get_message` → `render`.** `ask` hands
a prompt to the buzzabout assistant, which writes the query, previews
it, collects posts, profiles audiences, detects patterns, and analyses.
It returns immediately; you poll `get_message` for the answer, and
`render` draws any rich block as an interactive widget.
* **Read-only lookups** — list / fetch datasets, runs, mentions,
audience profiles, and tracking agents the account already has.
There are **no create / update / delete tools** — collecting,
profiling, and pattern detection all happen through `ask`. For
programmatic CRUD, use the [REST API](/api/overview).
Every tool — the assistant flow plus the read-only lookups.
Per-host wiring + a first prompt to test the loop.
OAuth for standard assistants, `x-api-key` for Claude Code / Codex / Cursor.
## The async flow [#the-async-flow]
Research can run for minutes — past a host's tool-call timeout — so the
assistant flow is asynchronous:
1. `buzzabout__ask(prompt)` returns immediately with
`{ chat_id, message_id, status: "working" }`.
2. The host polls `buzzabout__get_message(chat_id, message_id)` — which
**long-polls** (one call holds for \~45s, returning the moment the turn
settles) — until `stop_reason` is non-null.
3. The answer comes back as `blocks`: a `render: true` block is shown via
`buzzabout__render` as an interactive MCP App widget; a `render: false`
block carries plain markdown the host relays. Hosts without the MCP
Apps UI extension get markdown throughout.
Credit-exhausted accounts surface a `402` with a structured "need N more
credits" body so the assistant can ask the user to top up before
retrying.
## When to use MCP vs REST [#when-to-use-mcp-vs-rest]
| Use MCP | Use REST |
| ------------------------------------------------ | ------------------------------------------ |
| Interactive — a person talking to an LLM client. | Batch — scheduled job, cron-driven sync. |
| You want the assistant to drive the research. | You're writing the orchestration yourself. |
| Results inline in the conversation. | You need primitive CRUD / precise control. |
Both surfaces are backed by the same primitives, so hybrid setups work
naturally (e.g. run a heavy collection via REST, then ask an MCP-capable
assistant to summarise it).
## See also [#see-also]
* [Agentation](https://agentation.dev/) — third-party MCP devtool that
pairs well with buzzabout for local agent development and inspection.
## Next steps [#next-steps]
* [Tools reference](/mcp/tools/reference) — the 15-tool surface.
* [Use in your agent](/mcp/use-in-your-agent) — per-host wiring +
first prompt.
* [Authentication](/mcp/auth) — pick OAuth or `x-api-key`.
# Use in your agent (/mcp/use-in-your-agent)
The buzzabout MCP server speaks the Model Context Protocol — any
MCP-capable client can connect. This page covers the wiring for the
common hosts plus the SDK pattern for your own agent.
## Endpoint [#endpoint]
```text
https://mcp.buzzabout.ai/mcp/
```
Streamable HTTP. Trailing slash required. Standard assistants (Claude
Desktop/web, ChatGPT) authenticate via **OAuth**; CLI / IDE agents
(Claude Code, Codex, Cursor) and custom agents use an **`x-api-key`**
header — see [Authentication](/mcp/auth).
## Wire it up [#wire-it-up]
`Settings → Connectors → Add custom connector` (the `+`). Fill in:
| Field | Value |
| ----- | ------------------------------- |
| Name | `buzzabout` |
| URL | `https://mcp.buzzabout.ai/mcp/` |
The connector is added under **Not connected**. Click **Connect** to
sign in with your buzzabout account (OAuth) — it stays disconnected and
unusable until you do. Once connected, Claude replays the token on later
calls. Identical on Claude Desktop and Claude.ai (web).
Claude Code uses an API key (no OAuth flow for custom MCP servers). Mint
a key under `Settings → API keys` in the buzzabout web app, then:
```bash
claude mcp add --transport http buzzabout \
https://mcp.buzzabout.ai/mcp/ \
--header "x-api-key: bz_live_..."
```
Check it's connected with `claude mcp list`.
Add an entry to `~/.codex/config.toml`. Codex authenticates a
streamable-HTTP server with static headers — use `x-api-key` (mint a key
under `Settings → API keys` in the buzzabout web app):
```toml title="~/.codex/config.toml"
[mcp_servers.buzzabout]
url = "https://mcp.buzzabout.ai/mcp/"
http_headers = { "x-api-key" = "bz_live_..." }
```
`Settings → Cursor Settings → MCP → Add new MCP server`.
```json title="~/.cursor/mcp.json"
{
"mcpServers": {
"buzzabout": {
"transport": "streamable-http",
"url": "https://mcp.buzzabout.ai/mcp/",
"headers": {
"x-api-key": "bz_live_..."
}
}
}
}
```
Cursor doesn't ship an OAuth flow for custom MCP servers — use the
`x-api-key` path. Mint a key under `Settings → API keys` in the
buzzabout web app.
`Settings → Apps → Create app`, enter the server URL, and select
**OAuth** as the auth mechanism. Requires a paid ChatGPT plan (Plus, Pro,
or Team).
| Field | Value |
| ----- | ------------------------------- |
| URL | `https://mcp.buzzabout.ai/mcp/` |
| Auth | OAuth |
ChatGPT then prompts you to sign in with your buzzabout account.
For your own agent, use one of the official MCP SDKs with an
`x-api-key` header.
```python title="agent.py"
import asyncio
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main() -> None:
headers = {"x-api-key": os.environ["BUZZABOUT_KEY"]}
async with streamablehttp_client(
"https://mcp.buzzabout.ai/mcp/",
headers=headers,
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print(f"loaded {len(tools.tools)} buzzabout tools")
result = await session.call_tool(
"buzzabout__list_datasets",
arguments={"limit": 5},
)
print(result.content)
asyncio.run(main())
```
## A first prompt [#a-first-prompt]
Once the server is wired in, try this in any MCP-capable assistant:
> *"Research how people talk about cold brew on Reddit over the last
> week, then show me the top themes and a few representative posts."*
The assistant routes the whole thing through `buzzabout__ask` — it
writes the query, previews it, collects posts, and analyses — then polls
for the answer:
1. `buzzabout__ask("research cold brew on Reddit, last week …")` →
returns `{ chat_id, message_id, status: "working" }` immediately.
2. `buzzabout__get_message(chat_id, message_id)` — long-polls until
`stop_reason` is non-null (the run can take a few minutes).
3. Walk the returned `blocks`: a `render: true` block →
`buzzabout__render(message_id, block_id)` shows it as an interactive
widget; a `render: false` block carries its `text` to relay.
4. Continue the thread by passing the `chat_id` back into `ask`.
Every tool call is visible in the host's UI — inspect what was sent and
what came back.
Collecting datasets, profiling audiences, and detecting patterns all
happen **through `ask`** — there are no direct CRUD tools. The other
tools are read-only lookups. See the [tools reference](/mcp/tools/reference).
## Troubleshooting [#troubleshooting]
**Trailing slash?** `https://mcp.buzzabout.ai/mcp/` (with
trailing slash). The unslashed `/mcp` redirects via 307, which strips
the request body in many MCP clients.
**Auth?** OAuth tokens expire — sign out and back in via the host's
integration settings. API keys can be revoked via the buzzabout web
app's `Settings → API keys`.
**Plan?** MCP access is gated by plan tier — your plan must include
MCP. `GET /v1/me` reports whether it's enabled.
If the tools list is empty, the most likely causes are:
1. **Auth failure** — sign out and back in (OAuth) or check key validity
(`x-api-key`).
2. **Network proxy / firewall** — outbound HTTPS to
`mcp.buzzabout.ai/mcp/` is blocked.
3. **Account lacks access** — your plan must include MCP.
Still stuck? Mail [support@buzzabout.ai](mailto:support@buzzabout.ai)
with the request id from any failed call.
## Next steps [#next-steps]
* [Tools reference](/mcp/tools/reference) — every tool the surface
exposes.
* [Authentication](/mcp/auth) — which auth method per client.
* [MCP overview](/mcp/overview) — the surface at a glance.
# Analyse feature requests (/tutorials/analyse-feature-requests)
If you build a B2B SaaS project-management tool, your roadmap signals are already sitting in public conversations — people asking "please add a Gantt view", "why doesn't it support SAML SSO", "I wish it integrated with Slack". The **Feature requests** skill reads a dataset you've already collected, pattern-matches those product-directed asks, ranks them by severity, and triages each one, so a stream of social chatter becomes a prioritised product backlog you can hand to your product team.
## Prerequisites [#prerequisites]
* A dataset with a completed collection run, so there are posts and comments to analyse. See [Set up your project](/tutorials/set-up-your-project) and [Create a mention collection](/tutorials/create-a-mention-collection).
* A chat or project open against that dataset — a skill can only be applied inside one. If you're new to applying skills, start with [Use skills](/tutorials/use-skills).
## Walkthrough [#walkthrough]
### Open skills [#open-skills]
Open a chat scoped to the dataset that holds your project-management mentions. In the chat composer, click the **Open skills** book icon to pop the skills picker. The skill needs a draft to attach to, so make sure you're inside a chat or project.
### Browse all skills [#browse-all-skills]
The picker opens on **Favourite skills**. Click **Browse all skills** in the footer to open the full library, then open the **Content & positioning** or **Audience research** category in the left **Skills** sidebar — **Feature requests** is tagged under both. You can also type into the search box to jump straight to it by name.
### Use this skill [#use-this-skill]
Click the **Feature requests** row to open its detail view and read the instructions. When it's the right one, click **Use this skill** to attach it to the current chat draft. The modal closes and the skill appears as a chip in the composer.
### Add context and send [#add-context-and-send]
Attach the project-management dataset as context in the composer before you send — the skill chip and the context chip sit independently on the same message. Type a short prompt such as `What features are people asking us to add?` and send. The skill's instructions tell the assistant to scan for product-directed asks, so you don't need to spell out the method.
### Let the pattern pipeline run [#let-the-pattern-pipeline-run]
To separate genuine feature requests from general complaints, the skill runs the async pattern-matching pipeline over your mentions. This takes a few minutes and may charge credits. If the dataset already has pattern assignments from an earlier run, the assistant reuses them instead of re-detecting, so a second pass is faster and cheaper.
The pipeline pattern-matches asks like "please add X" and "why doesn't it support Y" and deliberately keeps them **distinct from pain points** (problems with what already exists) and **objections** (reasons not to buy). It ranks each request by severity and triages it: requests that are **already solved** are flagged as a discoverability gap rather than a build, and the rest are scoped **small**, **medium**, or **large**.
### Read the severity bar and request table [#read-the-severity-bar-and-request-table]
The assistant returns the standard skill artifact: a hero chart, a detail table, and three takeaways. The hero chart is a **severity bar** colour-coded by recommended action — **ship**, **communicate** (for already-solved asks that just need surfacing), or **defer**. Below it, a **request detail table** lists each request with its severity, scope, and triage call, and the takeaways name the **top 3 to prioritise**. Open the result in the side panel to read the full breakdown and the mentions behind each row.
## Gotchas [#gotchas]
* **The pattern pipeline is asynchronous and may charge credits.** It polls for several minutes. The assistant reuses existing pattern assignments on the dataset when they're present, so it only pays the full cost on the first run; re-running over the same data is faster.
* **Feature requests are not pain points or objections.** The skill deliberately scopes to product-directed asks ("add X", "support Y"). Problems with the existing product are pain points; reasons people don't buy are objections. If you want those, use the matching skills instead — see Next steps.
* **Already-solved asks are a discoverability signal, not a build.** When people request something you already ship, the skill triages it as `communicate` rather than `ship` — the work is surfacing the feature, not building it.
* **You need collected mentions first.** Pattern matching requires a dataset that already has posts and comments — run a collection before applying the skill.
* **Applying the skill does not run it.** Attaching the chip only pins the instructions to the draft. The analysis (and any credit cost) happens when you send the message.
## Next steps [#next-steps]
Surface the problems people hit with what you already ship.
Turn a prioritised request into a structured content brief.
Learn the general flow for applying any skill to a chat.
# Analyse pain points (/tutorials/analyse-pain-points)
If you run an e-bike DTC brand, you already half-know the complaints — range anxiety, brake feel, delivery delays, patchy after-sales support — but you can't tell which one is actually costing you sales. The **Analyze pain points** skill reads a dataset you've already collected and returns a ranked map: a severity hero chart, pain-point clusters weighted by **reach + intensity + recurrence** (not raw mention count), and three handles for what to do next — a messaging fix, a product fix, and a content angle. You point the assistant at your mentions, apply the skill, and read the result.
## Prerequisites [#prerequisites]
* A dataset with a completed collection run, so there are posts and comments to analyse. See [Set up your project](/tutorials/set-up-your-project) and [Create a mention collection](/tutorials/create-a-mention-collection).
* Enough volume for the clusters to mean something. A few dozen mentions will surface anecdotes; aim for **\~100+** mentions before you trust the severity ranking.
## Walkthrough [#walkthrough]
You can run this two ways: apply the built-in skill (so the assistant follows the full pain-point pipeline every time), or just ask the assistant in plain language. Both end at the same Asset.
### Open a chat [#open-a-chat]
Open a chat against the dataset that holds your e-bike mentions — either from `/chat` or from your project's chat. The assistant works over the mentions that dataset's runs have already collected, so make sure the collection has finished first.
### Open skills [#open-skills]
In the chat composer, click the **Open skills** book icon (or type `/` at the start of an empty message) to pop the skills picker. It shows your **Favourite skills** with a **Browse all skills** footer.
### Browse all skills [#browse-all-skills]
Click **Browse all skills** to open the full library. **Analyze pain points** lives under both **Content & positioning** and **Audience research**, and it's tagged as a suggested skill, so it often surfaces near the top. You can also type its name into **Search skills…**.
### Use this skill [#use-this-skill]
Open the **Analyze pain points** row to read its instructions, then click **Use this skill** to attach it to the current chat draft. The modal closes and the skill appears as a chip in the composer. Attach your e-bike dataset as context if it isn't already, type a short prompt like `Analyse the pain points in this dataset`, and send.
If you'd rather skip the library, you can just ask in plain language — `What pain points do e-bike buyers complain about most?` — and the assistant will run the same pipeline. There is no separate "Pain Points" button; the skill is a saved instruction block, not a one-click report.
### Let the assistant run the pattern pipeline [#let-the-assistant-run-the-pattern-pipeline]
Once you send, the assistant runs the pattern-matching pipeline to discover and cluster the pain-point categories, weighing each cluster by reach, intensity, and recurrence rather than how often it's mentioned. This runs **asynchronously** and can take a few minutes. If the dataset already has pattern assignments from an earlier run, the assistant **reuses** them instead of re-detecting, so the answer comes back faster.
### Open in side panel [#open-in-side-panel]
The assistant wraps its deliverable in an Asset. Inline you'll see a clickable reference card with a short summary; click it to **Open in side panel** and read the full breakdown. You'll get a **severity hero chart**, a cluster detail table (each pain point with its weight and the mentions behind it), and **three handles** — a messaging angle, a product angle, and a content angle — telling you what to do with the top clusters.
### (Optional) Narrow the mentions by Sentiment [#optional-narrow-the-mentions-by-sentiment]
To read the raw evidence behind a cluster, open the mentions view and use the filter builder. Click **Add filter**, set the **Where** field to **Sentiment**, leave the operator as **is**, and pick **Negative**. Combine rows with **and** / **or**, and use **Reset** to clear. This narrows which mentions you're reading — the pain points themselves are still derived by the assistant, not by the filter.
**Refining the underlying query.** If your dataset is pulling in the wrong conversations, fix it upstream in the collection's keyword query rather than in the filter. Operators are **AND, OR, NOT** plus **parentheses** for grouping and **"double quotes"** for exact phrases. The **default join between two keywords is OR** (broadens reach) — add **AND** to require co-occurrence, **NOT** to exclude. Operators are case-insensitive (shown uppercase). Examples: `"electric bikes" NOT kids`; `nike AND (running OR marathon)`; `rivian polestar lucid` (implicit OR). Sanity-check complex queries against the live mention-count estimate.
## Gotchas [#gotchas]
* **There is no "Pain Points" button or asset type.** Pain points are auto-extracted by the **Analyze pain points** skill (or by asking in plain language) via the pattern pipeline. The result is shown in the generic Asset wrapper — `Pain Points` is a label the assistant uses internally, not a dedicated control.
* **There is no "emotion" mention filter.** The filter builder supports only **Keyword**, **Sentiment** (**Positive** / **Negative** / **Neutral**), **Views**, **Likes**, **Comments**, **Engagement rate**, and custom parameters. A finer-grained emotion breakdown exists per mention as a display field only — it is never filterable.
* **The pipeline is asynchronous and may charge credits.** Pattern/post-processing runs cost roughly 0.5 credit per mention and poll for several minutes. By default the skill reuses any existing pattern on the dataset to avoid re-running; it only re-detects when you explicitly ask.
* **Clusters are weighted, not counted.** Ranking blends reach, intensity, and recurrence, so a loud complaint from a few high-reach posts can outrank a quiet one mentioned more often. Read the weight column, not just the row order.
* **You need collected mentions first.** The pipeline needs a dataset that already has posts and comments — run a collection before applying the skill.
* **The chat needs a user session.** Over MCP, `buzzabout__ask` requires OAuth/JWT auth; an API key alone returns `403` and cannot reach the assistant.
## Now analyse it [#now-analyse-it]
The same dataset answers more than just "what's wrong." Apply another built-in skill to extract a different slice:
Surface the product-directed asks buried in the same mentions.
Turn the top pain points into a structured brief for content.
See the full menu of built-in skills and how to apply them.
# Pattern analysis (/tutorials/analyse-patterns)
Pattern analysis is the engine under most of buzzabout's research. It's a technique, not a button: you point a natural-language question at a dataset and the assistant discovers an *emergent taxonomy* — it reads the posts, finds the recurring distinctions, and groups them into a short, ranked set of clusters along **one axis you define per run**. Ask a B2B SaaS project-management dataset *"what pain points do people raise?"* and you get clusters like onboarding friction, integrations, pricing objections, and missing reporting — each backed by the exact posts that say so. Ask a different question over the same posts and you get a different map.
This page explains *what* pattern analysis is and what you can get from it. Running it is the easy part — it's a single question in a chat, covered at the bottom.
## What it can extract [#what-it-can-extract]
The axis is open-ended: you choose it by how you phrase the question. The same technique surfaces, among others:
* pain points
* feature requests
* objections
* topics & themes
* frequently asked questions
* CTA types
* hooks
* tone of voice
* communication / narrative style
* emotions
* intent
* content categories
Each run reads across **text and visual signals** in the posts, scores the recurring ones, and clusters them into a handful of clearly distinct, named categories — then assigns each post to the cluster it best matches, with the citations to prove it.
**Technique vs. use case.** Pattern analysis is the *approach*. Tutorials like [Analyse pain points](/tutorials/analyse-pain-points), [Analyse feature requests](/tutorials/analyse-feature-requests), and [Spot trends](/tutorials/spot-trends) are *use cases* that run this same technique with a specific question. There's no separate "pain points" or "trends" engine underneath — it's one pattern pipeline pointed at a different axis. That's why the possibilities are effectively endless: any distinction you can describe in a sentence is an axis you can cluster on.
## Why it's useful [#why-its-useful]
A dataset of thousands of posts is unreadable by hand. Pattern analysis collapses it into the handful of distinctions that actually recur — and, crucially, ranks them by how much they matter (reach × intensity × recurrence, not raw count), so a loud-but-rare complaint doesn't outweigh a quiet-but-common one. The output is a map you can act on: the themes to address, the language your audience uses, the objections to pre-empt, the gaps to fill — each traceable back to real mentions.
## How to run it [#how-to-run-it]
There's no setup, no "Patterns" page, and no button — you just ask. Point it at a dataset that already has collected mentions (aim for \~100+ for meaningful clusters), open its chat, and ask a question that defines the axis you care about:
* *"What pain points do people raise about project-management tools?"*
* *"What kinds of calls to action show up in these posts?"*
* *"What tones of voice do people use here?"*
The assistant interprets it as a pattern question, runs a `Pattern detection` block in the conversation (asynchronous, \~4 minutes), and then summarises the discovered clusters — citing the underlying posts for any of them. Per-post assignments also show up as an optional `Pattern Detections` column on the dataset's canvas, so you can see exactly which cluster each mention landed in. Reading and re-reading results is free; only the original run charges credits.
## Now analyse it [#now-analyse-it]
The built-in **Skills** turn the technique into ready-made reads, each pointing pattern analysis at a specific axis and shaping the result into a chart + table + takeaways. Open the skills picker from the chat input (`Open skills` book icon → `Browse all skills`), then `Use this skill`:
* [Analyse pain points](/tutorials/analyse-pain-points) — the friction clusters, ranked, with handles to act on.
* [Analyse feature requests](/tutorials/analyse-feature-requests) — the product-directed asks buried in your mentions.
* [Spot trends](/tutorials/spot-trends) — which clusters are accelerating over time.
## Gotchas [#gotchas]
* **One axis per run.** Each run discovers a taxonomy along the single axis your question defines. To analyse a different axis (tone instead of pain points), ask a new question — that's a separate run.
* **Running charges credits — reading is free.** A run costs roughly `0.5` credits per mention analysed. Browsing the results afterwards (the in-chat block, the canvas columns) never charges.
* **It runs asynchronously.** A typical run takes about four minutes while the assistant polls in the background — it's not an instant answer.
* **Asking again may not re-run it.** Once a pattern exists on a dataset, the assistant returns the existing results instead of re-running (an intentional cost guard). To force a fresh run, explicitly ask it to re-run the analysis.
* **The chat is the only trigger.** There's no "Patterns" page or "Run pattern detection" button; results surface only as the in-chat `Pattern detection` block and the per-dataset canvas column.
* **This is not [Smart Parameters](/tutorials/use-smart-parameters).** Pattern analysis discovers a taxonomy on its own; it does not classify each post against a label you defined up front. Reach for Smart Parameters when you already know the categories you want.
If you use the MCP tools directly, the chat trigger maps to `buzzabout__create_pattern_detection_run` (the run that charges credits), with `buzzabout__get_pattern_detection_run` to poll status and `buzzabout__get_pattern` / `buzzabout__get_pattern_item` to read the results for free.
## Next steps [#next-steps]
Run the technique against the pain-point axis for a ranked read on what frustrates your audience.
Point the same technique at the product-directed asks in your mentions.
See which clusters are growing or fading over time.
# Brand research (/tutorials/brand-research)
Brand research reads your **earned media** — the unprompted posts, comments, reviews, influencer shout-outs, and community threads (a subreddit, a YouTube comment section, an X reply) where people talk about your brand without you asking. Instead of guessing from your own campaign metrics, you collect those mentions into a dataset and ask what people actually love, complain about, and compare you to. Throughout this tutorial we'll use a cold-brew coffee brand as the running example: you type the brand as a keyword, preview how much conversation exists, then collect it into a dataset for analysis.
## Prerequisites [#prerequisites]
* **Enough conversation to analyse.** Meaningful brand analysis needs roughly **100+ mentions**. A large, well-known brand clears this easily; a small or new brand may simply have too little earned media to draw conclusions from yet. The preview card tells you how much is out there before you spend anything — if the estimate is thin, widen the timeframe to `Last year` before deciding.
* **Credits to cover the depth you choose** (1 mention ≈ 1 credit).
* **A Pro or Business plan for multi-source research.** Starter collects a single source — but you pick *any one* of the six platforms, not a fixed one.
## Walkthrough [#walkthrough]
### Search a topic or paste a URL [#search-a-topic-or-paste-a-url]
On the home screen, find the composer under the `Discover what people buzz about` heading. The input placeholder reads `Search a topic or paste a URL`. Type your brand name as a keyword — for example, `cold brew coffee` — to read what the open web says about you, or paste a **profile URL** (a Reddit, X, Instagram, TikTok, YouTube, or LinkedIn account) to analyse the posts on that account.
You can also click a suggested-question chip under a category such as `Trends` or `Competitors` to pre-fill a starting query.
URL search analyses
**accounts/profiles**
, not individual posts — paste the handle or profile link, not a single permalink to one comment or tweet.
### Adjust the inline filters [#adjust-the-inline-filters]
Before sending, you can tune the inline filter chips. The source picker covers `Reddit`, `X`, `Instagram`, `TikTok`, `YouTube`, and `LinkedIn` — multi-select on Pro and Business, single-source on Starter (you still choose which one of the six). The time chip offers `Last week`, `Last 3 months`, `Last year`, and `Custom`. There are also language and country chips; the language picker has a `Find language...` search field.
Defaults are: time `Last year`, language All, and country US. For a smaller brand with thin volume, keep the timeframe at `Last year` (or widen a narrower one) to gather enough mentions to be worth analysing.
### Send message [#send-message]
Press Enter or click the `Send message` (arrow) button. A new chat is created, you land on the chat page, and your message auto-sends to the assistant.
### Keyword query [#keyword-query]
For a typed topic, the assistant returns a research preview card titled `Keyword query`, showing an estimated mention count and a volume badge. For our `cold brew coffee` example, this is where you confirm there's enough conversation to research before spending any credits — if the estimate is well under \~100, widen the timeframe to `Last year` or broaden the keywords before collecting.
Edit the keyword chips directly to shape what you collect. The add-input reads `Enter a keyword query` (or `Add keyword…`), and you press Enter or comma to add a chip. This is where boolean operators come in.
**Boolean operators in the keyword query.** Operators are **AND, OR, NOT** plus **parentheses** for grouping and **"double quotes"** for exact phrases. The **default join between two keywords is OR** (it broadens reach) — add **AND** to require co-occurrence, **NOT** to exclude. Operators are case-insensitive (they display uppercase). Examples:
* `"cold brew" NOT decaf` — posts mentioning the exact phrase `cold brew` but not `decaf`.
* `"cold brew" AND (subscription OR refill)` — cold-brew posts that also mention a subscription or refill.
* `stumptown chameleon "high brew"` — any post mentioning any of the three competitors (implicit OR).
Sanity-check complex queries against the live mention-count estimate on the card.
### URL query [#url-query]
If you pasted a profile URL instead, the card is titled `URL query` and reports `profiles found` rather than a mention estimate — it sizes the work by the **accounts** you're collecting, not a mention count. There is **no `Research depth` picker** on a URL query and no credit badge; the source picker is locked because sources are derived from the URLs you pasted. Use this when you want to read the posts of a specific influencer, community account, or your own brand profile.
### Research depth [#research-depth]
For keyword queries, refine the preview in place: edit the keyword chips, and change the source, time, language, or country chips — each edit re-generates the estimate. Then pick a `Research depth`. The options are `Overview` (100 mentions), `Landscape screening` (200 mentions), `Qualitative research` (500 mentions), and `Quantitative analysis` (1,000 mentions). The helper text reads `How many mentions to collect when you run research.`
The credit cost updates live as you change depth, since 1 mention ≈ 1 credit. Depth options above your plan cap are disabled: Starter caps at 300 mentions per research (so only `Overview` and `Landscape screening` are selectable); Pro and Business reach the full 1,000; Enterprise goes up to 10,000 mentions per research.
### Preview mentions [#preview-mentions]
Optionally click `Preview mentions` to inspect a sample of results in the canvas before committing. This is free — it doesn't spend credits or create a dataset. Use it to sanity-check that the mentions are genuinely about your cold-brew brand and not an unrelated topic.
### Start research [#start-research]
When the preview looks right, click `Start research`. This sends `Collect this dataset.` with your chosen filters and depth, spends the credits, and creates the dataset run. The preview hides and a dataset card takes over the turn while collection runs.
### Show dataset [#show-dataset]
When the run completes, the collected mentions appear as a mentions table. This is where the downstream `Sentiment` and `Sentiment score` columns and the sentiment filter live — they're part of the collected data, not the composer. Use `Show dataset` to open the full table, then ask follow-up questions in the chat against the dataset.
## Now analyse it [#now-analyse-it]
Collecting the dataset is the starting line, not the finish. Once your cold-brew mentions are in, the dataset is an **extraction menu** — open the skills panel (the book icon in the chat input) or just ask the assistant in chat, and pull out the answers that matter:
* **Pain points** — the recurring complaints and frustrations buried in the mentions.
* **Feature requests** — what people wish your brand offered.
* **Positive and negative quotes** — the standout praise and criticism in people's own words.
* **Share of voice** — your portion of total mention volume against rival brands. Ask the assistant to *"compare share of voice across these brands in this dataset"* and it renders the comparison as horizontal bars (there's no standalone Share-of-Voice button — it's an analysis you request).
* **Audience** — who is doing the talking, their interests and brand affinities, and an LLM-inferred personality (OCEAN) read.
See the cross-links below for step-by-step playbooks on each.
## Gotchas [#gotchas]
* **Volume matters.** Brand analysis is only meaningful at roughly **100+ mentions**. Very small or new brands may have too little earned media to draw conclusions from — widen the timeframe to `Last year` and broaden keywords before deciding there's "nothing there".
* **Keyword vs URL is auto-detected.** A typed topic gives a `Keyword query` preview with a mention estimate, volume badge, and a `Research depth` picker. A pasted URL gives a `URL query` preview that reports `profiles found` (not mentions), has **no depth picker and no credit badge**, and a **locked** source picker — sources are derived from the URLs.
* **URL search is profiles, not posts.** It analyses the accounts you paste (up to 100), not a single permalink. Paste profile/handle links, not one-post URLs.
* **Single-source is not Reddit-only.** Starter collects one source per research, but you choose any of `Reddit`, `X`, `Instagram`, `TikTok`, `YouTube`, or `LinkedIn`. An inline `Multi-source research is available on Pro & Business` nudge appears when you try to add a second.
* **Plan caps differ from picker options.** Starter caps at 300 mentions per research (Overview and Landscape screening only); Pro and Business reach 1,000; Enterprise goes up to 10,000 mentions per research.
* **Default join between keywords is OR**, which broadens reach. Add `AND` to require co-occurrence and `NOT` to exclude; wrap multi-word phrases in `"double quotes"`.
* **Preset time and custom date range are mutually exclusive.** Picking a preset clears the custom range and vice versa; custom range is capped to the last 5 years.
* **`Preview mentions` is free; `Start research` spends credits.** Only `Start research` creates the dataset run.
* **Editing any preview field regenerates the estimate.** Changing a keyword chip, source, time, language, country, or URL fires a regenerate; buttons lock while a regenerate is in flight or a message is streaming.
* **Sentiment is downstream, not in the composer.** It appears afterward as a `Sentiment` / `Sentiment score` column and a filter on the collected mentions table.
* **Input is capped at 4000 characters** (an `N left` counter appears past 3000).
## Next steps [#next-steps]
Run the same flow against rival brands to compare share of conversation.
Profile who is talking about your brand — interests, affinities, and OCEAN traits.
Surface the complaints and unmet needs hiding in your collected mentions.
Apply ready-made skills to extract quotes, requests, and share of voice from the dataset.
# Competitor research (/tutorials/competitor-research)
When you sell a B2B SaaS project-management tool, the questions that move the roadmap are about your rivals: what users actually say about each one across the open web, which feature requests and pain points keep recurring, who their audiences are, and whose share of voice is growing. Competitor research in buzzabout is not a separate screen or wizard — it is the standard research flow scoped to competitor keywords (user-generated mentions) or competitor profile URLs (their own posts). You collect one dataset per competitor, group them in a project, and then point the assistant and skills at the result to compare share of voice, benchmark engagement, and profile the people talking.
## Prerequisites [#prerequisites]
* A buzzabout account with available credits (1 mention ≈ 1 credit). Audience analysis and CSV export require a Pro plan or higher.
* Optional: competitor profile or post URLs on a supported platform (`reddit`, `tiktok`, `youtube`, `x`, `instagram`, or `linkedin`) for URL-mode research.
* New to the research flow? Start with [Brand research](/tutorials/brand-research) — competitor research reuses the same preview and run mechanics.
## Boolean keywords for competitor sets [#boolean-keywords-for-competitor-sets]
Competitor research lives or dies on the keyword query, so it is worth knowing the operator model before you start. The keyword chip editor supports **AND, OR, NOT** plus **parentheses** for grouping and **"double quotes"** for exact phrases. The **default join between two keywords is OR** (it broadens reach) — add **AND** to require co-occurrence, **NOT** to exclude. Operators are case-insensitive and shown uppercase.
* `asana monday "clickup"` — any post mentioning any of the three rivals (implicit OR), good for a head-to-head competitor set.
* `asana AND (pricing OR "too expensive")` — Asana posts that also raise cost, to isolate one pain theme.
* `"project management" NOT jira` — the category conversation with one incumbent removed.
Sanity-check complex queries against the live mention-count estimate the editor shows — long boolean chains can broaden or narrow reach more than you expect.
## Walkthrough [#walkthrough]
### Competitors [#competitors]
From the home screen (`Discover what people buzz about`), open the `Competitors` tab in the suggested questions and pick a starting prompt — for example `How are people comparing CrewAI vs LangChain for building agents?` or `Reverse-engineer what's working for a competitor — paste their profile URL.` These are examples to adapt; for a project-management tool you might instead ask how people compare your two closest rivals.
### Keyword query [#keyword-query]
Type a competitor comparison query into the chat input and send it — for example a phrase comparing two rival project-management tools. This creates a chat, and the assistant returns a research preview of type `Keyword query`. A keyword query captures user-generated mentions across the web that match your keywords. Edit the keyword chips to refine which terms are matched, using the boolean operators above.
### URL query [#url-query]
Alternatively, paste a competitor's profile or post URL into the chat input. The assistant returns a `URL query` preview, which scopes to that competitor's own profile and posts and reports a profile count (`profiles found`) rather than a mention estimate. Add or remove competitor URLs with the `Add URL…` field — the source is auto-detected from the host. URL queries have no `Research depth` picker and no credit badge; the scope is the profiles you add.
### Research depth [#research-depth]
For keyword previews, refine the filter row (sources, time and date range, language, country) — each edit regenerates the preview and updates the estimate. Then pick a `Research depth`. The picker controls `How many mentions to collect when you run research.` and sets the credit cost: `Overview` (100 mentions), `Landscape screening` (200), `Qualitative research` (500), or `Quantitative analysis` (1,000). Depth applies to keyword runs only; URL previews are scoped by the profiles you add.
### Preview mentions [#preview-mentions]
Click `Preview mentions` to inspect a sample of matching mentions in the canvas. This is free — it does not run collection or spend credits — so use it to sanity-check that your competitor keywords are pulling relevant conversations before you commit.
### Start research [#start-research]
When the preview looks right, click `Start research`. This spends credits and runs the dataset collection. The preview hides and a dataset card takes over the turn, showing `Collected N mentions` where N is however many your depth and matches produced. The run is asynchronous — the preview polls while pending, so give it a moment to finish.
### Create project [#create-project]
To keep competitors together, run a separate dataset for each rival and group them in a project. Click `Create project` (`Projects help you organize chats, datasets, and listening agents around a topic or brand.`), give it a `Project name` such as `Q2 Competitor Analysis`, and click `Create`. Run each competitor's research chat from inside the project.
### Datasets [#datasets]
Every dataset you collect from a project chat lands in the project's `Datasets` panel (`Linked datasets from project chats`). This is where your competitors sit together — one dataset per rival keyword set or profile URL. The project groups the datasets; it does not add a built-in side-by-side compare view, so you read across them in the panel and in chat.
## What you can do after collecting [#what-you-can-do-after-collecting]
A collected competitor dataset is raw material. The payoff is analysing it — and most analysis runs in chat, either by asking the assistant directly or by applying a skill. Open the skills picker from the chat input (the book icon, `Open skills`), choose `Browse all skills`, open a skill, and click `Use this skill` to inject its instructions into your next message. Most skills return the same shape: a hero chart, a detail table, and three takeaways. Several depend on pre-computed enrichment (sentiment, emotion, brand, topic columns, or an audience dataset) and will say so in one line if the data is not present.
### Compare share of voice [#compare-share-of-voice]
Share of voice is not a button, page, or standalone feature — it is something you ask for. Apply the `Mentioned brands` skill, which reads the pre-computed brand-mention field per post and renders a per-brand share-of-voice bar coloured by sentiment, plus a brand detail table. Or ask the assistant in plain language, for example `compare share of voice across Asana, Monday and ClickUp in this dataset` or `show share of voice by platform`. The assistant renders the comparison as horizontal mention-volume bars — each brand's or platform's portion of total relevant mentions. For a single competitor dataset this tells you who dominates the conversation; across the project's datasets you read the shares side by side.
### Analyse who engages with each competitor [#analyse-who-engages-with-each-competitor]
To understand the people behind a competitor's mentions, build an audience dataset from a collected dataset. In the chat where the dataset lives, ask the assistant to profile that dataset's audience. An `Audience research in progress` card appears; when it finishes, click the `View … profiles` button (it shows the live profile count) to open the audience canvas — a sortable, filterable profiles table. Open any profile for its location and language, content niche, interests, brand affinities, authenticity, creator tier, a marketing-focused summary, and a `Personality (OCEAN)` section with bars for `Openness`, `Conscientiousness`, `Extraversion`, `Agreeableness`, and `Neuroticism`.
OCEAN is inferred by an LLM from each person's public posts — a directional AI estimate, not a psychometric test — and is hidden for low-signal profiles. Used as creative guidance, a high-`Openness` competitor audience tends to respond to novel, experimental messaging, while a high-`Conscientiousness` audience responds to proof and reliability framing. The `Audience demographic chart` and `Audience psychographic chart` skills summarise the same data across the whole audience dataset. Audience analysis is a Pro-plan-and-up feature and costs 3 credits per profile. See [Run audience analysis](/tutorials/run-audience-analysis) for the full flow.
### Benchmark mention volume and engagement [#benchmark-mention-volume-and-engagement]
Ask the assistant to benchmark each competitor's collected mention volume and engagement, and to break the numbers down by social network — for example `which network drives the most engagement for these mentions?`. Skills like `Topics vs. Reach – Bar Chart`, `Emotions vs. %ER – Bar Chart`, and `Intentions vs. %ER – Bar Chart` turn the dataset into per-segment bars you can read across competitors. Because each rival lives in its own dataset, you run the same skill on each and compare the outputs.
### Surface trends, feature requests, and pain points [#surface-trends-feature-requests-and-pain-points]
Point pattern-pipeline skills at a competitor dataset to extract what to build and what to avoid: `What's trending` splits the dataset into recent versus baseline windows and shortlists rising themes; `Feature requests` ranks product-directed asks and triages each one; `Analyze pain points` clusters complaints weighted by reach and intensity. `Positive / negative quotes` pulls the strongest testimonial-grade and warning-grade quotes from a rival's conversation. These pattern runs are asynchronous and may charge credits.
To keep any of this live, attach a [listening agent](/tutorials/set-up-a-listening-agent) so the competitor's queries re-run on a schedule and the dataset keeps growing.
## Gotchas [#gotchas]
* **Owned (URL) vs user-generated (keyword) are different scopes.** A `URL query` scopes to a competitor's own profile and posts and returns a profile count; a `Keyword query` captures public mentions across the web and returns a mention estimate. Choose deliberately based on whether you want their channel or the conversation around them.
* **You cannot fully exclude a competitor's own posts from a keyword run.** Keyword runs collect public mentions matching the keywords, which can include the brand's own posts. There is no owned/user-generated exclusion toggle.
* **Preview type is locked.** A keyword preview always regenerates as a keyword preview, and a URL preview always as a URL preview. You cannot switch a preview between keyword and URL mode.
* **`Preview mentions` is free; `Start research` spends credits.** 1 mention ≈ 1 credit, at the depth you picked (100, 200, 500, or 1,000).
* **Volume matters.** Meaningful share-of-voice and audience comparisons need a healthy sample — aim for \~100+ mentions per competitor. A thin dataset for a small rival will skew any comparison.
* **Research depth is plan-clamped.** On the Starter plan you pick a single source and only `Overview` (100) and `Landscape screening` (200) are selectable; multi-source research, deeper depths, audience analysis, and CSV export unlock at Pro and above. Options above your plan's maximum are disabled and auto-fall-back to the highest allowed depth.
* **The URL-type source picker is locked.** For URL previews, sources are derived from the pasted URLs and are not independently editable.
* **URL hosts are restricted.** Only `reddit`, `tiktok`, `youtube`, `x`/twitter, `instagram`, and `linkedin` are accepted. An unknown host shows `Unsupported URL — must be reddit, tiktok, youtube, x, instagram, or linkedin` and does not regenerate. A duplicate shows `URL already in list`.
* **Runs are asynchronous.** The preview polls while pending; a stuck run is flipped to failed by a backend watchdog after about 60 seconds, after which the dataset card exposes a `Show preview` toggle.
* **A project groups, it does not compare.** Projects keep chats, datasets, and listening agents together — there is no built-in side-by-side compare view, so comparison across the `Datasets` panel and in chat is manual.
## Next steps [#next-steps]
The same research flow scoped to your own brand keywords and channels.
Compare per-brand mention share coloured by sentiment with the Mentioned brands skill.
Profile who engages with a competitor — demographics, interests, and OCEAN psychographics.
Follow specific competitor profiles and their own posts over time.
# Connect MCP to Claude (/tutorials/connect-mcp-to-claude)
Once Buzzabout is wired into Claude over MCP, you can research a market without leaving the chat: ask Claude to spin up a dataset, collect mentions across Reddit, X, TikTok and the rest, profile the audience, then ask follow-up questions in plain language — all driven from the same conversation. A developer wiring Buzzabout into Claude gets all eleven `buzzabout__*` tools, so an agent can collect, list, analyse and ask without a single hand-written API call. There are two ways to connect: OAuth for an interactive user in Claude Desktop or Claude.ai, and an `x-api-key` for headless or server-side agents. This tutorial covers both.
## Prerequisites [#prerequisites]
* **To mint an API key:** a Buzzabout account on the **Business** plan. API access is a Business plan feature — see the gotcha below for the upgrade path.
* **For the Claude.ai OAuth path:** a Claude.ai workspace on a **Team or Enterprise** plan with custom integrations enabled. Claude Desktop works on any plan.
* **For the headless path:** an MCP-capable host or SDK (Python `mcp`, or the TypeScript `@modelcontextprotocol/sdk`) that can send a custom `x-api-key` header.
## Walkthrough [#walkthrough]
### Decide your auth path [#decide-your-auth-path]
Pick how Claude will authenticate before you wire anything up:
* **OAuth** — for an interactive person using Claude Desktop or Claude.ai. Claude runs a browser sign-in on first use and stores a JWT. This path unlocks all eleven `buzzabout__*` tools, including `buzzabout__ask`.
* **`x-api-key`** — for a headless agent or server process. You mint a key in the web app and send it as a header on every request. This path covers the ten REST-mirror tools but not `buzzabout__ask`.
The MCP transport endpoint is the same for both: `https://api.buzzabout.ai/mcp/`.
### API Keys [#api-keys]
For the headless path, you mint the key in the web app. Open **Settings** and switch to the **API Keys** tab (this surface lives at `/settings?tab=api-keys`). The tab is described as `Manage API keys for programmatic access to Buzzabout`. If you have no keys yet, you'll see `No API keys yet` and `Create your first API key to start using the Buzzabout API`.
### Create API Key [#create-api-key]
Click **Create API Key**, give it a descriptive name in the **Key Name** field (the placeholder reads `e.g., Production API Key`), then click **Create Key**. The button shows `Creating...` while it works.
When it finishes, the **API Key Created** dialog appears with the warning `Make sure to copy your API key now. You won't be able to see it again!`. Click **Copy to Clipboard** (it confirms with `Copied!`) and store the key somewhere safe. The value looks like `bz_live_...`. Click **Done** to close. Afterwards the list only shows `Key ends with: •••` — there is no way to reveal the full value again.
### Open the integration settings (OAuth) [#open-the-integration-settings-oauth]
For the interactive path, point Claude at the MCP transport URL:
* **Claude Desktop:** `Settings → Developer → Edit Config`. Claude opens `claude_desktop_config.json` in your editor.
* **Claude.ai:** `Settings → Integrations → Add custom`.
### Add the Buzzabout server [#add-the-buzzabout-server]
Use the streamable HTTP transport and the trailing-slash URL `https://api.buzzabout.ai/mcp/`.
Add a `buzzabout` entry inside the existing `mcpServers` block:
```json title="claude_desktop_config.json"
{
"mcpServers": {
"buzzabout": {
"transport": "streamable-http",
"url": "https://api.buzzabout.ai/mcp/"
}
}
}
```
In the `Add custom` dialog, set:
| Field | Value |
| ----- | ------------------------------- |
| Name | `buzzabout` |
| URL | `https://api.buzzabout.ai/mcp/` |
| Auth | OAuth |
### Authorise [#authorise]
The first time Claude calls a tool, it opens a browser window to `api.buzzabout.ai/mcp/oauth/authorize`. Sign in with your Buzzabout account and Claude exchanges the redirect code for a JWT, which it stores locally. You won't see this prompt again until the token expires.
### Wire a headless agent (API key) [#wire-a-headless-agent-api-key]
If you took the `x-api-key` path instead, send a POST to `https://api.buzzabout.ai/mcp/` with the `x-api-key` header on every request, or configure your MCP SDK's HTTP client to attach it. In Python that's the `streamablehttp_client`; in TypeScript it's the `StreamableHTTPClientTransport`, each with a custom header carrying your `bz_live_...` key.
The dual-auth middleware checks `x-api-key` first and falls back to `Authorization: Bearer `. If neither resolves, the server returns `401` with a `WWW-Authenticate` header pointing at the OAuth metadata.
### Verify [#verify]
Open a new conversation and ask:
> *"Which Buzzabout tools do you have available?"*
Claude should list the eleven `buzzabout__*` tools. Async tools like `buzzabout__create_dataset_run` and `buzzabout__create_audience_dataset_run` return a `pending` status, so the host LLM polls `get_*_run` until the status is `completed` or `failed`. Collection and analysis runs charge credits.
## Now drive it from chat [#now-drive-it-from-chat]
With the tools connected, you can run a whole research loop in conversation. A good first prompt:
> *"Create a Buzzabout dataset for e-bike commuters, collect a few hundred mentions, then tell me the top complaints."*
Claude will call `buzzabout__create_dataset`, kick off a collection run, poll until it finishes, then reach for `buzzabout__ask` (OAuth path) or `buzzabout__list_mentions` to read the results. From there the data is the same data the web app analyses — so the deeper extraction (pain points, feature requests, share of voice, audience and OCEAN profiles, trends) lives in the analysis tutorials below.
## Gotchas [#gotchas]
* **Trailing slash is required.** Use `https://api.buzzabout.ai/mcp/`. The unslashed `/mcp` returns a `307` that strips the request body in many MCP clients, causing silent failures or empty tool lists.
* **Use the right host.** The endpoint is `api.buzzabout.ai/mcp/`, not `mcp.buzzabout.ai`.
* **`buzzabout__ask` needs OAuth.** It only works over an OAuth/JWT session. An `x-api-key` caller attempting it gets a structured `forbidden` error. The other ten tools work with either auth method.
* **API keys are shown once.** When the dialog says `Make sure to copy your API key now. You won't be able to see it again!`, copy it immediately. Afterwards you only see `Key ends with: •••`.
* **API access is a Business plan feature.** When it's unavailable the create button is replaced by an `Upgrade plan` button and the empty state reads `API access is a Business plan feature`.
* **Claude.ai custom integrations need Team or Enterprise.** Free and Pro workspaces don't see the `Add custom` option. Claude Desktop has no such restriction.
* **No destructive MCP tools.** There are no PATCH or DELETE tools over MCP — admin and destructive actions stay in the web app.
## Next steps [#next-steps]
Ask the AI assistant questions against the data Claude can now reach.
Define custom analysis parameters Claude can run over your posts.
# Create a mention view (/tutorials/create-a-mention-collection)
Once you've collected mentions into a dataset, the Library is where you make them readable. A saved **View** is a personal lens over that data: for a cold-brew coffee brand you might keep one view for "negative Reddit mentions from the last 30 days" and another that combines your brand dataset with a competitor dataset so you can scan both feeds side by side. Build the lens once, save it, and come back to a fresh read whenever you want — then export the rows you care about to CSV. (A saved view is sometimes called a "collection"; in the app the object you save is a **View**.)
## Prerequisites [#prerequisites]
* A **dataset with collected mentions** in the app. If you haven't collected any yet, run [Brand research](/tutorials/brand-research) first — the Library only shows mentions you've already collected.
* A **Pro, Business, or Enterprise plan** if you want to export to CSV. CSV export is disabled on lower plans.
## Walkthrough [#walkthrough]
The Library (`/library`) is a read-only surface over every mention you've collected, across all your datasets. You don't create datasets here — collection happens in chat. What you do here is shape, save, and export views. A View is just your **current filters and sort** saved under a name, so saving one never requires picking individual rows.
### All mentions [#all-mentions]
Open the Library. **All mentions** is the unfiltered feed spanning every dataset you've collected. Use the filter and sort controls to narrow it down — filter by **sentiment**, **platform**, **dataset**, and **posting date**, and sort the table (for example, newest first to scan the latest mentions). Because the feed spans all datasets, there's a `dataset` column and filter, so you can scope to one dataset or leave several in view at once.
To combine datasets into one view, simply leave more than one selected in the `dataset` filter — the table merges their mentions into a single feed.
### Save as view [#save-as-view]
When the filters and sort give you a feed worth returning to, save it straight from the **applied-filters bar** above the table — no row selection needed. Click the **Save as view** button on that bar, then name it in the popover (for example, `Negative cold-brew · last 30 days`) and click **Save**. The popover spells out what it captures: "Save the currently-filtered mentions as a new view." The view stores your filter and sort expression, not a fixed list of posts — so as new mentions arrive that match, they show up the next time you open it.
If you later tweak a view's filters, the same bar swaps in **Save changes** (overwrite the active view) and **Save as new** (branch off a fresh view) so you can decide where the edits land.
### Views [#views]
Switch between saved views from the **Views** dropdown next to **All mentions**. Selecting a view applies its saved filters in one click; if you tweak the filters afterward an **Unsaved changes** dot appears so you know the live feed has drifted from what's saved. From the same menu you can **Rename view** or **Delete view**. Pick **All mentions** to clear back to the full feed.
### Export [#export]
To pull mentions out of the app, select rows in the mentions **table** (the selection bar shows a count like `120 selected`, and a scope menu lets you grab the first N), then click **Export**. You'll get a `library-.csv` download and a toast confirming how many mentions were exported.
The export includes **all columns plus every Smart Parameter** for the selected rows — regardless of which columns you've toggled visible in the table. Column visibility is only a viewing preference; it doesn't affect what lands in the file. Export is a Pro+ feature; on lower plans the button stays visible but disabled with an upgrade tooltip.
## Now analyse it [#now-analyse-it]
A view is the input to analysis, not the end of it. Once you can see a clean, filtered feed, hand it to the assistant to turn raw mentions into findings:
* **Pain points and complaints** — [Analyse pain points](/tutorials/analyse-pain-points).
* **Feature requests** — [Analyse feature requests](/tutorials/analyse-feature-requests).
* **Positive and negative quotes, objections, and themes** — apply [Skills](/tutorials/use-skills) in chat against the dataset.
* **Share of voice across brands** — produced by the "Mentioned brands" skill; see [Use insights](/tutorials/use-insights).
## Gotchas [#gotchas]
* **Views are personal.** Each saved view is private to you (scoped to your user). A teammate on the same account sees their own views list, not yours — there's no team sharing of views.
* **A view saves filters, not a fixed set of posts.** It re-runs your filter and sort expression each time you open it, so the same post can surface in several views and new matching mentions appear automatically.
* **Saving a view never uses row selection.** The **Save as view** button lives on the applied-filters bar and captures the current filters and sort. Row selection in the table is only for **Export** — the Library deliberately leaves "Add to view" off the selection bar.
* **You can't create a dataset from the Library.** `/library` is read-only over already-collected mentions. Collection happens in chat — there is no "Collect more data" button in the Library.
* **Export needs Pro+.** On plans without it the Export button is disabled with a `CSV export isn't available on your plan. Upgrade to export.` tooltip.
* **Export ignores column visibility.** The CSV always contains all columns and every Smart Parameter for the selected rows — you don't need to enable a column to export it.
* **Selection and Export live in the table, not card view.** Bulk-select rows from the table to bring up the selection bar.
To keep a view fresh, attach a **listening agent** to its dataset. The agent re-runs the dataset's queries on a schedule and adds new mentions into the same dataset, so your saved view stays current without manual re-collection. See [Set up a listening agent](/tutorials/set-up-a-listening-agent).
## Next steps [#next-steps]
Collect the mentions that feed your views in the first place.
Keep a dataset growing on a schedule so your views stay fresh.
Turn a filtered view into the patterns and takeaways that drive decisions.
# Create a watchlist (/tutorials/create-a-watchlist)
A "watchlist" is the set of exact accounts, profiles, subreddits, or URLs you want to keep an eye on over time — your rivals' accounts, the loudest influencers in your category, the subreddits where your niche lives, or specific posts you care about. If you run a B2B SaaS project-management tool, that might be the X and LinkedIn accounts of two competing tools, a couple of productivity influencers, and `r/projectmanagement`. buzzabout has no literal **Watchlist** button or object — instead you assemble one from two real building blocks: a **URL query** dataset that collects from the exact profiles you name, and a listening agent that re-scrapes it on a schedule and posts a focused digest of what's new.
Use this pattern to **track competitors**, **track influencers**, **monitor your niche by exact profiles or subreddits**, or **watch specific URLs** — anything where you already know who or what you want to follow.
There is no **Watchlist** object or page in buzzabout. A watchlist is a use-case pattern you build from two real pieces: a **URL query** dataset (Step 1) and a listening agent (Step 2).
## Prerequisites [#prerequisites]
* A set of profile, account, subreddit, or post URLs you want to watch. Supported platforms are Reddit (including subreddits), TikTok, YouTube, X, Instagram, and LinkedIn.
## Walkthrough [#walkthrough]
### Add URL… [#add-url]
In any chat, start a research preview and switch it to a **URL query**. Paste each profile, account, subreddit, or post URL into the **Add URL…** input — every accepted URL becomes a chip in the list. For the project-management example you might add the X and LinkedIn accounts of two rival tools, a couple of productivity influencers on YouTube and TikTok, and the `r/projectmanagement` subreddit.
You can add up to 100 URLs to a single query, and they all go into one dataset. Each host is validated as you add it:
* An unsupported host is rejected with *Unsupported URL — must be reddit, tiktok, youtube, x, instagram, or linkedin*.
* A repeat is rejected with *URL already in list*.
### Start research [#start-research]
A **URL query** behaves differently from a keyword query. There is no research-depth picker and no credit badge — the sources are derived from the URLs you pasted, not chosen separately. Instead of a mention estimate, the preview shows a profiles-found count — for example **7 profiles found** — confirming how many of your pasted URLs were recognised.
Click **Start research** to collect from those profiles into a single dataset. This is the watchlist dataset your listening agent will watch.
### New listening agent [#new-listening-agent]
Now attach a listening agent so the watchlist keeps refreshing. Open the **Listening agents** page from the left sidebar (`/agents`), or open a project and switch to its **Listening agents** tab. Click **New agent** (or **Add agent** on a project tab) to open the **New listening agent** modal, whose first step is titled *Configure what this agent tracks and when it runs.*
### Instructions [#instructions]
Give the agent a **Name** — the placeholder reads `e.g. Daily AI mentions`. Something like `Competitor & niche watch` fits this example. Then write **Instructions**, which answers *What should this agent summarise from the scraped posts?* This field is where you **focus** the watch: instead of generic updates, tell the agent exactly what to surface each run. Pick the angle that matters to you, for example:
* **Complaints monitoring** — "Flag complaints and frustrations about rival project-management tools."
* **Gotchas** — "Call out pricing changes, deprecations, and migration pain people mention."
* **Trends analysis** — "Summarise emerging trends and shifts in how the category is discussed."
* **Topics analysis** — "Group new posts by topic and highlight which topics are growing."
A focused instruction is what turns a raw scrape into a digest worth reading.
### Datasets [#datasets]
Select the watchlist dataset you collected in Step 2 from the **Datasets** picker. This is a multi-select, so one agent can watch several datasets at once — for example a competitors dataset and an influencers dataset. At least one is required. If the list is empty you'll see *No datasets in your account yet* with the hint *Run a research from any chat first; the resulting dataset will appear here.*
### Mentions per run [#mentions-per-run]
Choose **Mentions per run** — the options are 10, 25, 50, 100, 150, and 200, defaulting to 50. This sets how many mentions each scheduled run pulls from the watched profiles. A larger count means more data per run, and more cost per run. It is a separate control from the initial **Start research** collection.
### Schedule [#schedule]
Pick a **Schedule**: **Daily** or **Weekly**. Weekly adds a day picker. Then choose a time — note it is in `(UTC)`, so convert from your local time. A daily morning slot is a sensible default for keeping up with competitor activity.
### Create agent [#create-agent]
Optionally click **Next** to advance to the destinations step and deliver each digest via Slack, email, or webhook — this is optional, and the agent still posts summaries into its own chat with no integrations. Then click **Create agent** to save. You land back on the **Listening agents** page with the new agent in the side panel.
From now on, each run re-scrapes your watchlist, grows the dataset with new mentions, and posts a focused digest you can read like a chat.
## Now analyse it [#now-analyse-it]
The digest is the daily readout, but the real value is that every run feeds fresh mentions back into the watchlist dataset — so the same analysis you run on a one-off collection stays current automatically. Once the agent has been running for a while, open the dataset and dig in:
* **Run analysis skills on the fresh data.** Apply skills to surface pain points, feature requests, objections, and competitor share of voice over the mentions your watchlist keeps pulling in. See [use skills](/tutorials/use-skills).
* **Save a live Library view.** Filter the growing mentions by sentiment, platform, dataset, or posting date and save the view — it keeps showing the latest mentions as the agent adds them. See [use insights](/tutorials/use-insights).
* **Keep competitor and audience work current.** Because the dataset keeps growing, the watchlist is the easiest way to keep [competitor research](/tutorials/competitor-research) and [audience analysis](/tutorials/run-audience-analysis) from going stale.
## Gotchas [#gotchas]
* **There is no "Watchlist" feature.** A watchlist is the two-step pattern above — a **URL query** dataset plus a listening agent. Don't look for a Watchlist button or page; there isn't one.
* **Six platforms are supported.** A URL query accepts Reddit (including subreddits), TikTok, YouTube, X, Instagram, and LinkedIn. Anything else is rejected inline with *Unsupported URL — must be reddit, tiktok, youtube, x, instagram, or linkedin*, and duplicates with *URL already in list*.
* **Up to 100 URLs per query.** A single URL query is capped at 100 URLs. To watch more than that, split them across more than one dataset and attach the same agent to all of them.
* **The URL flow has no depth or credit picker.** Unlike a keyword query, a URL query hides the depth tabs and the credit badge — sources are derived from the URLs, and the preview shows a profiles-found count instead of a mention estimate.
* **Mentions per run is the agent's control, not the collection's.** The agent's **Mentions per run** (10–200, default 50) sets how much each scheduled run scrapes; it is separate from the initial **Start research** collection.
* **Schedule is Daily or Weekly only, in UTC.** Times are fixed hours in UTC. Weekly adds a day picker.
* **Every run consumes credits.** Each scheduled or manual run re-scrapes the watchlist, which consumes credits scaling with **Mentions per run**. There is no per-run credit figure shown in the agent UI; the cost comes from the underlying scrape.
## Next steps [#next-steps]
Full reference for creating, scheduling, and managing listening agents.
Run a one-off deep dive on a competitor instead of watching profiles over time.
Profile the people behind the accounts you watch.
# Create custom skills (/tutorials/create-custom-skills)
If your team keeps retyping the same research prompt — for a B2B SaaS project-management tool, say, "pull recurring complaints about onboarding and group them by team size" — turn it into a custom skill. You write the instruction once, save it to the Skills library, and from then on apply it to any chat or project with one click. It is the fastest way to standardise how you and your colleagues run a recurring analysis: the same prompt, phrased the same way, every time.
## Prerequisites [#prerequisites]
The Skills library opens from inside the chat input, so you need at least one open chat or project to reach it. If you have not created one yet, see [Set up your project](/tutorials/set-up-your-project).
## Walkthrough [#walkthrough]
### Open skills [#open-skills]
In an open chat or project, click the book icon in the chat input toolbar (labelled `Open skills`) to open the Skills popover.
### Browse all skills [#browse-all-skills]
In the popover, click `Browse all skills` to open the Skills library modal. The popover itself only lists your starred skills for quick access, so this is the way into the full library.
### Create custom skill [#create-custom-skill]
In the modal's left sidebar (titled `Skills`), click `Create custom skill` — the dashed button at the bottom of the sidebar. This switches the active category to `Custom` and opens the create form on the right.
### Name, description, and instructions [#name-description-and-instructions]
Fill in the create form's three fields:
* **`Name`** (required, 1–120 characters; placeholder `Short, descriptive title`) — e.g. `Onboarding feedback by team size`.
* **`Description (optional)`** (up to 400 characters; placeholder `One-line summary`) — a reminder of what the skill does, e.g. `Groups onboarding complaints by company/team size`.
* **`Instructions`** (required, 10–4000 characters, with a live character counter) — the prompt the assistant runs when you apply the skill, e.g. `Analyse onboarding feedback for our B2B SaaS project-management tool. Group recurring complaints by team size and surface the top three themes with example mentions.`
### Create [#create]
Click `Create`. The button shows `Creating…` while it saves. On success a `Skill created` toast appears and the new skill opens in its detail view. Saving is a plain store operation — no AI generation, no credits.
### Use this skill [#use-this-skill]
Your new skill lives under the `Custom` category. From its detail view you can `Edit` or `Delete` it, star it to add it to `Favorites`, or click `Use this skill` to drop its instructions into the open chat or project draft.
## Now apply it [#now-apply-it]
A custom skill is only useful once you run it against collected data. Open a chat or project on a dataset, apply the skill, and the assistant works through your saved instruction — grouping onboarding complaints by team size, surfacing the top themes, and quoting example mentions. The same pattern works for any recurring analysis you save: pain points, feature requests, positive and negative quotes, objections, or share of voice. To apply built-in skills the same way and see the full catalogue, see [Use skills](/tutorials/use-skills).
## Gotchas [#gotchas]
* **"Skill" and "prompt" are the same thing.** The interface says `skill` (sidebar `Skills`, buttons `Create custom skill` and `Use this skill`), but the underlying API path is `/processing/prompts`. Built-in catalog items are prompts; the ones you create are custom skills. Treat skill and prompt as the same object.
* **Creating a skill is free.** Saving is a plain create-and-store operation — there is no AI generation and no credits are consumed. The skill does not run anything on its own; it just stores reusable instructions you apply later.
* **Validation is enforced.** `Name` must be 1–120 characters, `Description (optional)` is capped at 400, and `Instructions` must be 10–4000. The `Create` button stays disabled until the form is valid.
* **You cannot pick a category.** New skills are always filed under `Custom`. The four thematic categories — `Market research`, `Content & positioning`, `Audience research`, and `Charting & visualization` — only hold the built-in catalog.
* **Only custom skills can be edited or deleted.** Built-in catalog skills show a `Customize` button instead, which forks them into a new custom skill — the tooltip reads `Saves as a new custom prompt — the original stays as is`. The copy lands under `Custom` and the original built-in skill is untouched.
* **`Favorites` is a filter, not a folder.** Starring a skill makes it show under `Favorites` and pins it to the chat-input Skills popover for quick access — it does not move the skill out of `Custom`.
* **`Use this skill` needs an open draft.** The button is disabled unless a chat or project draft is active; the tooltip reads `Open a chat or project to apply this skill.`
## Next steps [#next-steps]
Apply built-in and custom skills inside a chat or project.
Add reusable custom analysis parameters to your datasets.
# Export mentions as CSV (/tutorials/export-mentions-csv)
Sometimes the fastest next step isn't another question in chat — it's a spreadsheet. Exporting mentions to CSV lets you pull your collected posts out of buzzabout so you can pivot them yourself, hand a clean dataset to an analyst, or feed the rows into another tool. If you run an e-bike DTC brand, you might filter the Library down to negative Reddit mentions from the last 30 days, select them, and export a single `library-.csv` that carries the author, content, sentiment, engagement, and every enrichment for each post. The file always includes **all columns plus every Smart Parameter** — regardless of which columns you've toggled visible in the table — so nothing you've computed gets left behind.
## Prerequisites [#prerequisites]
* A **dataset with collected mentions** in the app. The Library only shows mentions you've already collected — if you have none yet, run [Brand research](/tutorials/brand-research) first.
* A **Pro, Business, or Enterprise plan**. CSV export is a Pro+ feature; on lower plans the **Export** button stays visible but disabled with an upgrade tooltip.
## Walkthrough [#walkthrough]
Export runs from the **table** view of the Library, not card view. Cards aren't selectable — bulk selection and the **Export** button only appear once you're in the mentions table.
### All mentions [#all-mentions]
Open the Library at `/library` and make sure you're in the **table** view (not cards). **All mentions** is the unfiltered feed spanning every dataset you've collected, laid out as rows you can select. Each row is one collected post.
### Filter into a view [#filter-into-a-view]
Optional, but it keeps the export tight. Use the filter and sort controls to narrow the feed before you select — filter by **sentiment**, **platform**, **dataset**, and **posting date**, then sort the table (for example, newest first). For the e-bike brand you might filter to negative sentiment on Reddit over the last 30 days, so the CSV only carries the mentions you actually want to analyse. If it's a feed you'll export again, save it as a View first — see [Create a mention view](/tutorials/create-a-mention-collection).
### Select rows [#select-rows]
Select the rows you want to export. Tick individual rows, or use the **selection scope menu** to grab the **first N** at once instead of clicking each one. As you select, a selection bar appears with a running count — for example `120 selected` or `First 100 selected`. Use **Clear selection** to start over.
### Export [#export]
Click **Export** in the selection bar. The button shows **Exporting…** while it works, then your browser downloads a file named `library-.csv` (for example `library-2026-06-08.csv`) and a toast confirms the result — `Exported 120 mentions to CSV`.
The CSV includes **all columns plus every Smart Parameter** for the selected rows. That covers the author, content, and platform; sentiment and sentiment score; engagement metrics like views, likes, comments, and shares; the posting date and source dataset; the per-post enrichment fields (top emotion, category, content intention, tone of voice, narrative structure, hook, CTA, content topics, questions, mentioned brands, entities, tags, classifications, and — when enabled — transcription and visual description); plus one column for each Smart Parameter you've defined.
## Hand it off [#hand-it-off]
Once the file lands, the rows are yours to work with outside buzzabout:
* **Hand it to an analyst.** A self-contained CSV with sentiment, engagement, and enrichment columns is something a teammate can open in any spreadsheet without a buzzabout login.
* **Pivot it in a spreadsheet.** Group by platform, sentiment, or any Smart Parameter to count and slice the way you need.
* **Feed it into another tool.** Import the CSV into a BI tool, a notebook, or wherever your other data already lives.
## Gotchas [#gotchas]
* **Export needs Pro+.** On plans without it the Export button is disabled with a `CSV export isn't available on your plan. Upgrade to export.` tooltip.
* **The CSV ignores column visibility.** It always contains all columns and every Smart Parameter for the selected rows. Column visibility is only a viewing preference — you don't need to enable a column to export it, and hiding one doesn't drop it from the file.
* **Selection and Export live in the table, not card view.** Library cards aren't selectable; switch to the table to bring up the selection bar and the Export button.
* **A row is a post.** Each exported row is one public post. Comments aren't exported as their own rows — they're pulled in per-post as context only.
* **This is not asset export.** CSV export pulls raw mention rows out of the Library. Exporting an AI-built report, chart, or dashboard as PNG/PDF — or sharing it via a public link — is a separate flow. See [Share & export assets](/tutorials/share-and-export-assets).
* **Filters shape the feed, selection shapes the file.** Filtering narrows what's visible; the CSV contains exactly the rows you selected, so filter first, then select.
## Next steps [#next-steps]
Filter and save the views that feed a clean export.
Add AI-filled columns that ride along in every CSV export.
Export and share AI-built reports and charts as images, PDFs, or live embeds.
# Generate a content brief (/tutorials/generate-a-content-brief)
A content brief isn't a button — it's an **asset the assistant generates inside a chat**, and you can produce one in any chat, not just from a project folder. The trick is that the brief is the *culmination* of the analysis you've already done in the same thread. Say you run an e-bike DTC brand: in one chat grounded on your Reddit and TikTok mentions about commuting, range anxiety, and theft, you first surface pain points and feature requests, then get content ideas, then run a content gap analysis of your niche. Ask for the content brief last and it weaves all of that in — an effort-vs-impact plan where every angle traces back to a real finding you already pulled up. The result is a shareable asset you can hand to teammates.
## Prerequisites [#prerequisites]
* A mentions dataset with a completed collection run, so there are real posts to ground the brief on. See [Create a mention view](/tutorials/create-a-mention-collection).
* Enough volume for the synthesis to find repeatable angles — a few dozen mentions surface anecdotes; aim for **\~100+** before you trust the brief.
## Walkthrough [#walkthrough]
The order matters here. Each skill below builds on the last in the **same chat thread**, so by the time you ask for the brief, the assistant already has pain points, requests, ideas, and gaps in front of it.
### Open a chat [#open-a-chat]
Start a chat from the home page, or open any project's chat — either works. The brief is just an asset the assistant emits, so you don't have to begin from a project folder.
### Add context [#add-context]
Ground the chat in a real dataset. Click **Add context** in the composer and tick a mentions dataset — under **In this chat**, **All your mentions datasets**, or **In this project** if you're in a project. For the e-bike brand, pick the dataset holding your commuting and range-anxiety threads.
If you have nothing to attach yet, you'll see **No mentions datasets yet.** or **No mentions datasets in this project.** — collect mentions first, then come back. The brief is only as good as the conversation underneath it.
### Analyse pain points and feature requests [#analyse-pain-points-and-feature-requests]
Apply the **Analyze pain points** skill, then the **Feature requests** skill, in the same thread. Open the skills picker (the book icon, **Open skills**), click **Browse all skills**, find each under **Content & positioning**, and choose **Use this skill**.
Pain points surface the recurring frustrations — range anxiety, theft worry — that make the most magnetic hooks. Feature requests turn product-directed asks into explainer angles. Running these first means the assistant has the raw frustrations and asks already on the table before it ever drafts a brief.
### Get content ideas [#get-content-ideas]
Now apply the **Suggest content ideas** skill in the same chat. Because it's a synthesis layer, it draws on the pain points and requests you've already surfaced — plus outliers, audience questions, and buzzwords — and pulls candidate ideas, each traced to a real finding, scored on effort versus impact.
Add a short steer if you want, for example `Focus on short-form video for commuters`, and send.
### Run a content gap analysis [#run-a-content-gap-analysis]
Apply the **Content gap analysis** skill next. It compares what your niche talks about (supply) against what your audience is asking for in comments (demand) and surfaces a demand-vs-supply quadrant — the gaps where demand outstrips supply are your sharpest, least-crowded angles.
Running this in the same thread means the brief that follows knows which ideas are genuinely under-served, not just popular.
### Ask for the content brief [#ask-for-the-content-brief]
Now ask, in plain language: `Pull all of this into a content brief`. Because everything above lives in the same thread, the assistant incorporates the pain points, feature requests, ideas, and gaps you already surfaced — it doesn't start from scratch.
It composes the brief as an asset: an effort-vs-impact scatter (your quick wins sit high-impact / low-effort), followed by a content-brief table — one row per idea, each carrying a hook, a structure, a format, an emotion, and a CTA, plus a source quote pulled from your mentions. In the thread the asset shows as a compact reference card with an **Open in side panel** action; when streaming finishes, the side panel auto-opens with the full brief.
### Draft the script [#draft-the-script]
At the bottom of each brief row there are follow-up buttons — by default **Draft the script**, **Find similar mentions**, and **Suggest a hook**. Each button's label is the exact message sent back to the assistant to continue from that specific idea, so clicking **Draft the script** on your "range anxiety, debunked" row asks the assistant to draft that script next.
## Share it with your team [#share-it-with-your-team]
The brief is an asset, so you can hand it off. From the side panel, use **Share asset** to get a public **Sharing link** or an **Embed snippet** to drop into Notion or a blog, or download it as PNG or PDF. See [Share & export assets](/tutorials/share-and-export-assets) for the full set of controls — and note that share links are public and unauthenticated.
## Gotchas [#gotchas]
* **It's a use case, not a button.** There is no "Generate content brief" control anywhere. You ground a dataset, run your analysis in the thread, then *ask* — and the model decides to emit the brief asset. A vague prompt with no grounding may not produce one.
* **Order matters.** The brief is the culmination of the chat, not the start of it. If you ask for a brief cold, before surfacing pain points, ideas, and gaps, you get a thinner result — the synthesis only weaves in what's already in the thread.
* **Ground it in a real dataset.** Data-backed briefs need a mentions dataset attached via **Add context**. The picker is datasets-only; wherever product copy says "collection" it means a mentions dataset.
* **The skills trigger underlying passes.** Pain points, content gap, and idea synthesis kick off pattern-detection runs. Those run asynchronously, can take a few minutes, and may charge credits; if the data is too thin the assistant will say so rather than invent angles.
* **The inline card doesn't show the body.** In the thread you only see the reference card; the full brief parses in the side panel. The panel auto-opens only for an asset that finished streaming this turn — reopening an old chat won't auto-open historical briefs, so click the card.
* **Web-only rendering.** Over MCP, `buzzabout__ask` returns markdown only — the rich brief asset, its scatter, and the follow-up buttons exist solely in the web app.
## Next steps [#next-steps]
Surface the recurring frustrations that make the strongest hooks.
Turn product-directed asks into explainer and roadmap angles.
Share the finished brief with teammates or embed it anywhere.
# Niche research (/tutorials/niche-research)
A single, well-tuned niche dataset is the richest thing you can pull in buzzabout. For an e-bike DTC brand, one focused collection of `electric bike commuting` conversation tells you the market's pain points and objections, the tone of voice buyers actually use, where the volume and engagement sit, and how attention is split across social networks — before you spend a cent on ads or product. This page is about what you can *extract* from a niche, not just how to collect it: a short collect step, then the techniques that turn that dataset into market intelligence.
## What you can extract from a niche dataset [#what-you-can-extract-from-a-niche-dataset]
Once a niche dataset is collected, it answers questions a survey never could, because it is real unprompted conversation:
* **Pain points** — the recurring frustrations buyers raise (range anxiety, service friction, theft worries) and how often each comes up.
* **Objections** — the reasons people give for *not* buying, in their own words ("too heavy to carry upstairs", "won't survive a wet commute").
* **Tone of voice** — the actual vocabulary, slang, and register the market uses, so your copy sounds native rather than corporate.
* **Dynamics, volume, and engagement** — how much conversation exists, whether it is growing, and the average engagement rate per post (a proxy for what the market cares about).
* **Market share across networks** — which social networks own the conversation, and which trending topics dominate on each.
The rest of this tutorial collects a tight niche dataset, then shows the extraction techniques on top of it.
## Prerequisites [#prerequisites]
* An account that can run research, with credits available. Research depth options are gated by plan: Starter is single-source (you pick any one of Reddit, X, Instagram, TikTok, YouTube, or LinkedIn), Pro and Business are multi-source up to 1,000 mentions, and Enterprise goes up to 10,000.
* A niche worth tuning a boolean query for. A meaningful read on pain points and market share needs roughly 100+ mentions — for a thin niche, widen the date range or broaden the query rather than reading too much into a handful of posts.
## How to collect a tight niche dataset [#how-to-collect-a-tight-niche-dataset]
The quality of everything you extract depends on the dataset matching your audience. A generic `ebike` search drowns you in mountain bikes, e-scooters, and regulation debates. Tune the boolean query until the conversation is actually your market.
### Search a topic or paste a URL [#search-a-topic-or-paste-a-url]
On the home page you'll see `Discover what people buzz about` with a `Search a topic or paste a URL` box. Type a starting topic for your niche — for the e-bike brand, something like `electric bike commuting`. Or pick a starter prompt from a category tab (`Trends`, `Audience`, `Content ideas`, `Market needs`, `Competitors`, `Briefs`) using `Show suggestions`. Optionally set source, time, language, and country filters in the chip row, then send.
### Keyword query [#keyword-query]
In the chat the assistant returns a research preview card titled `Keyword query`. It shows your topic as editable `AND` / `OR` / `NOT` chips, an estimated mention count, and a volume badge — `Too narrow`, `Sweet spot`, or `Too broad`. For a broad `ebike` query you'll often see `Too broad`, with the note `High volume. It's recommended to narrow the intent to avoid generic results.`
### Tune the chips to Sweet spot [#tune-the-chips-to-sweet-spot]
This is the core of niche research. The operators available in the chip editor are **AND, OR, NOT** plus **parentheses** for grouping and **"double quotes"** for exact phrases. The **default join between two keywords is OR** (broadens reach) — add **AND** to require co-occurrence, **NOT** to exclude. Operators are case-insensitive but render uppercase.
A reliable way to find a niche-specific Sweet spot is to **combine a top brand or category keyword with an intent keyword**:
* **Brand + pain point:** `"electric bike" AND (range OR battery OR theft)` — surfaces the niche's frustrations.
* **Brand + feature:** `"electric bike" AND (torque OR "throttle" OR "pannier")` — surfaces what buyers actually evaluate.
* **Brand + expressive language:** `"electric bike" AND (love OR hate OR "wish it" OR annoying)` — surfaces tone of voice and strong opinions.
* **Competitor set (implicit OR):** `rivian polestar lucid` style — `"rad power" "aventon" "lectric"` returns any post mentioning any of the three.
Narrow with `AND` / `NOT` (`NOT scooter`, `NOT "mountain bike"`), broaden with `OR`-synonyms (`ebike OR "electric bike" OR "e-bike"`). Nested groups are supported. Each edit re-runs the estimate — you'll briefly see `Calculating…` — and the badge updates. Aim for `Sweet spot` (the green badge). Sanity-check complex queries against the live count; if you over-narrow you'll see `Too narrow` or `Insufficient volume` with `Low volume. It's recommended to broaden the search query or widen the date range.`
### Research depth [#research-depth]
Pick how many mentions to collect under `Research depth` (`How many mentions to collect when you run research.`). The options are `Overview` (`100 mentions`), `Landscape screening` (`200 mentions`), `Qualitative research` (`500 mentions`), and `Quantitative analysis` (`1,000 mentions`). The credits line updates as you change depth — collection costs 1 credit per mention, so `500 mentions` is 500 credits. Options above your plan are disabled. For a confident read on pain points and per-network market share, collect at least `Landscape screening` (`200 mentions`).
### Preview mentions, then Start research [#preview-mentions-then-start-research]
Click `Preview mentions` to inspect sample posts for free and sanity-check that the query is on-topic for the niche. Previews and estimates cost nothing. When the sample looks right, click `Start research` to collect the dataset — this sends the message `Collect this dataset.` and spawns the run. This step is what charges credits.
## Now analyse it — extract the market intelligence [#now-analyse-it--extract-the-market-intelligence]
Collection just gives you the raw conversation. The extraction happens in chat: ask the assistant questions against the dataset, or apply a skill (open the book icon in the chat input → `Browse all skills` → open a skill → `Use this skill`). Each skill returns a hero chart, a detail table, and a few takeaways. Here is what to pull from a niche dataset and how:
### Pain points and objections [#pain-points-and-objections]
Ask the assistant to find the recurring themes — it runs pattern detection, showing a `Pattern detection` block that reads `Discovering recurring themes` then `Pattern detection complete`, grouping mentions into named categories with the share of posts in each. For the e-bike niche you might see clusters like range anxiety, commuting-cost savings, and service or repair friction. To go further, ask it to separate genuine *objections* (reasons not to buy) from neutral discussion, and to quote the strongest examples in the buyers' own words.
### Tone of voice [#tone-of-voice]
Ask the assistant to describe how this market talks: the vocabulary, slang, register, and the emotional language buyers reach for. Pulling the actual phrasing — not your internal jargon — is what makes downstream copy sound native to the niche. The expressive-keyword query you tuned earlier (`AND (love OR hate OR "wish it" …)`) makes this read sharper.
### Volume, dynamics, and engagement [#volume-dynamics-and-engagement]
Ask for the volume and engagement profile of the niche: how many mentions, whether the conversation is trending up or down over the date range, and the average engagement rate per post. Engagement is a proxy for what the market actually cares about — high-engagement themes are the ones worth building product and content around.
### Market share across networks [#market-share-across-networks]
Ask the assistant for **share of voice by platform** — the portion of the niche's total mention volume that sits on each network. It renders this as a horizontal bar comparison so you can see, at a glance, whether the conversation lives on Reddit, YouTube, or TikTok. Follow up by asking it to compare the **trending topics per network**: the e-bike commuting conversation on Reddit (long troubleshooting threads) reads very differently from TikTok (range tests, theft footage), and that tells you where each message belongs.
Share of voice isn't a button or a standalone page — you ask the assistant for it in chat, and it builds the comparison from the dataset's mention volume. The "Mentioned brands" skill produces a per-brand share-of-voice bar coloured by sentiment if you want to compare brands inside the niche instead of platforms.
## Keep the niche live with a listening agent [#keep-the-niche-live-with-a-listening-agent]
A one-off niche dataset is a snapshot. Attach a **listening agent** to it and the same query re-runs on a schedule, so new pain points, product launches, and shifts in tone keep landing without you re-collecting by hand. From the sidebar choose `New listening agent`, reuse the boolean query you tuned above, and pick a cadence — it will surface new mentions as they appear and can push them to Slack or a webhook. This turns niche research from a project into a standing radar on your market.
## Gotchas [#gotchas]
* **Breadth is the boolean query, not a toggle.** There is no control labelled `broad` or `specific`. You widen or narrow the niche by editing the boolean query (`AND` / `OR` / `NOT`, nested groups, `"quoted phrases"`) and watching the volume badge. A space between two keywords means `OR`, not `AND` — add `AND` explicitly when you need co-occurrence.
* **Trust the volume badge.** `Insufficient volume` (red) means too few posts for a reliable report; `Too narrow` (red) and `Too broad` (orange) bracket the usable range; `Sweet spot` (green) is the target. As a rough fallback, under 300 reads as `Too narrow` and over 30,000 as `Too broad`. For dependable pain-point and market-share reads, aim for \~100+ collected mentions.
* **Preview is free; collection costs credits.** `Preview mentions` and the live estimates cost nothing. `Start research` collects at 1 credit per mention, so depth `100` / `200` / `500` / `1,000` costs that many credits.
* **Depth and multi-source are plan-gated.** Over-plan depths are disabled with an upgrade prompt. Starter is single-source, so cross-network market-share comparison needs Pro or above.
* **Share of voice is conversational, not a feature.** There is no dedicated Share of Voice page, button, or chart type. You ask the assistant, which builds a per-platform or per-brand mention-volume comparison. Don't expect a standing roster card.
* **Pattern detection is conversational and asynchronous.** There is no `Detect patterns` button — you ask the assistant, which calls its pattern-detection tool, polls for a result, and reuses an existing pattern on a dataset rather than re-running it. The named categories and their per-cluster share are real; framing one as a "content gap" is your editorial reading, not a built-in metric.
## Next steps [#next-steps]
Go deeper on the pattern taxonomy and how categories and shares are derived.
Track how the niche's themes and volume move over time.
Turn the niche pain points and tone of voice you surfaced into a structured content brief.
Keep the niche live so new pain points and launches keep arriving.
# Run audience analysis (/tutorials/run-audience-analysis)
A collected dataset tells you *what* people are saying about your e-bike DTC brand. Audience analysis tells you *who* they are. From the same posts, buzzabout walks the authors and commenters and profiles them — location and language, content niche, interests, brand affinities, creator tier, a marketing-focused summary, and an inferred "Personality (OCEAN)" fingerprint. Instead of guessing your buyer, you get a profile of the real people in the conversation, with directional guidance for who to target and how to message them.
## Prerequisites [#prerequisites]
* A dataset with a completed collection run, so there are authors and commenters to profile. Audience analysis is built *from* a collected dataset — you can't profile an audience from scratch. See [Set up your project](/tutorials/set-up-your-project) and [Create a mention view](/tutorials/create-a-mention-collection).
* A **Pro** plan or higher. Audience analysis unlocks at Pro+.
* Credits to spend. Each profile costs **3 credits**, and you choose how many profiles to collect — so budget for the run before you start.
## Walkthrough [#walkthrough]
### Open a chat against your dataset [#open-a-chat-against-your-dataset]
Open a chat scoped to the dataset that holds your e-bike mentions — from `/chat` or from your project's chat. There is no top-nav "Audience" tab: audience analysis lives inside a chat conversation and opens as a canvas overlay, so start from the same place you ask any other research question.
### Ask the assistant to profile the audience [#ask-the-assistant-to-profile-the-audience]
Type a plain-language request, such as `Profile the audience for this dataset` or `Who are the people talking about our e-bikes?`. There is no "Audience" button — you describe what you want and the assistant prepares an audience run over the dataset's authors and commenters.
### Audience analysis [#audience-analysis]
The assistant renders an **Audience analysis** card in the chat thread. It shows the read-only **Source dataset** it'll profile and an **Audience size** picker — four preset buttons: `100`, `250`, `500`, and `1000` profiles. Each button shows its credit cost at **3 credits** per profile, so `250 profiles` reads `750 credits`. The default selection is **250** (your last choice is remembered for next time); higher options can be locked on lower plans, with a `Upgrade your plan to analyse this audience size.` tooltip.
### Collect Audience [#collect-audience]
Pick the size you want and click **Collect Audience**. The total credit cost shows next to the button before you commit. The assistant then kicks off the run at the count you chose — there's no separate confirmation step.
### Audience research in progress [#audience-research-in-progress]
The card switches to **Audience research in progress** and works through the pipeline steps. This is asynchronous and can take several minutes — it reads the dataset's deduped posts, walks the authors and commenters, and profiles each one until it reaches your target count. The card updates to **Audience research complete** when it finishes (or **Audience research failed** if something went wrong). Use **Show settings** on the card to see the run's configuration.
### View profiles [#view-profiles]
When the run completes, the card shows a **View profiles** button labelled with the actual profile count — for example `View 248 profiles`. Click it to open the **audience canvas** — a right-panel overlay with a sortable, filterable table of every profiled person.
### Sort and filter the audience canvas [#sort-and-filter-the-audience-canvas]
The canvas table lists each profile with their computed fields — follower count, engagement rate, and creator tier (`civilian`, `nano`, `micro`, `mid`, `macro`, `mega`). Sort by score, follower count, engagement rate, or authenticity, and filter to narrow the audience: by source platform, verified status, location country, creator tier, content niche, or interest clusters. This is how you isolate, say, the `micro` creators in your e-bike niche from the `civilian` commenters.
### Open a profile for the detail modal [#open-a-profile-for-the-detail-modal]
Click any row to open the profile detail modal. Alongside the person's identity and metrics, you'll see the LLM-derived layer: **Content niche**, **Interests**, **Brand affinities**, a marketing-focused summary covering lifestyle, purchasing habits, and brand affinity, plus per-platform chips (for example **Top subreddits** on Reddit, **Tagged locations** and **Collaborations** on Instagram, or **Skills** and **Education** on LinkedIn). These are the fields you use to target: who else they follow, what they care about, and where they fit.
### Read the Personality (OCEAN) bars [#read-the-personality-ocean-bars]
Many profiles include a **Personality (OCEAN)** section: five bars for the Big Five personality traits — **Openness**, **Conscientiousness**, **Extraversion**, **Agreeableness**, and **Neuroticism**. Buzzabout *infers* these from each person's public posts and profile via an LLM, then shows them as percentages. Use them as a directional creative signal: a high-**Openness** segment tends to respond to novel, experimental angles, while a high-**Conscientiousness** segment leans toward proof, reliability, and spec-led framing — useful when you're deciding how to pitch your e-bike's range, build quality, or design.
### Grow the audience later [#grow-the-audience-later]
To add more people to an existing audience, use **Collect more profiles**. It's a free-numeric input — pick any count from `50` to `5,000` (it defaults to `100`), still at **3 credits** per profile — and the new profiles are appended to the same audience. Use this when an early `100`- or `250`-profile pass looks promising and you want a deeper read of the same conversation.
Now you have a built audience dataset. **Now analyse it → [skills](/tutorials/use-skills).** To roll individual profiles up into something you can present, apply an audience skill in chat: **Audience demographic chart** summarises the demographic spread, and **Audience psychographic chart** plots the OCEAN traits across the audience. Both run over the audience dataset you just built.
## What OCEAN is — and what it isn't [#what-ocean-is--and-what-it-isnt]
OCEAN (the "Big Five") is a common framework for describing personality across five dimensions: Openness (curiosity, openness to new experiences), Conscientiousness (organisation, reliability), Extraversion (sociability, energy), Agreeableness (warmth, cooperation), and Neuroticism (emotional sensitivity, stress reactivity). In buzzabout these scores are **inferred by an LLM from a person's public posts** — a directional AI estimate, not a validated psychometric test. Treat them as a hint about messaging tone, not a clinical assessment, and pair them with the harder targeting signals on each profile: interests, brand affinities, and creator tier.
## Gotchas [#gotchas]
* **You choose the audience size — the default is 250.** The **Audience analysis** card offers preset sizes `100` / `250` / `500` / `1000`, pre-selected at `250`. There is no hidden "850 by default" in the app — `850` is only an internal fallback the assistant uses if you trigger a run purely conversationally without naming a count.
* **OCEAN is an AI estimate, not a psychometric test.** The five traits are inferred by an LLM from public posts. They're a directional signal for creative and messaging, not a measured personality score — don't treat them as ground truth.
* **OCEAN may be absent for low-signal profiles.** When a person hasn't posted enough for a confident read, the model returns no scores and the entire **Personality (OCEAN)** section is hidden for that profile. Expect plenty of profiles with no OCEAN bars.
* **The bars read as percentages.** In the profile modal each OCEAN trait is shown as a percentage — they are not scored "out of 5".
* **You need a collected dataset first.** Audience analysis profiles the authors and commenters of an existing dataset. Run a collection before you ask the assistant to profile the audience.
* **It's a Pro+ feature and it costs credits.** Each profile is 3 credits, so a `250`-profile pass is 750 credits. Higher presets can be locked on lower plans. Confirm your plan and credit balance before kicking off a run.
* **There's no standalone audience page.** Audience analysis is triggered in chat and opens as a canvas overlay — there is no top-nav "Audience" route to navigate to.
## Doing this over MCP [#doing-this-over-mcp]
If you're driving buzzabout from Claude or another MCP client, the same flow is available as tools: `buzzabout__create_audience_dataset` to create the audience container, `buzzabout__create_audience_dataset_run` to run it against your source dataset, poll `buzzabout__get_audience_dataset_run` until it completes, then `buzzabout__list_audience_profiles` to read the profiles. Over MCP you pass `total_profile_count` explicitly (`1`–`2000`); when you omit it the agent falls back to its internal default rather than the app's `250` card. See [Connect MCP to Claude](/tutorials/connect-mcp-to-claude) and the [audience profiles endpoints](/api/endpoints/audience-profiles).
## Next steps [#next-steps]
Collect the brand mentions you'll profile an audience from.
Profile a competitor's audience to see who you're up against.
Apply the audience demographic and psychographic chart skills.
# Run your first research (/tutorials/run-your-first-research)
The fastest way to see what buzzabout does is to run one research from the home screen. You type a topic, the app previews how much conversation is out there, you pick how deep to go, and a few moments later you have a set of real public posts you can read, question, and analyse. We'll use a cold-brew coffee brand as the running example — by the end you'll have collected its mentions and asked the assistant a question about them.
## Walkthrough [#walkthrough]
### Search a topic or paste a URL [#search-a-topic-or-paste-a-url]
On the home screen, find the composer under the `Discover what people buzz about` heading. The placeholder reads `Search a topic or paste a URL`. Type a topic — for our example, `cold brew coffee` — and press Enter or click `Send message` (the arrow button).
A new chat opens and your message sends to the assistant. If you'd rather start from a prompt, click a suggested-question chip under a category such as `Trends` or `Competitors`.
### Keyword query [#keyword-query]
The assistant returns a research preview card titled `Keyword query`, showing an estimated mention count and a volume badge. This is your free read on whether there's enough conversation to research — no credits are spent yet.
You can refine the query right here. Edit the keyword chips to broaden or narrow reach, and change the source, time, language, or country chips — each edit re-generates the estimate. The default time filter is `Last year`.
**Refining with boolean keywords.** Keyword chips support **AND, OR, NOT** plus parentheses for grouping and `"double quotes"` for exact phrases. The default join between two keywords is **OR** (broadens reach) — add **AND** to require co-occurrence, **NOT** to exclude. Operators are case-insensitive and shown uppercase. For example, `"cold brew" NOT decaf`, or `coffee AND (refreshing OR smooth)`. Sanity-check complex queries against the live mention estimate as you edit.
### Research depth [#research-depth]
Pick a `Research depth` — this sets how many mentions to collect when you run research. The options are `Overview` (100 mentions), `Landscape screening` (200 mentions), `Qualitative research` (500 mentions), and `Quantitative analysis` (1,000 mentions). The helper text reads `How many mentions to collect when you run research.`
The credit cost updates live as you change depth, since 1 mention = 1 credit. Depth options above your plan cap are disabled. For a first run, `Overview` is plenty to see the value.
### Start research [#start-research]
When the preview looks right, click `Start research`. This spends the credits for your chosen depth and starts collecting. The preview hides and a dataset card takes over the turn while the run completes.
If you want to look before you commit, `Preview mentions` opens a free sample of results in the canvas first — it doesn't spend credits or create a dataset.
### Show dataset [#show-dataset]
When the run finishes, click `Show dataset` to open the full table and read what people are actually saying. Each row is one real public post about cold brew — the comments on a post are pulled in as context (about 10 per post) rather than listed as their own rows.
Every post is also enriched with a column of structured fields you can sort and filter on — things like `Sentiment` (a positive / negative / neutral label, paired with a `Sentiment score` from −1 to +1), `Top emotion`, `Content intention`, `Tone of voice`, `Narrative structure`, `Hook`, `CTA`, `Content topics`, `Entities`, and `Mentioned brands`. A couple of fields — `Transcription` and `Visual description` — are opt-in, so they only fill in when you enable them on the run.
### Ask a follow-up or apply a skill [#ask-a-follow-up-or-apply-a-skill]
You now have data to work with. Ask the assistant a follow-up question in the chat — for example, *"What do people love and complain about with cold brew?"* — and it answers against your dataset with cited mentions.
For structured analysis, open the skills menu from the chat input (the book icon), choose `Browse all skills`, open a skill, and click `Use this skill`. Skills are the analysis engine: they turn your mentions into pain points, feature requests, audience profiles, share of voice, trends, and more.
## Gotchas [#gotchas]
* **`Preview mentions` is free; `Start research` spends credits.** Only `Start research` collects the dataset. Credits are 1 per mention, so your chosen depth (100 / 200 / 500 / 1,000) is your credit cost.
* **Plan shapes breadth and depth.** Starter collects from a single source — your choice of any one of Reddit, X, Instagram, TikTok, YouTube, or LinkedIn — and its depth caps at 300 mentions, so only `Overview` and `Landscape screening` are selectable. Pro and Business unlock multi-source research and up to 1,000 mentions; Enterprise goes up to 10,000. On a single-source plan you'll see a `Multi-source research is available on Pro & Business` nudge.
* **Editing any preview field regenerates the estimate.** Changing a keyword chip, source, time, language, or country re-runs the estimate; the buttons lock briefly while it recalculates or while a message is streaming.
* **Pasting a URL is a different mode.** A typed topic gives a `Keyword query` preview with a mention estimate. A pasted profile URL gives a `URL query` preview that counts `profiles found` instead, has no depth picker, and locks its source to whatever the URL implies.
* **Meaningful analysis wants volume.** A handful of mentions won't reveal much. Aim for \~100+ so the patterns, sentiment, and themes are real signal rather than noise.
## Next steps [#next-steps]
Organise your research, chats, and datasets under a project.
Save a filtered, sorted view of your mentions in the Library.
Apply skills to turn collected mentions into structured analysis.
# Set up a listening agent (/tutorials/set-up-a-listening-agent)
A collection is a snapshot — it captures what people were saying at the moment you ran it. A listening agent keeps that research **alive and growing**: on the schedule you set, it re-runs the queries behind one or more datasets, scrapes new mentions, adds them to those datasets, and posts a digest of what changed. If you run a cold-brew coffee brand, point an agent at your brand and competitor datasets, give it sharp **Instructions** — "summarise complaints and feature requests about our cold brew, flag new pain points and competitor comparisons" — and every morning it surfaces what actually matters instead of a generic activity log. One agent can watch several datasets at once, and it can deliver that digest to Slack, your own webhook, or email as well as its own chat.
## Prerequisites [#prerequisites]
* **At least one collected dataset to monitor.** An agent re-runs the queries that already exist on a dataset, so the dataset needs to have been searched at least once. If you don't have one yet, [create a mention view](/tutorials/create-a-mention-collection) first so the agent has data — and queries — to re-run.
The UI calls these **Listening agents**. The API and MCP tools call the same feature **tracking agents** (`tracking_agents`, `buzzabout__create_tracking_agent`). They are the same thing.
## Walkthrough [#walkthrough]
### Listening agents [#listening-agents]
Open the **Listening agents** page from the left sidebar (`/agents`), or open a project and switch to its **Listening agents** tab. The page is described as: *Watch your data on a schedule. Each agent posts a digest into its own chat.* If you have none yet, you'll see **No agents yet.** (or **No listening agents yet** on the project tab).
### New agent [#new-agent]
In the side panel header, click the **New agent** button (an icon-only `+` button, labelled `New agent` for screen readers). You can also click the visible **New agent** button in the empty-state hint, or **Add agent** on a project tab. Any of these opens the **New listening agent** modal, whose first step is titled *Configure what this agent tracks and when it runs.*
### Project [#project]
Optionally pick a **Project**. Leaving it as **No project** makes the agent account-wide; binding it to a project filters it into that project's **Listening agents** tab. For our cold-brew brand, you might bind it to the `Cold Brew` project so it sits alongside that project's other work.
### Name [#name]
Enter a **Name** — the placeholder is `e.g. Daily AI mentions`. For our example, something like `Daily cold-brew mentions` works. The name is just a label; the next field is where the agent earns its keep.
### Instructions [#instructions]
**Instructions** is the most important field. It answers *What should this agent summarise from the scraped posts?* — and it decides whether each run is a useful read or generic noise. Give it focus: tell it what to surface and what to flag.
Vague instructions ("summarise new mentions") produce a vague digest. Sharp instructions point the agent at the value you care about. For our cold-brew brand:
> Summarise new mentions of our cold-brew brand. Flag complaints and feature requests, call out any new pain points or recurring topics, and note competitor comparisons. Skip generic positive chatter.
Patterns that work well: *"summarise complaints and feature requests about X"*, *"flag new pain points, trends, or topics that weren't there last run"*, *"surface negative quotes and the platforms they came from."* The tighter the instruction, the more each run reads like a briefing rather than a feed.
### Datasets [#datasets]
Select one or more **Datasets** to monitor. This is a multi-select and at least one dataset is required — if you skip it you'll see *Pick at least one dataset*. Pointing one agent at several datasets keeps them all growing together: for the cold-brew brand you might add your brand dataset, a competitor dataset, and a category dataset to a single agent. If the list is empty you'll see *No datasets in this project yet* or *No datasets in your account yet*, which means you need to run a collection first.
### Mentions per run [#mentions-per-run]
Choose **Mentions per run** — the options are 10, 25, 50, 100, 150, and 200, defaulting to 50. This sets how many new mentions each run scrapes and adds to the datasets. A larger count means more data added per run, and more cost per run.
### Schedule [#schedule]
Pick a **Schedule**: **Daily** or **Weekly**. Weekly adds a day picker. Then choose a time — note it is in `(UTC)`, so convert from your local time. The agent's footer later renders this as, for example, `Daily at 9:00 AM`.
### Next [#next]
Click **Next** to advance to the destinations step. (You can also use **Back** to return, or **Cancel** to discard.) The destinations step is optional — the next part of this tutorial covers it.
## Deliver alerts [#deliver-alerts]
The destinations step is labelled **Optional**: *Pick integrations to deliver summaries to. Optional — you can skip this and add them later.* With nothing attached the agent still works — as the helper text says, *The agent runs and posts summaries in the chat without any. Add integrations to also deliver them via Slack, email, or webhook.*
Add a destination when you want the digest to reach you where you already work. The same panel appears under **Settings → Integrations** if you prefer to set integrations up first, but attaching them here in the destinations step is the usual path.
### Slack [#slack]
Deliver each new-mention alert into a channel like `#brand-mentions`, with the author, a link, and a snippet of the post.
### Connect Slack Workspace [#connect-slack-workspace]
In the **Slack notifications** card (subtitle *Connect Slack channels for your alerts*), click **Connect Slack Workspace**. This redirects you to Slack's OAuth screen to authorize the app. After install, the card shows a green **Connected** badge.
Only the account owner can do this. If you aren't the owner, ask them to connect the workspace once for the whole account.
### Add Channel [#add-channel]
With the workspace connected, click **Add Channel** to open the **Add Slack Channel** dialog (*Post notifications to a Slack channel*). In the **Slack Channel** dropdown (**Select channel**), pick the channel you want alerts in — for example `#brand-mentions`. The list is pulled live from the connected workspace; channels already wired to an integration are filtered out, and if every channel is taken you'll see **All channels are already integrated**.
Optionally click **Test** to send a test alert (you'll get a **Test notification sent** confirmation), then click **Add Integration**. When you add it from the destinations step, the new integration is automatically selected for the agent.
### Webhook [#webhook]
Turn each scheduled run into an HTTP POST your own systems can act on — route fresh pain points to a roadmap board, fire an internal alert, or append rows to a database. Webhook integrations are available on **Pro and Business** plans.
### Add Webhook [#add-webhook]
In the **Webhooks** card (*Send HTTP POST requests to custom endpoints*), click **Add Webhook**. If your plan doesn't include webhook access, this button reads **Upgrade plan** instead, with the note `Webhook integrations are available on Pro and Business plans.` In the **Add Webhook Integration** modal, fill in two fields:
* **Integration Name** — a label for your own reference, for example `Project-mentions to Zapier`.
* **Webhook URL** — the endpoint that receives the POST, for example `https://example.com/webhook`. It must be a valid `http` or `https` URL; otherwise you'll see `Please enter a valid webhook URL`.
Optionally click **Test** to fire a test POST (toast `Webhook test successful!`), then click **Add Integration**. The webhook is account-scoped, so you can reuse it across multiple agents — select it on the destinations step to attach it.
### The run payload [#the-run-payload]
On each completed run the agent sends an HTTP POST with headers `Content-Type: application/json` and `User-Agent: buzzabout/webhook-integration`. The body is a `tracking_agent.run_completed` event — a condensed view:
```json
{
"event": "tracking_agent.run_completed",
"agent": { "id": "...", "name": "Daily cold-brew mentions" },
"run": { "id": "...", "new_mentions_count": 42, "new_comments_count": 11 },
"short_description": "...",
"cta_url": "...",
"mentions_preview": [
{
"source": "reddit",
"url": "https://reddit.com/...",
"title": "...",
"text": "...",
"created_at": "2026-06-08T12:00:00Z"
}
]
}
```
Every row in `mentions_preview` has a non-empty `url`, and `created_at` timestamps are ISO 8601 UTC. The **Test** button does not send this shape — it POSTs a minimal `{ "type": "test", "message": "Hello from buzzabout" }` body — so write your handler against the real `tracking_agent.run_completed` event.
### Email [#email]
Email is also a destination — select it on the same step to receive the run digest in your inbox. Like Slack and webhook, it's an optional add-on to the chat the agent always posts in.
### Create agent [#create-agent]
Click **Create agent** to save (the button reads **Save changes** when editing an existing agent), and your selected destinations are persisted with the agent. You land back on the **Listening agents** page with the new agent in the side panel. From then on, each run delivers its digest to every destination you attached — and still posts in the chat.
### Agent actions [#agent-actions]
Open the row dropdown labelled **Agent actions** to manage the agent: **Trigger run**, **Pause** or **Resume**, **Edit agent**, assign it to a project, or **Delete**. A manual **Trigger run** shows a toast — **Agent triggered** — and polls the agent's chat for about 30 seconds so the digest appears without a refresh. Use **Trigger run** to confirm the agent works (and that your destinations fire) before waiting for its first scheduled run.
### Read run digests [#read-run-digests]
The **Listening agents** page carries an account-wide summary: a strip of KPI tiles for **Mentions**, **Comments**, **Engagements**, and **Words analysed** (aggregated across all your agents), and a feed of recent assistant replies. Until any agent has posted its first digest, that feed shows *No assistant replies yet — agents will post a digest here after their next run.*
To read a specific agent's run digests as a conversation, click its row to open the agent's dedicated chat (`/chat/`). Each scheduled or manual run posts its summary there, so you can scroll the run history like any other chat.
## Now analyse the data it collects [#now-analyse-the-data-it-collects]
The digest is a quick readout, but the real payoff is that every run feeds new mentions back into the datasets the agent monitors — so the same analysis you run on a one-off collection stays current automatically. Once an agent has been running for a while, open the underlying datasets and dig in:
* **Run analysis skills on the fresh data.** Apply skills to surface pain points, feature requests, objections, positive and negative quotes, and share of voice over the mentions your agent keeps pulling in. See [use skills](/tutorials/use-skills).
* **Save a live Library view.** Filter the growing mentions by sentiment, platform, dataset, or posting date and save it as a personal view — it keeps showing the latest mentions as the agent adds them. See [use insights](/tutorials/use-insights).
* **Keep audience and competitor work current.** Because the datasets keep growing, an agent is the easiest way to keep [audience analysis](/tutorials/run-audience-analysis) and [competitor research](/tutorials/competitor-research) from going stale.
## Gotchas [#gotchas]
* **Instructions decide the quality of every run.** A vague instruction yields a generic digest; a focused one ("summarise complaints and feature requests, flag new pain points") makes each run a briefing. Spend your effort here.
* **Agents monitor datasets, not keywords.** An agent re-runs the queries on one or more collected datasets, and at least one is required. If you have none, collect mentions first so a dataset exists to monitor.
* **No prior search queries means the trigger fails.** Triggering an agent whose datasets have never been searched returns the toast: *This agent's datasets have no search queries yet — run a research preview first*. Run a collection on the dataset before relying on the agent.
* **Every run re-scrapes and consumes credits.** Each scheduled or manual run re-runs the agent's datasets' queries and adds new mentions, which consumes credits, scaling with **Mentions per run** — a 200-mention run costs more than a 50-mention one. There is no per-run credit figure shown in the agent UI; the cost comes from the underlying scrape.
* **Schedule is Daily or Weekly only, in UTC.** Times are fixed hours in UTC, so convert from your local time. Weekly adds a day picker.
* **Destinations are optional, and add on top of the chat.** With no integrations the agent still posts summaries into its own chat; Slack, webhook, and email only add extra delivery.
* **Slack is a two-step, owner-only connect.** First the account owner connects the workspace via OAuth, then anyone picks a channel. There's one Slack workspace per account, each channel can be integrated once, and Slack is **not** plan-gated here.
* **Slack delivers per-mention alerts, not the narrative digest.** Each Slack message is an alert for a new matching mention — author, link, and a truncated snippet — not the rolled-up summary you read in the chat.
* **Webhooks are Pro/Business only, and the Test body isn't the real one.** The card shows **Upgrade plan** without access. The Test POST sends a minimal `{ "type": "test" … }` body, so build your handler for the full `tracking_agent.run_completed` payload, and make sure your endpoint returns 2xx within the 5-second default timeout.
* **Delete is permanent.** Deleting an agent *permanently deletes the agent and its monitored data.*
## Next steps [#next-steps]
Build a dataset around specific accounts, then attach an agent to keep it growing.
Turn the mentions your agent keeps collecting into emerging trends.
Drive your agents and datasets from Claude over MCP.
# Set up your project (/tutorials/set-up-your-project)
A project is the context layer for a brand or topic: it holds your brand details plus the datasets, insights, and assets you collect, and reuses that context across every chat inside it. Set it up once for your cold-brew coffee brand and every analysis, content brief, and listening agent already knows your category, positioning, and tone — and can pull from the same dataset you collected earlier — so AI answers come back sharper and you never re-explain your brand or re-collect the same data again.
## Walkthrough [#walkthrough]
### New project [#new-project]
In the left sidebar, open the `Projects` section and click the `+` button (or the `New project` row) to open the `Create project` modal. The modal notes that `Projects help you organize chats, datasets, and listening agents around a topic or brand.`
### Create project [#create-project]
Enter a `Project name` — the placeholder suggests `e.g. Q2 Competitor Analysis`, but for our example use something like `Cold Brew Brand`. Click `Create` (or `Cancel` to back out). You're routed to the new project page at `/project/[projectId]`.
### Set up brand context [#set-up-brand-context]
On the project page, the right-hand settings card has a `Brand context` section. With nothing set yet, it reads `Add context to tailor responses`. Click the `+` button to open the `Set up brand context` modal. As the modal explains: `Add your brand details to tailor AI responses across all project chats.` This is the context layer at work — the details you add here are fed into every chat in the project, so the AI answers in your brand's terms instead of guessing.
### Auto-fill [#auto-fill]
Optionally paste your `Website URL` (placeholder `https://yourbrand.com`) and click `Auto-fill`. As the modal says, `Paste your website URL and we'll extract brand details automatically.` The button shows `Analyzing…` while it runs AI extraction over the site, then fills in `Brand name`, `Category`, `Description`, `USP`, and `Tone of voice`. Note that auto-fill overwrites whatever is already in those fields, and a URL with no scheme is normalized to `https://`.
### Save [#save]
Review and edit the fields. For the cold-brew brand that might be `Brand name`: your brand; `Category` (placeholder `e.g. DTC sleep tech, B2B analytics SaaS`): `DTC cold-brew coffee`; `Description` (`What the business does and offers, in plain terms.`); `USP` (`What makes this brand different from the alternatives?`); and `Tone of voice` (`Formal, friendly, authoritative, playful…`). Optionally expand `Additional instructions` for `Project-specific instructions that apply to every chat in this project.` Click `Save`; you'll see a `Brand context saved` toast.
### Edit brand context [#edit-brand-context]
Later, use the 3-dot menu on the `Brand context` row to `Edit` or `Remove`. Choosing `Remove` confirms with `Remove brand context?` and the note `This removes the brand context from this project. You can always add it back later.` Removing only clears the context — it does not delete the project.
### Add to project [#add-to-project]
Brand context is one half of the context layer; your collected data is the other. Collect a dataset once — say a scrape of cold-brew conversations on Reddit and TikTok — and you can reuse it as grounding in every chat in this project instead of re-collecting it.
A dataset is only linked to a project by an explicit action. Open the dataset's kebab (3-dot) menu and choose `Add to project`, then pick this project. You'll see an `Added to ` toast, and the dataset now appears in the project's right-panel `Datasets` section (subtitle `Linked datasets from project chats`).
Running a research inside a project chat does
**not**
auto-link its dataset. You must choose
`Add to project`
explicitly for the dataset to be reusable in other chats.
### Add context [#add-context]
Now start a `New project` chat from the project dashboard and click the `Add context` (`+`) button below the input. The popover shows an `In this project` section listing the datasets you linked. Select your cold-brew dataset to ground the new chat in it, then send your first message — the chat now answers from that data plus the brand context, with no re-collection needed.
### Analyze project data [#analyze-project-data]
Keep working. Use the `Analyze project data` chat input to ask questions, and switch between the `Chats` and `Listening agents` tabs on the project. Every chat here inherits the brand context you set, and any linked dataset is one click away under `Add context` — so the project's full context layer (brand details, datasets, saved insights, and assets) is applied across every chat.
## Gotchas [#gotchas]
* **Dataset linking is manual.** A research run inside a project chat does not add its dataset to the project. Use the dataset kebab menu's `Add to project` to link it; only then does it show up under `In this project` in other chats.
* **`Add context` (`+`) appears only inside a project.** The `In this project` dataset list shows up in project chats, not in standalone (non-project) chats. It lists mentions datasets; audience datasets can be linked but don't appear in this picker.
* **There is no separate "Workspace".** buzzabout's hierarchy is your account → projects → (chats, datasets, listening agents). "Workspace" only ever refers to a connected **Slack** workspace under integrations — there's no project-vs-workspace distinction to manage here.
* **Brand context is per-project, not global.** It tailors AI responses across all chats in that one project. A second project starts with no brand context until you set it again.
* **`Auto-fill` overwrites fields.** It runs AI extraction over the website URL and replaces the form values, so run it before hand-editing. A URL with no scheme is saved as `https://`.
* **Save is diff-based.** Only changed fields are sent, and clearing a field sends an empty value. `Save` stays disabled when nothing has changed, or when `Description` exceeds its 500-character limit.
* **Field limits are enforced in the UI:** brand name 100, category 60, description 500, USP 200, tone of voice 200, and additional instructions 1000 characters.
* **Plan limits can block creation.** If you're over your project limit, a plan-limit modal opens instead of the `Create project` modal.
* **The onboarding questionnaire is not project setup.** The first-run questionnaire is a short pre-app intent capture that ends at the upgrade page; it never creates a project or sets brand context.
* The API/MCP names for these actions differ from the UI: project creation maps to `useCreateProject`, brand context to `useUpdateProjectContext` / `useExtendProjectContext`, and dataset linking to `linkDataset` internally. None of these are exposed on the public API or MCP surface — this is a UI-only flow.
## Next steps [#next-steps]
Collect posts into a dataset you can link to this project.
Turn the data in your project into answers and takeaways.
# Share & export assets (/tutorials/share-and-export-assets)
When you ask the AI assistant for a chart, a report, or a dashboard about your B2B SaaS project-management tool, it doesn't just answer in text — it renders a rich deliverable and opens it in the side-panel canvas. That deliverable is an **asset**, and it's meant to leave the app. You can download it as a PNG or PDF to drop into a deck, or share it as a public link — or a live embed — that anyone can open without logging in. The embed keeps refreshing against your data, so a chart pasted into a Notion page or a blog post stays current. This tutorial covers downloading an asset and sharing it as a link or embed.
## Prerequisites [#prerequisites]
* A **rich asset** — a chart, report, or dashboard the assistant has rendered and opened in the side-panel canvas. If you only have a plain-text answer, ask the assistant to turn it into a chart or report first. To produce one from scratch, start with [Run your first research](/tutorials/run-your-first-research), then ask the assistant to visualise the result.
## Walkthrough [#walkthrough]
### Open the asset in the canvas [#open-the-asset-in-the-canvas]
In a chat, ask the assistant for something visual — for example, *"Chart the sentiment breakdown of project-management complaints over the last 90 days."* When it finishes, the assistant renders the result as an asset and opens it in the side-panel canvas on the right. The download and share controls live in the canvas header.
You can also reach the same controls without opening the canvas: every rendered asset appears as a card in the chat right panel (and on the project page if you've saved it), and the card's kebab (More) menu carries the same actions.
### Download as PNG [#download-as-png]
In the canvas header, click the `Download as PNG` icon button. The app renders the asset and your browser downloads an image file named after the asset. A toast reading `PNG downloaded` confirms it; if rendering fails you'll see `Couldn't download PNG`.
From an asset card instead, open the kebab menu and choose `Export PNG` (the item reads `Exporting…` while it works). It produces the same file.
### Download as PDF [#download-as-pdf]
Next to it, click the `Download as PDF` icon button to get the same asset as a PDF document. A toast reading `PDF downloaded` confirms it; on failure you'll see `Couldn't download PDF`. From an asset card, the equivalent menu item is `Export PDF`.
Use PNG when you want to paste the chart into a slide or a doc, and PDF when you want a page-sized, print-ready copy of a report.
### Share asset [#share-asset]
Click the `Share asset` icon in the canvas header to open the share modal, titled `Share asset`. The modal reads `Copy the link to share with anyone, or use the embed snippet in Notion, a blog post, or anywhere that allows iframes. Data refreshes live.` It briefly shows `Creating share link…` while it mints the link, then displays two read-only fields.
### Sharing link [#sharing-link]
The `Sharing link` field holds a public URL to your asset. Click `Copy` next to it — the button toggles to `Copied` and a `Copied to clipboard` toast appears — then paste the link into an email, a Slack message, or a doc. Anyone who opens it sees the live asset in a clean viewer; they do not need a buzzabout account.
### Embed snippet [#embed-snippet]
The `Embed snippet` field holds an `
## Gotchas [#gotchas]
* **Share links are public and unauthenticated.** Anyone with the `Sharing link` — or anyone who can see a page where you've embedded the asset — can view it without signing in. The public viewer carries a `Powered by buzzabout` footer. Treat the link as you would any public URL: don't share an asset built on data you wouldn't publish.
* **Embeds refresh live.** An embed re-resolves your data each time the page loads, so a shared chart keeps updating after you've pasted it. That's the point — but it also means viewers see the latest numbers, not a frozen snapshot. If you need a fixed copy, download a PNG or PDF instead.
* **Download and share are different take-homes.** Downloading gives you a static PNG or PDF file on your machine. Sharing gives you a public link plus a live `
## Next steps [#next-steps]
Turn a shared report into a structured brief for writers.
Save the sharpest findings from a report so the assistant builds on them.
Pull the assistant's answers and references into Claude over MCP.
# Spot trends (/tutorials/spot-trends)
If you run a DTC e-bike brand, the difference between a good quarter and a flat one is often timing — catching a topic like torque-sensor upgrades, commuter-range anxiety, or a viral fold-and-carry format while it is still rising, not after every competitor has posted about it. The **What's trending** skill reads a dataset you've already collected and tells you what is genuinely accelerating: it defines a trend as *change over time*, so it splits your mentions into a recent window versus a baseline window, compares topic clusters on volume, reach, and cross-creator adoption, and shortlists the clusters that are actually rising — not a single mega-post that briefly spiked. The output is a multi-line over-time chart, a trend detail table, and three plays you can ship this week.
## Prerequisites [#prerequisites]
* A dataset with a completed collection run, so there are mentions to compare across time. See [Set up your project](/tutorials/set-up-your-project) and [Create a mention collection](/tutorials/create-a-mention-collection).
* **Timestamped mentions and enough volume.** A trend is change over time, so the skill needs posts with usable timestamps spread across a recent and a baseline window. A thin or single-day dataset has nothing to compare — collect more before running it.
## Walkthrough [#walkthrough]
### Open skills [#open-skills]
Open a chat against the dataset that holds your e-bike mentions — a skill needs a draft context to attach to. In the chat composer, click the **Open skills** book icon, or type `/` at the start of an empty message to pop the skills picker.
### Browse all skills [#browse-all-skills]
The picker shows your **Favourite skills** with a **Browse all skills** footer. Click **Browse all skills** to open the full library.
### Market research [#market-research]
In the modal, open the **Market research** category in the left **Skills** sidebar — **What's trending** lives there. You can also type `What's trending` into **Search skills…** at the top to jump straight to it.
### Use this skill [#use-this-skill]
Click the **What's trending** row to open its detail view and read the instructions — it explains that a trend means change over time and that it shortlists multi-creator clusters rather than one-off spikes. When you're ready, click **Use this skill** to attach it to the current chat draft. The modal closes and the skill appears as an inline chip in the composer.
### Add context and send [#add-context-and-send]
Attach the e-bike dataset as context via the composer's Contextualize picker, type a short question such as `What is trending in the e-bike conversation right now?`, and send. The skill instructions tell the assistant to split the mentions into a recent window versus a baseline, compare topic clusters on volume, reach, and cross-creator adoption, and keep only the clusters that are genuinely rising.
### Read the over-time chart and trend table [#read-the-over-time-chart-and-trend-table]
The assistant returns its deliverable as an Asset. At the top is a multi-line over-time chart — one line per shortlisted cluster — so you can see which topics are pulling away from the baseline. Below it is a trend detail table giving each cluster its **magnitude** (how big the change is), its **catalyst** (what's driving it), and **how to ride** it. Read the lines that are climbing steepest and cross-check them against the table before you act.
### Ship the three plays [#ship-the-three-plays]
The skill closes with three plays to ship this week — concrete, time-boxed moves tied to the rising clusters, such as a post format to test, an angle to lean into, or a question to answer while the topic is hot. Pick the ones that fit your roadmap and act on them before the window closes; the value of a trend is in catching it early.
## Gotchas [#gotchas]
* **A trend is change over time — you need timestamps and volume.** The skill compares a recent window against a baseline, so mentions must carry usable timestamps spread across both. A thin, single-day, or low-volume dataset has nothing to compare against and the skill will say so instead of inventing a trend.
* **Single-post surges are flagged, not celebrated.** A cluster that spikes off one mega-post is not a trend. The skill shortlists clusters with cross-creator adoption (multiple creators, not one viral post) and explicitly flags single-post surges so you don't chase a fluke.
* **Watch for dated catalysts.** The skill also flags catalysts that have already passed. If the thing driving a cluster is an event that's over, the "trend" may already be cooling — read the catalyst column before you commit a play.
* **It runs a pattern pipeline that's asynchronous and may charge credits.** Comparing topic clusters runs a pattern-matching pipeline that can take a few minutes; if a pattern already exists on the dataset it is reused rather than re-run.
* **It's a point-in-time read.** Running the skill once tells you what's rising today. To keep catching new trends as they emerge, pair it with a listening agent that re-runs the underlying queries on a schedule so the dataset stays fresh — then re-run the skill against the growing data.
## Next steps [#next-steps]
Collect the broad conversation a trend read needs before you run the skill.
Keep the dataset growing on a schedule so you catch new trends as they appear.
Learn the full skills workflow — favourites, categories, and customizing.
# Track share of voice (/tutorials/track-share-of-voice)
Share of voice answers one question for a B2B SaaS project-management tool: of all the brand mentions in a conversation, what slice is yours versus your rivals — and is that slice loved or loathed? buzzabout produces this from the **Mentioned brands** skill: collect a dataset that spans the category (your brand and your competitors), apply the skill, and you get a share-of-voice bar chart per brand coloured by its dominant sentiment, a brand detail table, and a few notable patterns. There is no "Share of Voice" page or button — it is this skill (or an equivalent ask to the assistant).
## Prerequisites [#prerequisites]
* A collected dataset that actually spans the brands you want to compare. Share of voice is only as fair as the conversation you collected — a dataset built around one brand's keywords will under-count everyone else. Run category- or competitor-level keyword research first. See [Competitor research](/tutorials/competitor-research) and [Create a mention collection](/tutorials/create-a-mention-collection).
* A bigger, multi-source dataset gives a fairer comparison. Multi-source research unlocks at Pro and above; on Starter you collect a single platform, which can skew share of voice toward wherever that brand happens to be loudest.
## Walkthrough [#walkthrough]
### Collect a dataset that spans the brands [#collect-a-dataset-that-spans-the-brands]
Share of voice compares brands *within one dataset*, so the dataset has to contain all of them. Run keyword research scoped to the category and your competitor set rather than just your own name — for example a query that names the rival project-management tools and the jobs people use them for, so the conversation captures everyone, not only you.
Use boolean operators to widen the net across the category. The operators are **AND**, **OR**, **NOT**, plus **parentheses** for grouping and **"double quotes"** for exact phrases. The default join between two keywords is **OR** (which broadens reach) — add **AND** to require co-occurrence and **NOT** to exclude. Operators are case-insensitive and shown uppercase. For a project-management comparison you might collect with `asana trello "monday.com" notion clickup` (implicit OR across the set) or `"project management" AND (asana OR trello OR notion)`. Sanity-check the live mention-count estimate before you run.
### Open skills [#open-skills]
Open the chat or project where you collected the dataset. In the chat composer, click the **Open skills** book icon to pop the skills picker. The picker shows **Favourite skills** with a **Browse all skills** footer.
### Browse all skills [#browse-all-skills]
Click **Browse all skills** to open the full library. In the left **Skills** sidebar, open the **Market research** category — that is where **Mentioned brands** lives. You can also type into the search box to find it by name.
### Use this skill [#use-this-skill]
Open the **Mentioned brands** skill to read what it does: it pulls the pre-computed brand-mention field from each post, aggregates reach, volume, dominant sentiment and context per brand, and renders a share-of-voice bar chart. Click **Use this skill** to attach it to the current chat draft — it appears as an inline chip in the composer. If no chat is open, **Use this skill** is disabled with the tooltip **Open a chat or project to apply this skill.**
### Add context and send [#add-context-and-send]
Attach your category dataset as context in the composer before you send — the skill reads whatever dataset you attach, so the share-of-voice comparison only covers the brands inside it. With the skill chip and the dataset context chip both on the message, send it. The skill does not run on its own; the analysis (and any credit cost) happens only when you send.
If you would rather skip the picker entirely, you can ask the assistant in plain language instead — for example **compare share of voice across Asana, Trello and Notion in this dataset**, with the same dataset attached as context. The result is the same kind of brand comparison.
### Share-of-voice chart [#share-of-voice-chart]
The hero artifact is a horizontal bar chart of the top brands by reach, with each bar coloured by that brand's **dominant sentiment** — positive, negative, neutral or mixed. This is your share-of-voice view: the longer the bar, the larger the brand's slice of the conversation; the colour tells you whether that slice is friendly. Read your own bar against your competitors' to see who owns the category discussion and at what cost in sentiment.
### Brand detail table [#brand-detail-table]
Below the chart, the brand detail table gives one row per brand: name, **reach** (distinct users mentioning it), **volume** (total mention count across posts), **dominant sentiment**, a one-to-two-line **context** note on how the brand is framed, and a representative verbatim quote with a link. Use it to separate reach from volume — a brand can be mentioned a lot by a handful of loud accounts, or a little by many.
### Notable patterns [#notable-patterns]
The skill closes with two to four notable patterns worth acting on: a brand **punching above its reach** (few mentions but strong sentiment), a brand dominating the conversation, a **co-mention** pattern where two brands almost always come up together in comparison threads, or a sentiment skew. These are the read-outs that turn a chart into a positioning decision — for instance, learning that your tool is co-mentioned with a specific rival whenever people discuss a particular workflow.
## Gotchas [#gotchas]
* **Share of voice is not a page or a button.** It is the output of the **Mentioned brands** skill (or an equivalent ask to the assistant). There is no dedicated Share of Voice screen, roster card or standalone chart to navigate to.
* **It only compares brands inside the dataset you attach.** If your dataset was built around your own keywords, you will look bigger than you are. Collect a category- or competitor-spanning dataset first so every brand has a fair chance to appear.
* **The skill reads a pre-computed field — it does not re-detect brands.** Brand detection runs during post-processing across text, audio and visual signals; the skill aggregates that field. If the dataset has very few brand mentions, the skill delivers what is there and notes the small sample.
* **Low-signal brands are dropped.** Brands with roughly fewer than 3 mentions across fewer than 3 distinct users are filtered out as too noisy — expect a focused top-10-to-15, not a long tail.
* **Bigger, multi-source datasets give a fairer comparison.** A single-platform Starter collection skews share of voice toward whichever brand is loudest on that one platform. Multi-source research (Pro and above) spreads the comparison across platforms.
* **Applying the skill does not run it.** Attaching the skill chip only pins it to the draft. The analysis — and any credit cost — happens when you send the message with the dataset attached as context.
## Next steps [#next-steps]
Collect the category- and competitor-spanning datasets that share of voice compares.
How to apply, favourite and customise any skill, including Mentioned brands.
Profile who is doing the talking behind each brand's share of voice.
# Use insights (/tutorials/use-insights)
When the AI assistant returns a long reply about your cold-brew coffee brand, one or two lines usually carry the finding you actually want to keep — a recurring pain point, a sharp objection, a quotable customer line. An insight is exactly that: a snippet you highlight in an AI reply and save. Saving it does more than bookmark the text — the snippet is added to the chat's context, and the assistant takes your saved insights into account on later turns and builds on them. Promote an insight to a project and it becomes reusable context across every new chat in that project. Insights are one context layer alongside your project datasets, saved assets, and brand context: the running shortlist of validated findings you want the assistant to keep working from.
## Prerequisites [#prerequisites]
* An existing chat with at least one AI assistant reply. If you haven't run any research yet, start with [Run your first research](/tutorials/run-your-first-research) to collect mentions, then ask the assistant about them.
* For project-level insights, the chat must belong to a project. See [Set up your project](/tutorials/set-up-your-project).
## Walkthrough [#walkthrough]
### Ask the AI assistant a question [#ask-the-ai-assistant-a-question]
Open a chat and ask the assistant something grounded in your collected data — for example, *"What do people complain about most with cold-brew coffee?"* The assistant reasons over your datasets and mentions and returns a reply. Wait for the answer to finish generating before the next step.
### Save as insight [#save-as-insight]
In the AI reply, select (highlight) the sentence or paragraph you want to keep — a pain point, an objection, or a verbatim customer quote. A small toolbar appears anchored above your selection. Click `Save as insight`. The button shows `Saving…` while the request is in flight, then a toast reading `Insight saved` confirms it and your selection is cleared. If saving fails you'll see `Failed to save insight`; just re-select and try again.
The snippet is now a chat-scoped insight, private to this chat — and from your next turn onward it is added to the chat's context. The assistant takes your saved insights into account and builds on them: if you save *"bitter aftertaste from concentrate"* as a pain point, then ask it to draft a few posts, it carries that line forward rather than starting cold.
### Add to project [#add-to-project]
If the chat belongs to a project, the `Insight saved` toast also offers an `Add to project` action. Click it to promote the snippet so it shows up on the project page. Promoting matters: a project insight is reused as context across **new** chats in that project, so a pain point or quote you validated in one chat keeps informing the assistant in the next one — without you re-pasting it.
You can also promote later from the insight card's menu, so there's no rush.
### Insights [#insights]
Open the chat's right panel to find the `Insights` section, labelled `Snippets you saved from AI replies`. Each saved snippet appears as a card. The list is paginated 20 at a time — use `Load more` (which reads `Loading…` while fetching) to see older insights.
### Reuse insights to brief, draft, or report [#reuse-insights-to-brief-draft-or-report]
Because saved insights ride in the chat's context, you can put them straight to work in the same chat. Once you've saved a couple of pain points and a customer quote, ask the assistant to act on them — for example:
* *"Using the insights I've saved, draft a content brief for a post about cold-brew aftertaste."* — feeds a [content brief](/tutorials/generate-a-content-brief).
* *"Turn these insights into three short posts, leading with the quote I saved."*
* *"Pull my saved insights into a short take-home report I can share with the team."*
There's no one-click "generate report from insights" button — the assistant weaves your saved insights into a report or take-home asset when you ask. Ask for a rich asset and it opens in the side panel, where you can [share or export it](/tutorials/share-and-export-assets).
### Jump back to the source message [#jump-back-to-the-source-message]
Click an insight card to jump back to the exact AI reply it came from. The URL gains a `#message-...` fragment and the source message briefly flashes so you can see it in context — useful when you want the full surrounding answer, not just the saved line.
### Link or delete from the card menu [#link-or-delete-from-the-card-menu]
Each insight card has a kebab (More) menu. In a project chat it offers `Add to project` to link the insight. It also offers `Delete`, which opens a confirmation dialog titled `Delete this insight?` with the warning `This cannot be undone.` — choose `Cancel` to back out or `Delete` to remove it.
### Insights on the project page [#insights-on-the-project-page]
Open the project page and look at the project settings card for its own `Insights` section, labelled `Linked insights from project chats`. This lists every insight promoted from any chat in the project — the shared context layer that new chats in the project draw on. From a project insight card, click to go back to its original chat and message, or use the menu's `Remove from project` to unlink it.
## Gotchas [#gotchas]
* Insights are soft context, not a hard directive. The assistant takes your saved insights into account and builds on them — it does not rewrite every answer around them. They steer; they don't override what you ask.
* Saving has no effect until the next turn. The snippet is added to the chat's context server-side, so the assistant only sees a new insight on your following message — not retroactively within the reply you saved it from.
* The `Save as insight` toolbar only appears on AI assistant replies, and only once the reply has finished generating. You cannot save a snippet while the answer is still streaming.
* An insight is a snippet *you* highlight and save, not an auto-generated AI insight. The product term means a user-saved excerpt of an AI reply, tied to the message it came from.
* Two scopes. Chat-scoped insights are private to one chat and steer only that chat. Only **promoted** (linked) insights become project context and reach new chats in the project — `Add to project` appears only when the chat belongs to a project.
* Saving, promoting, unlinking, and deleting insights is a web-app action only. There is no MCP tool or public REST endpoint to create or link an insight — an agent can get the assistant's answer through `buzzabout__ask`, but it cannot save one as an insight.
* Deleting a chat insight is irreversible (`This cannot be undone.`). `Remove from project` only unlinks the insight from the project — it does not delete the underlying chat insight.
* If the originating chat is deleted, a project insight still shows, but its source line reads `From deleted chat ·` with the date and the card is no longer clickable — there's no source message to jump to.
* Lists load 20 at a time. Use `Load more` to page through longer lists.
## Next steps [#next-steps]
Turn the insights you saved into a structured brief for writers.
Group chats and datasets so promoted insights become shared context.
Pull the assistant's answers and their
`references`
into Claude over MCP.
# Use skills (/tutorials/use-skills)
Skills are how you get a senior analyst's brief out of one click. A skill is a saved, expert instruction block you apply to a chat so the AI assistant runs the same analysis the same way every time — no re-typing a prompt into every new chat. Say you've collected a few hundred mentions about a B2B SaaS project-management tool. Apply the **Feature requests** skill and you get a ranked list of what people are asking you to build; apply **Mentioned brands** and you get a share-of-voice picture against your competitors. Pick the skill, point it at your mentions, ask your question, and send. This page is the hub: how to apply any skill, what data skills need, the shape of what they return, and a tour of the built-in catalog.
## Prerequisites [#prerequisites]
* A collected dataset of mentions to point the skill at. Most skills analyse the mentions you attach as context, so you need at least one collection first. See [Create a mention collection](/tutorials/create-a-mention-collection). For meaningful results, aim for \~100+ mentions — a handful of posts won't support a chart or a ranked table.
In-app the feature is called **Skills** everywhere. "Prompt Library" / "prompt" is only the internal code name — it never appears in the UI.
## What a skill returns [#what-a-skill-returns]
Most built-in skills follow the same output template, so you always know what to expect:
* **A hero chart** — the headline visual (a severity bar, a share-of-voice bar, a trend line).
* **A detail table** — the rows behind the chart, so you can drill into specifics.
* **3 takeaways** — concrete next moves (messaging, product, or content handles), not just a summary.
When a skill needs data that isn't there, it says so in one line instead of rendering an empty chart.
## Walkthrough [#walkthrough]
### Open skills [#open-skills]
Open a chat or project for your project-management research — a skill needs a draft to attach to. In the chat composer, click the **Open skills** book icon, or type `/` at the start of an empty message to pop the skills picker.
### Favourite skills [#favourite-skills]
The picker shows **Favourite skills** (skills you've starred) with a **Browse all skills** footer. Click a favourite to apply it instantly, or click **Browse all skills** to open the full library. The favourites list starts empty — until you star something you'll see **No favourite skills yet** with the hint to star skills in the library to pin them here.
### Browse all skills [#browse-all-skills]
In the modal, pick a category in the left **Skills** sidebar — **Market research**, **Content & positioning**, **Audience research**, **Charting & visualization**, or **Custom** — or open the **Favorites** tab. To find a skill by name, type into **Search skills…** at the top.
### Use this skill [#use-this-skill]
Click a skill row to open its detail view and read the instructions. When it's the right one, click **Use this skill** to attach it to the current chat draft. The modal closes and the skill appears as an inline chip in the composer.
If no chat is open, **Use this skill** is disabled with the tooltip **Open a chat or project to apply this skill.**
### Customize [#customize]
To turn a built-in skill into one you can edit, open it and click **Customize**. This forks an editable copy (named `{name} Custom`) and the original stays as is. The tooltip reads **Saves as a new custom prompt — the original stays as is**. Only custom skills show **Edit** and **Delete**; built-in skills only show **Customize**.
## The built-in catalog [#the-built-in-catalog]
The built-in skills span four categories. A few are worth singling out — and several have their own deep-dive tutorial.
**Market research** — understand your standing and your competitors.
* **Mentioned brands** — a share-of-voice bar coloured by sentiment, plus a per-brand detail table. This is how you get share of voice; there is no standalone "SoV page." See [Track share of voice](/tutorials/track-share-of-voice).
* **What's trending** — splits your mentions into a recent vs baseline window, shortlists rising topics, and returns an over-time chart with plays to ship this week. See [Spot trends](/tutorials/spot-trends).
* **Controversy map** — finds polarized topics and maps the two sides with quotes.
**Content & positioning** — turn conversation into a roadmap and a content plan.
* **Feature requests** — pattern-matches product-directed asks ("please add X"), ranks them by severity, and triages each one. See [Analyse feature requests](/tutorials/analyse-feature-requests).
* **Analyze pain points** — clusters pain points weighed by reach and intensity, with messaging and product handles. See [Analyse pain points](/tutorials/analyse-pain-points).
* **Positive / negative quotes** — surfaces the strongest quotes per polarity, with reuse and routing suggestions.
* **Suggest content ideas** — a synthesis skill that draws on outliers, gaps, pains, and questions to propose scored content briefs. See [Generate a content brief](/tutorials/generate-a-content-brief).
* Also here: **Analyze content outliers**, **Content gap analysis**, **Hook analysis**, **Audience questions**, **Objections mining**, **Unmet needs**, **Summarize comments**.
**Audience research** — understand who is talking.
* **Audience demographic chart** and **Audience psychographic chart** (OCEAN radar) render from an audience-profile dataset. See [Run audience analysis](/tutorials/run-audience-analysis).
**Charting & visualization** — quick, focused charts (emotions, intentions, topics vs engagement rate or views, an engagement-rate trend line). These share an identical structure: pick the axis, get the chart and a short takeaway.
## Now analyse it → skills [#now-analyse-it--skills]
Skills are the analysis engine for every research playbook. Once you have a collection, the fastest path to a decision is to apply the right skill:
* Competitive standing → **Mentioned brands** ([Track share of voice](/tutorials/track-share-of-voice))
* Roadmap input → **Feature requests** ([Analyse feature requests](/tutorials/analyse-feature-requests)) and **Analyze pain points** ([Analyse pain points](/tutorials/analyse-pain-points))
* Momentum → **What's trending** ([Spot trends](/tutorials/spot-trends))
* Content plan → **Suggest content ideas** ([Generate a content brief](/tutorials/generate-a-content-brief))
* Audience → **Audience psychographic chart** ([Run audience analysis](/tutorials/run-audience-analysis))
## Gotchas [#gotchas]
* **Applying a skill does not run anything.** A skill is just a saved instruction block. Attaching it pins the skill onto the chat draft — the analysis (and any credit cost) happens only when you send the chat message.
* **Many skills need pre-computed enrichment.** Skills that read sentiment, emotion, intent, topic, or brand columns — or an audience-profile dataset — only render fully when that data exists. If it's missing, the skill says so in one line instead of drawing an empty chart.
* **Pattern-based skills run async and may charge credits.** Pain points, feature requests, objections, unmet needs, content gap, controversy map, hook analysis, and what's-trending kick off a pattern-detection pipeline that takes a few minutes and can cost credits (post-processing is \~0.5 credit per mention). They reuse existing pattern assignments if those have already been computed.
* **You must be in a chat or project.** **Use this skill** is disabled outside a chat or project, because there is no draft to attach to.
* **Only one skill per message.** Applying a skill removes any previously attached skill chip first, so a draft carries just one at a time.
* **"Run on a collection" means attaching context.** There is no per-skill run button. Attach a collection (or dataset) as context in the same composer before sending; the skill chip and the context chips are independent.
* **"Summarize comments" needs a selection first.** It runs against post(s) you've selected, not the whole dataset — select at least one post before applying it.
* **A couple of skills aren't under a category tab.** "Get buzzwords" has no category, so you'll find it only via search or as a favourite.
* **Built-in vs custom.** Built-in skills can't be edited or deleted — only **Customize**d into a copy. Edit and Delete appear only on your own custom skills; new custom skills land in the **Custom** category.
## Next steps [#next-steps]
Use the Mentioned brands skill to size your share against competitors.
Turn product-directed asks into a ranked roadmap input.
Surface what's rising with the What's trending skill.
Write and save your own reusable instruction blocks.
# Use smart parameters (/tutorials/use-smart-parameters)
A Smart Parameter turns any question you have about your mentions into a column that AI fills in for you. Your prompt runs against every mention in scope and its answer becomes the column's value — so you can tag, classify, or extract one thing across the whole collection without reading each post by hand. If you run an e-bike DTC brand, you might add a column for buyer intent, the pain point each post raises, or whether it names a competitor, and have it answered for thousands of mentions at once.
## Prerequisites [#prerequisites]
* A dataset with collected mentions to run against — collect one first (see [Create a mention collection](/tutorials/create-a-mention-collection)).
* Available credits. Running costs `0.5` credits per mention; the test-run preview is free.
In the app this feature is called **Smart Parameter**. In the API and MCP the same entity is named `custom_parameter` (with `instructions` and `value_type` fields). The walkthrough below uses the in-app names.
## Walkthrough [#walkthrough]
### Add column [#add-column]
Open the Library at `/library`, or open a dataset table at `/datasets/[id]`. In the column header, click the `+` **Add column** button to open the column-settings popover. Under **Add a property**, click **Smart Parameter** (labelled **AI auto-fill column**) to open the **New Smart Parameter** modal.
### Configure [#configure]
This is phase one of three. Optionally pick a starting point under **Start from preset** — choose **Custom** to **Start blank**, or use one of the named presets (Topic, Buyer intent, Pain points, Competitor mentions, Content type, Language, Action summary).
Then fill in the fields. Enter a **Name** (the placeholder shows `e.g. Buyer intent`). Write your **Prompt template** — the prompt is sent to the AI for each mention. Optionally add an **Expected output**, and choose an **Output type**: **Text**, **List**, or **Object**.
For the e-bike brand you might name the column `Buyer intent`, set the output type to **Text**, and use a prompt template like: classify whether this mention is from someone researching a purchase, comparing models, or just discussing e-bikes generally.
### Test run [#test-run]
In the **Test run** section, click **Run test** to preview results on the first 3 visible mentions. This is free and uses no credits, so iterate on your prompt here before committing to a full run. Each row shows **Thinking…** while it works, then the AI's **Output**.
### Save [#save]
Click **Save** to create the parameter. The modal stays open and switches to edit mode for the parameter you just created — saving never closes the modal by design. Close it later with **Cancel**, the `X`, or `Escape`.
### Scope [#scope]
This is phase two. Under **Scope**, pick which mentions to analyse — your current saved View or the dataset. The helper text reads: "Choose which mentions to analyse. The run starts after you click Run." A saved View is required to run; if there is no scope context, the picker and Run buttons are hidden and a note tells you to save a View first.
### Confirm & run [#confirm--run]
This is phase three. Review the mention count and the credit estimate, then click **Run**. If you have not picked a scope yet you will see "Pick a scope above to see the credit estimate."
### Watch the column fill in [#watch-the-column-fill-in]
After the run starts, values populate per mention over time. Cells show `—` for mentions not yet run, **Running…** while in progress, the AI value when done, and **Error** on failure. There is no inline retry. Mentions already analysed are skipped automatically if you re-run.
### Re-edit or run again later [#re-edit-or-run-again-later]
Use the column kebab menu to manage the parameter. **Edit prompt & test run…** reopens the modal, **Hide column** / **Show column** toggle visibility, and **Delete column** removes it — note that deleting the column stops AI computations. **Run now** computes the parameter against the selected scope, skipping mentions already analysed.
## Now use the column [#now-use-the-column]
Once a column is filled in, it behaves like any other column in the mentions table — and it travels with your data:
* **Filter and sort by it** in a saved View. Combine a Smart Parameter with sentiment, platform, or posting date to slice mentions exactly the way you need.
* **Export it.** When you select rows and **Export** to CSV, the file (`library-.csv`) includes every Smart Parameter — regardless of which columns are currently toggled on — alongside the standard mention fields. CSV export is a Pro+ feature.
* **Feed it into analysis.** Smart Parameters create the enriched columns that many skills and insights read from, so a buyer-intent or pain-point column makes the next analysis sharper.
## Gotchas [#gotchas]
* **Three stages, and only one costs credits.** Create, then **Test run** (a free, stateless preview on the first 3 mentions), then run on your collection — only the collection run charges credits.
* **Cost is `0.5` credits per mention.** The estimate is `count × 0.5` rounded up. The numbers shown in the app are estimates only; the API charges the precise amount when it runs.
* **Per-run cap of 5,000 mentions.** Larger scopes are sliced: "Up to 5,000 mentions will be processed in this run. Re-run after completion to continue with the next batch."
* **A saved View or dataset is required to run.** With no scope context the picker and Run buttons are hidden, and a note tells you to save a View first.
* **Save never closes the modal.** Dismiss it with **Cancel**, the `X`, or `Escape`. Only a run-only flow closes on a successful run.
* **Run is disabled while the form is unsaved or dirty.** You will see "Save first to run" before the parameter exists, and "Save changes first" while you have unsaved edits.
* **Credits gate the run.** With a zero balance you see "Top up to run a Smart Parameter — you have 0 credits." A nonzero but insufficient balance still runs the first affordable batch.
* **Values fill in asynchronously.** Cell statuses move from `—` to **Running…** to a value, or **Error** on failure (including rows stuck over 60 minutes). There is no inline retry.
* **Re-runs skip analysed mentions.** A re-run may report nothing to do with "All mentions already analyzed", or block if a run is already in progress.
* **Duplicate names are rejected** by the API, and an empty name surfaces inline under the **Name** field.
* **Chat can suggest one too.** The assistant may emit a **Suggested Smart Parameter** card with **Edit** / **Confirm** and a **Run on dataset** picker (or **Skip — just save**); confirming creates the parameter and can queue a run.
## Next steps [#next-steps]
Run the analysis skills that read from your enriched columns.
Turn your enriched mentions into insights you can act on.
# Ask (assistant) (/api/endpoints/ask)
`POST /v1/ask` hands a message to the buzzabout assistant. Optionally
continue an existing chat via `chat_id` and scope the turn to specific
datasets — the assistant returns markdown with inline post citations
plus a typed list of references. Already wired buzzabout into Claude /
Cursor / ChatGPT? You get the same surface through MCP — see
[Use in your agent](/mcp/use-in-your-agent).
**Free** — asking the assistant does not consume credits. See
[Pricing](/getting-started/pricing).
## Endpoint [#endpoint]
## Response shape [#response-shape]
The response carries:
* **`text`** — markdown body, including inline post citations as
`[label](post:source:id)` links (see
[Reference types](/api/reference-types)).
* **`references[]`** — a flat list of typed pointers
(`{ type, id }`) into buzzabout resources (patterns, datasets,
research previews, pattern-detection runs, etc.).
* **`chat_id`** + **`message_id`** — the assistant chose a chat for
this turn. Pass `chat_id` back on the next call to continue the
same conversation.
The output is always markdown. The endpoint enforces
`output_format=markdown` on the assistant — public clients cannot
request openui or other in-app block formats.
## Continuing a conversation [#continuing-a-conversation]
```python
import httpx
client = httpx.Client(
base_url="https://api.buzzabout.ai",
headers={"x-api-key": "bz_live_abcdef1234567890abcdef1234567890"},
)
# First turn
turn1 = client.post(
"/v1/ask",
json={"message": "Find the top hooks for cold brew posts"},
).raise_for_status().json()["data"]
chat_id = turn1["chat_id"]
# Second turn — continues the same chat
turn2 = client.post(
"/v1/ask",
json={
"message": "Now compare the top hooks on Reddit vs TikTok",
"chat_id": chat_id,
},
).raise_for_status().json()["data"]
```
Both turns are asynchronous — the response carries a `message_id` you
poll via
[`GET /v1/chats/{chat_id}/messages/{message_id}`](/api/endpoints/chats)
until `status` transitions to `completed`.
## Scoping with context [#scoping-with-context]
The optional `context` field accepts:
* **`dataset_ids`** — list of dataset ids the assistant should treat as
in-scope for the turn. When omitted, the assistant may consult any
dataset visible to the account.
* **`post_refs`** — up to 50 specific posts to pin into the assistant's
working context (each `{ id, source }` — see the schema above).
Filters and other narrowing (sentiment-only, date windows, etc.) live
inside the `message` text — the assistant reads them naturally. There
is no structured filter field.
## Reading the history [#reading-the-history]
Once you have a `chat_id`, use
[`GET /v1/chats/{id}/messages`](/api/endpoints/chats) to page through
the full transcript (user + assistant turns, ascending by
`created_at`).
## Next steps [#next-steps]
* [Chats](/api/endpoints/chats) — read message history and chat
metadata.
* [Reference types](/api/reference-types) — how `references[]` and
the `post:source:id` markdown scheme resolve.
* [Use in your agent](/mcp/use-in-your-agent) — same surface via MCP
for Claude / Cursor / ChatGPT users.
# Audience datasets (/api/endpoints/audience-datasets)
An **audience dataset** turns the posts in a source dataset into a
collection of typed audience profiles (age range, role, interests,
inferred persona). Profile collection is asynchronous, like a regular
dataset run.
Audience-dataset runs charge **3 credits per `audience_profile`**,
reservation-based. The reservation is sized by `total_profile_count`
(default 300) and refunded down to actuals on completion. See
[Pricing](/getting-started/pricing#reservation-based-charging).
## Endpoints [#endpoints]
### POST `/v1/audience_datasets` [#post-v1audience_datasets]
### GET `/v1/audience_datasets` [#get-v1audience_datasets]
### GET `/v1/audience_datasets/{audience_dataset_id}` [#get-v1audience_datasetsaudience_dataset_id]
### PATCH `/v1/audience_datasets/{audience_dataset_id}` [#patch-v1audience_datasetsaudience_dataset_id]
### DELETE `/v1/audience_datasets/{audience_dataset_id}` [#delete-v1audience_datasetsaudience_dataset_id]
### POST `/v1/audience_datasets/{audience_dataset_id}/runs` [#post-v1audience_datasetsaudience_dataset_idruns]
### GET `/v1/audience_datasets/{audience_dataset_id}/runs` [#get-v1audience_datasetsaudience_dataset_idruns]
### GET `/v1/audience_datasets/{audience_dataset_id}/runs/{run_id}` [#get-v1audience_datasetsaudience_dataset_idrunsrun_id]
## Source dataset [#source-dataset]
Every audience-dataset run takes a `source_dataset_id` pointing at an
existing (completed) [dataset](/api/endpoints/datasets). The audience
pipeline reads that dataset's mentions and infers a profile per
distinct author / handle.
`total_profile_count` (default 300, range 1–2000) bounds how many
profiles the run will attempt to produce. The run stops early if the
source dataset doesn't have that many distinct authors.
## Read collected profiles [#read-collected-profiles]
Once a run reaches `completed`, query
[`POST /v1/audience_profiles`](/api/endpoints/audience-profiles) with
the audience dataset's id to read what the run produced.
## Next steps [#next-steps]
* [Audience profiles](/api/endpoints/audience-profiles) — read the
collected profile rows.
* [Datasets](/api/endpoints/datasets) — the source-of-posts that
audience runs point at.
# Audience profiles (/api/endpoints/audience-profiles)
The audience-profiles endpoint is **global**: one call returns
profiles from every audience dataset owned by the calling account.
Pass `audience_dataset_ids` to scope; omit it to span everything.
This is a `POST` (not `GET`) because filters are non-trivially nested,
mirroring the [`POST /v1/mentions`](/api/endpoints/mentions) shape.
Free — no credits charged. The cost lives on the upstream
[audience-dataset run](/api/endpoints/audience-datasets) that
collected the profiles. See [Pricing](/getting-started/pricing).
## Endpoint [#endpoint]
## Filters [#filters]
`filters` carries the same OR-of-AND-groups shape as
[mentions](/api/endpoints/mentions#filters). Available filter types
for profiles cover age range, location, role, interests, and inferred
persona — the schema above enumerates the exact union.
Maximum 10 filters total across all groups.
## Sort fields [#sort-fields]
`sort` accepts: `created_at`, `audience_dataset_run_at`. Other
dimensions (engagement-style metrics) are deliberately absent —
profiles do not carry their own engagement counts.
## Cursors [#cursors]
Cursors encode the sort dimension. Switch `sort` between calls →
fetch a fresh page (don't reuse a cursor across sorts).
## Next steps [#next-steps]
* [Audience datasets](/api/endpoints/audience-datasets) — manage the
containers profiles live in.
* [Mentions](/api/endpoints/mentions) — the posts that gave rise to
these profiles.
# Chats (/api/endpoints/chats)
Chats are user-owned: each chat carries a `user_id` matching the seat
that created it. Reading is scoped to **the same seat that created
the chat** — other team members (including the team owner) get a 404
when looking up another seat's chat.
Each API key carries both `account_id` (resource scope, shared
across the team) and `user_id` (acting seat). Account-shared
resources — datasets, mentions, tracking agents, custom parameters —
are readable by every key on the account. Chats are the exception:
they are private to the creating seat.
Free — no credits charged. The cost lives on the
[`POST /v1/ask`](/api/endpoints/ask) turn that created the chat. See
[Pricing](/getting-started/pricing).
## Endpoints [#endpoints]
### GET `/v1/chats/{chat_id}` [#get-v1chatschat_id]
### GET `/v1/chats/{chat_id}/messages` [#get-v1chatschat_idmessages]
## Chat metadata [#chat-metadata]
`GET /v1/chats/{id}` returns the bare bones:
* `id`
* `name` (nullable; the assistant assigns one after the first few
turns)
* `tracking_agent_id` (set when the chat belongs to a tracking
agent's dedicated dialogue, otherwise `null`)
* `created_at`
Heavier fields the in-app UI uses (`summary`, `blocks`, `read`,
`include_comments`, `include_blocks`, `short_preview_message`) are
intentionally absent from the public surface.
## Messages [#messages]
`GET /v1/chats/{id}/messages` is cursor-paginated. Default
`limit=25`, max 100. Returned **ascending by `created_at`** so the
oldest message is first — render top-to-bottom without re-sorting.
Each row carries:
```jsonc
// user
{ "id": "...", "role": "user", "text": "...", "context": {...}, "created_at": "..." }
// assistant
{ "id": "...", "role": "assistant", "text": "...", "references": [...], "created_at": "..." }
```
Assistant `text` is always markdown (the public surface enforces
`output_format=markdown` per turn). Citations follow the
[reference types](/api/reference-types) conventions — typed pointers
in `references[]`, inline post links in `text`.
## Creating chats [#creating-chats]
Chats are created implicitly via [`POST /v1/ask`](/api/endpoints/ask).
There is no dedicated create endpoint on the public surface.
## Next steps [#next-steps]
* [Ask](/api/endpoints/ask) — create or continue a chat.
* [Reference types](/api/reference-types) — how assistant references
resolve to underlying resources.
* [Tracking agents](/api/endpoints/tracking-agents) — agent-owned
chats live under `tracking_agent_id`.
# Credit prices (/api/endpoints/credit-prices)
`GET /v1/credit_prices` returns the current price per result for each
of the four public categories. Public read endpoint — no auth required.
Free — no credits charged. See
[Pricing](/getting-started/pricing) for the model behind the
numbers this endpoint returns.
## Endpoint [#endpoint]
## Why this exists [#why-this-exists]
So your agent or dashboard can ground cost reasoning in live prices
without scraping the docs. The shape is flat and stable; new
categories ship as additive fields.
```json
{
"status": "success",
"data": {
"mention": 1,
"audience_profile": 3,
"post_processing": 0.5,
"preview_generation": 1
}
}
```
`preview_generation` is the per-source price for a
[research preview](/api/endpoints/research-previews); `url` previews
refund profiles that returned no data.
See [Pricing](/getting-started/pricing) for which endpoints charge
which category, and which categories are reservation-based.
## Next steps [#next-steps]
* [Pricing](/getting-started/pricing) — overview of all four
categories.
* [`GET /v1/me/usage_history`](/api/endpoints/me) — your account's
charge feed.
# Custom parameters (/api/endpoints/custom-parameters)
A **custom parameter** is a named LLM extraction rule. Once defined,
you point it at a dataset to populate the extracted value on every
mention in that dataset. The shape and behaviour mirror the in-app
"Custom data" surface.
Custom-parameter runs charge **0.5 credits per `post_processing`** —
one charge per post the rule runs against. Reservation-based: sized
by the dataset's mention count up-front, refunded down to actuals on
completion (full refund on failure). Previews are **free**. See
[Pricing](/getting-started/pricing#reservation-based-charging).
## Endpoints [#endpoints]
### POST `/v1/custom_parameters` [#post-v1custom_parameters]
### GET `/v1/custom_parameters` [#get-v1custom_parameters]
### POST `/v1/custom_parameters/preview` [#post-v1custom_parameterspreview]
### GET `/v1/custom_parameters/{parameter_id}` [#get-v1custom_parametersparameter_id]
### PATCH `/v1/custom_parameters/{parameter_id}` [#patch-v1custom_parametersparameter_id]
### DELETE `/v1/custom_parameters/{parameter_id}` [#delete-v1custom_parametersparameter_id]
### POST `/v1/custom_parameters/{parameter_id}/runs` [#post-v1custom_parametersparameter_idruns]
### GET `/v1/custom_parameters/{parameter_id}/runs` [#get-v1custom_parametersparameter_idruns]
### GET `/v1/custom_parameters/{parameter_id}/runs/{run_id}` [#get-v1custom_parametersparameter_idrunsrun_id]
## Preview before running [#preview-before-running]
`POST /v1/custom_parameters/preview` takes raw `instructions` +
`value_type` + 1–5 `post_refs` and returns the would-be extraction
for those posts only. No charge. Use this loop to iterate on the
prompt before committing to a full run.
## Triggering a run [#triggering-a-run]
`POST /v1/custom_parameters/{id}/runs` takes a tagged-union `scope`:
```json
{ "scope": { "kind": "dataset", "id": "ds_2NK4Y3JxhJ8r9c0Y1u5lkjm9Wb1" } }
```
In each example replace `{dataset_id}` (visible placeholder) with the
real dataset id from your account.
`dataset` is the only variant in v1. The union shape keeps room for
`view` or other scopes in a future revision without breaking the
contract.
## Run status [#run-status]
`GET .../runs/{run_id}` reports three counters:
* `mentions_total` — posts the run will visit.
* `mentions_done` — posts successfully processed.
* `mentions_error` — posts the LLM couldn't process (retried; final
failures appear here).
Use these to render a progress UI. The run is complete when
`mentions_done + mentions_error === mentions_total`.
## Reading extracted values [#reading-extracted-values]
Once a run completes, query
[`POST /v1/mentions`](/api/endpoints/mentions) with the
`parameter_ids` field set to your parameter's id. Each mention's
response includes the extracted value under
`custom_parameters[{parameter_id}]`.
## Next steps [#next-steps]
* [Mentions](/api/endpoints/mentions) — read extracted values via
`parameter_ids`.
* [Datasets](/api/endpoints/datasets) — the scope target of a
custom-parameter run.
* [Pattern detections](/api/endpoints/pattern-detections) — the
sibling "process every post" analysis.
# Datasets (/api/endpoints/datasets)
A **dataset** is a named container of mentions. Runs populate it with
posts collected across one or more search queries. Resources are
scoped to the account that owns the API key.
Dataset runs charge **1 credit per `mention` collected**, reservation-based —
any unused reservation is refunded on completion. See
[Pricing](/getting-started/pricing#reservation-based-charging).
## Endpoints [#endpoints]
### POST `/v1/datasets` [#post-v1datasets]
### GET `/v1/datasets` [#get-v1datasets]
### GET `/v1/datasets/{dataset_id}` [#get-v1datasetsdataset_id]
### PATCH `/v1/datasets/{dataset_id}` [#patch-v1datasetsdataset_id]
### DELETE `/v1/datasets/{dataset_id}` [#delete-v1datasetsdataset_id]
### POST `/v1/datasets/{dataset_id}/runs` [#post-v1datasetsdataset_idruns]
### GET `/v1/datasets/{dataset_id}/runs` [#get-v1datasetsdataset_idruns]
### GET `/v1/datasets/{dataset_id}/runs/{run_id}` [#get-v1datasetsdataset_idrunsrun_id]
## Search queries [#search-queries]
`POST /v1/datasets/{id}/runs` accepts a tagged-union `search_query`:
* **`{ "type": "prompt", "sources": [...], "search_query": "..." }`** —
keyword search across one or more of `reddit`, `tiktok`, `youtube`,
`instagram`, `linkedin`.
* **`{ "type": "url", "source_urls": [...] }`** — direct URL scraping;
supports the same sources via URL pattern.
Both variants accept optional `count`, `date_range`,
`num_comments_per_post`, `country_code`, `language`,
`enable_visual_recognition`, `enable_transcribing`, and
`content_analysis_actions`. See the schema above for exact bounds.
## Run lifecycle [#run-lifecycle]
`POST /v1/datasets/{id}/runs` returns immediately with
`status: "pending"`. Poll `GET /v1/datasets/{id}/runs/{run_id}` until
`status.type` is `completed` or `failed`. The status envelope reports
each pipeline step (`scraping`, `enrichment`, `analysis`) with
timestamps so you can render a progress UI.
When `status.type === "failed"`, the full credit reservation is
refunded. When `completed`, you are charged only for the mentions
that were collected.
## Read collected mentions [#read-collected-mentions]
Once a run reaches `completed`, query
[`POST /v1/mentions`](/api/endpoints/mentions) with the dataset's id
to read what it collected. Mentions live across runs — re-running a
dataset adds to the same pool.
## Next steps [#next-steps]
* [Mentions](/api/endpoints/mentions) — read the posts a run collected.
* [Pattern detections](/api/endpoints/pattern-detections) — discover
recurring narratives across a dataset.
* [Custom parameters](/api/endpoints/custom-parameters) — annotate
every post in a dataset with bespoke LLM-extracted fields.
# Account (me) (/api/endpoints/me)
The `me` endpoints describe the calling seat — its account, plan,
feature gates, balance, and a chronological feed of credit charges /
refunds.
Free — no credits charged. See
[Pricing](/getting-started/pricing) for the chargeable
categories that show up on `usage_history`.
## Endpoints [#endpoints]
### GET `/v1/me` [#get-v1me]
### GET `/v1/me/usage_history` [#get-v1meusage_history]
## What `/v1/me` returns [#what-v1me-returns]
The response carries:
* **Identity** — `id`, `account_id`, `email`, `name`, `team_name`.
* **`members[]`** — current team roster, each entry tagged as
`member` (joined) or `invitation` (pending).
* **`teams[]`** — every account the seat is a member of (in case
they belong to multiple teams).
* **`plan`** — `{ name, type, features, limits }`. Use
`plan.features.{api_access, mcp, webhooks, ...}` for feature gates
and `plan.limits.{num_seats, tracking_agents, projects, ...}` for
numerical caps.
* **`balance`** — current credit balance.
## Usage history [#usage-history]
`GET /v1/me/usage_history` is cursor-paginated. Each row carries a
category, the endpoint that produced the charge, and the delta in
credits (positive for charges, negative for refunds).
The category vocabulary is the three
[public categories](/getting-started/pricing) — `mention`,
`audience_profile`, `post_processing` — plus legacy strings
(`ai_assistant`, `REPORT`, `AUDIENCE_RESEARCH`, `TRACKING`) that only
appear on historical rows pre-dating the public surface.
Don't mistake the `ai_assistant` category for a charge on
[`POST /v1/ask`](/api/endpoints/ask) or its MCP equivalent. The
category belongs to the assistant in the **previous version of the
app**. Asking the assistant today is free everywhere — through the
API, through MCP, and in the current web app — so `ai_assistant`
shows up only on old rows, never on charges from your API or MCP
calls.
Usage history is reported at the account level — every seat sees
the same feed. Per-seat breakdowns will land via a dedicated audit
endpoint in a future revision.
## Next steps [#next-steps]
* [Pricing](/getting-started/pricing) — the three chargeable
categories.
* [`GET /v1/credit_prices`](/api/endpoints/credit-prices) — current
unit prices.
# Mentions (/api/endpoints/mentions)
The mentions endpoint is **global**: one call returns mentions from
every dataset owned by the calling account. Pass `dataset_ids` to scope
the search; omit it to span everything.
The body is `POST` (not query string) because filters are non-trivially
nested. The full request/response schema, examples, and integrated
playground are below — the prose that follows highlights the parts that
benefit from a longer explanation.
Free — no credits charged. The cost lives on the upstream
[dataset run](/api/endpoints/datasets) that collected the mentions.
See [Pricing](/getting-started/pricing).
## Endpoint [#endpoint]
## Filters [#filters]
`filters` is a list of *filter groups*. Each group is a list of single
filters. Groups are combined with **OR**, filters within a group with
**AND**. Maximum 10 filters total across all groups.
The full filter taxonomy:
| Type | Shape |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `keyword` | `{ "operator": "is" \| "is_not", "value": "..." }` — max 2 words. |
| `sentiment` | `{ "values": ["positive"\|"negative"\|"neutral"] }` |
| `metric_change` | `{ "metric": "likes"\|"views"\|"comments"\|"engagement_rate", "operator": { ... } }` — `operator` is one of `greater_than`, `less_than`, `in_range`, or `changed_by`. |
| `source` | `{ "values": ["reddit", ...] }` |
| `content_topic` | `{ "operator": "any_of", "values": [...] }` |
| `content_intention` | `{ "operator": "any_of", "values": [...] }` |
| `tone_of_voice` | `{ "operator": "any_of", "values": [...] }` |
| `hook` | `{ "operator": "any_of", "values": [...] }` |
| `cta` | `{ "operator": "any_of", "values": [...] }` |
| `mentioned_brands` | `{ "operator": { "type": "any_of"\|"equals"\|"contains", "values"/"value": ... } }` |
| `country_code` | `{ "values": ["US", "GB"] }` — uppercase ISO 3166-1 alpha-2. |
| `has_media` | `{ "value": true \| false }` |
| `dominant_emotion` | `{ "values": ["joy"\|"sadness"\|"anger"\|"fear"\|"surprise"\|"disgust"\|"neutral"] }` |
## Sort fields [#sort-fields]
`sort` accepts: `date`, `likes`, `engagement_rate`, `views`, `comments`,
`shares`, `sentiment_score`, `dataset_run_at`.
Cursors are sort-aware. When you change `sort` between calls, request a
fresh page rather than reusing a cursor from the previous sort — the
validator will reject a mismatched cursor.
## Reference types [#reference-types]
The `datasets` and `collections` arrays on each mention echo a small
subset of `references[]` types (see [Reference types](/api/reference-types)).
Comment bodies, when included, appear inline on the mention via `comments`;
they are not separate reference entries.
## Next steps [#next-steps]
* [Reference types](/api/reference-types) — how `references[]` and the
`post:source:id` markdown scheme work across the surface.
* [Mentions in MCP](/mcp/tools/reference) — the equivalent `mentions_*`
tool family for agent integrations.
# Pattern detections (/api/endpoints/pattern-detections)
A **pattern detection** is a one-shot async analysis of a dataset
that surfaces recurring narratives, hooks, or angles across many
mentions. The output is a [`Pattern`](/api/endpoints/patterns) — a
clustered set of `PatternItem`s, each grouping the underlying posts
that exemplify it.
Pattern detection charges **0.5 credits per `post_processing`** — one
charge per post in the dataset's most recent completed run.
Reservation-based: estimated up-front against the dataset's mention
count, refunded down to actuals on completion (full refund on failure).
See
[Pricing](/getting-started/pricing#reservation-based-charging).
## Endpoints [#endpoints]
### POST `/v1/pattern_detections` [#post-v1pattern_detections]
### GET `/v1/pattern_detections/{run_id}` [#get-v1pattern_detectionsrun_id]
## Lifecycle [#lifecycle]
`POST /v1/pattern_detections` returns immediately:
```json
{
"status": "success",
"data": {
"run_id": "pdr_01H...",
"status": "pending"
}
}
```
Poll `GET /v1/pattern_detections/{run_id}` until `status` is
`completed`. The completed response includes a `pattern_id`:
```json
{
"run_id": "pdr_01H...",
"status": "completed",
"pattern_id": "pt_01H..."
}
```
Resolve the pattern via
[`GET /v1/patterns/{pattern_id}`](/api/endpoints/patterns).
## Insufficient credits [#insufficient-credits]
Like other chargeable endpoints, returns `402 insufficient_credits` if
the account doesn't have enough credits to cover the projected cost
(`0.5 × posts_in_dataset`). No partial runs.
## Next steps [#next-steps]
* [Patterns](/api/endpoints/patterns) — read a discovered pattern.
* [Tracking agents](/api/endpoints/tracking-agents) — repeat the same
analysis on a schedule.
* [Reference types](/api/reference-types) — pattern detections show up
as `references[]` entries in assistant turns.
# Patterns (/api/endpoints/patterns)
A **pattern** is the artefact a
[pattern detection](/api/endpoints/pattern-detections) produces — a
named, clustered view of a dataset that groups posts by recurring
narrative or angle. Patterns are read-only on the API; create them
via pattern detections or via a [tracking agent](/api/endpoints/tracking-agents).
Free — no credits charged. The cost lives on the upstream
[pattern-detection](/api/endpoints/pattern-detections) or
[tracking-agent](/api/endpoints/tracking-agents) run that produced
the pattern. See [Pricing](/getting-started/pricing).
## Endpoints [#endpoints]
### GET `/v1/patterns/{pattern_id}` [#get-v1patternspattern_id]
### GET `/v1/patterns/{pattern_id}/items/{item_id}` [#get-v1patternspattern_iditemsitem_id]
## Shape [#shape]
`GET /v1/patterns/{id}` returns a top-level summary plus an `items[]`
array of `PatternItem` summaries. Each item carries:
* A short title and synopsis.
* A `post_count` (how many posts cluster into it).
* An `item_id` you can use to drill into the underlying posts.
`GET /v1/patterns/{pattern_id}/items/{item_id}` expands one item with
the full list of constituent posts. Use the
[mentions endpoint](/api/endpoints/mentions) with the returned
`post_refs` to fetch the post bodies.
## Pattern in `references[]` [#pattern-in-references]
Assistant turns sometimes cite a pattern under
[`references[]`](/api/reference-types) with
`{ "type": "pattern", "id": "pt_..." }`. Resolve via the endpoint
above.
## Next steps [#next-steps]
* [Pattern detections](/api/endpoints/pattern-detections) — how to
produce a pattern from scratch.
* [Tracking agents](/api/endpoints/tracking-agents) — patterns
produced on a schedule.
* [Mentions](/api/endpoints/mentions) — fetch the underlying posts via
`post_refs`.
# Research previews (/api/endpoints/research-previews)
A **research preview** is a cheap, capped sample of a search — a live
SERP/profile snapshot plus a volume estimate — so you can validate a
query before committing to a full [dataset run](/api/endpoints/datasets).
Each preview persists and can be retrieved later by id. Resources are
scoped to the account that owns the API key.
Previews charge **1 credit per source**, reservation-based. `url`
previews **refund** profiles that returned no data (private,
non-existing, or failed to retrieve). See
[Pricing](/getting-started/pricing#reservation-based-charging).
## Endpoints [#endpoints]
## Preview types [#preview-types]
`POST /v1/research_previews` accepts a tagged-union body discriminated
on `type`:
* **`{ "type": "prompt", "search_query": "...", "sources": [...] }`** —
keyword search across one or more of `reddit`, `tiktok`, `youtube`,
`instagram`, `linkedin`. Returns `estimated_number_of_results` and a
sample of `posts`.
* **`{ "type": "url", "source_urls": [...] }`** — direct profile/URL
scraping. Returns the `profiles` that resolved, plus
`failed_to_retrieve_profiles`, `non_existing_profiles`, and
`private_profiles` for the URLs that returned no data.
Both variants accept an optional time window, `language`, and
`country_code`. See the schemas above for exact fields and bounds.
## Time window (prompt) [#time-window-prompt]
A `prompt` preview takes **exactly one** time window — either a relative
`time_filter` **or** an absolute `date_since` + `date_until` pair, never
both and never neither. Supplying both, or an incomplete absolute pair,
fails validation with `422`. (`url` previews use `date_filter_since` /
`date_filter_until`.)
## Per-source pricing [#per-source-pricing]
Previews charge **1 credit per source**, held as a single reservation
up front and finalized to the billable count:
* **`prompt`** — `source_count = len(sources)` (the platforms searched).
All platforms are queried, so the full amount is charged; there is no
partial refund.
* **`url`** — `source_count = len(source_urls)` (each URL is a separate
scrape). Only the URLs that **return data** are billable: any URL that
is private, non-existing, or failed to retrieve is **refunded**. A
6-URL preview where 2 came back empty is charged 4.
If the request would exceed your balance, the endpoint returns
`402 insufficient_credits_research_preview` **before** any scraping —
you are never partially charged. If the scrape itself fails, the full
reservation is refunded.
## From preview to a dataset run [#from-preview-to-a-dataset-run]
A preview de-risks a run: check `estimated_number_of_results` (or the
returned `profiles`) and the sample before committing credits to a full
collection. When the shape looks right, launch a
[dataset run](/api/endpoints/datasets) with the **same** `search_query`
parameters (`sources` / `source_urls`, time window, `country_code`,
`language`) via `POST /v1/datasets/{dataset_id}/runs`.
Hold onto the returned `preview_id` to re-fetch the sample any time with
`GET /v1/research_previews/{preview_id}` — a **free** DB read (no
re-scrape), scoped to your account. A `preview_id` that belongs to
another account, or does not exist, returns `404`.
## Next steps [#next-steps]
* [Datasets](/api/endpoints/datasets) — commit a validated search to a
full, paid collection run.
* [Pricing](/getting-started/pricing) — the per-source model and
reservation-based charging behind previews.
# Tracking agents (/api/endpoints/tracking-agents)
A **tracking agent** is a long-running re-scrape + analysis schedule
attached to a dataset. Each cycle re-pulls fresh mentions, looks for
pattern drift, and emits messages summarising what changed.
Each re-scrape cycle charges per-mention as a normal dataset run
(`mention` category, reservation-based). Manual `trigger` calls
follow the same model. See
[Pricing](/getting-started/pricing#reservation-based-charging).
## Endpoints [#endpoints]
### POST `/v1/tracking_agents` [#post-v1tracking_agents]
### GET `/v1/tracking_agents` [#get-v1tracking_agents]
### GET `/v1/tracking_agents/{agent_id}` [#get-v1tracking_agentsagent_id]
### PATCH `/v1/tracking_agents/{agent_id}` [#patch-v1tracking_agentsagent_id]
### DELETE `/v1/tracking_agents/{agent_id}` [#delete-v1tracking_agentsagent_id]
### POST `/v1/tracking_agents/{agent_id}/pause` [#post-v1tracking_agentsagent_idpause]
### POST `/v1/tracking_agents/{agent_id}/resume` [#post-v1tracking_agentsagent_idresume]
### POST `/v1/tracking_agents/{agent_id}/trigger` [#post-v1tracking_agentsagent_idtrigger]
### GET `/v1/tracking_agents/{agent_id}/messages` [#get-v1tracking_agentsagent_idmessages]
## Lifecycle [#lifecycle]
An agent moves through three states:
* **`active`** — re-scrapes on the configured schedule, emits messages
for noteworthy changes.
* **`paused`** — no scheduled work; `POST .../resume` brings it back
online without losing history.
* **`deleted`** — soft delete. The agent and its message history are
hidden from list endpoints but retained on the server.
`POST .../trigger` forces an out-of-schedule cycle. It returns 402 if
the account has insufficient credits to cover the reservation.
## Messages [#messages]
`GET .../{id}/messages` returns the per-agent alert feed,
cursor-paginated, newest first. Each message has a `text` body (markdown
with inline post links — see [Reference types](/api/reference-types))
plus a `created_at` timestamp.
Pattern-detection alerts include a `pattern` reference under
`references[]`; expand via
[`GET /v1/patterns/{id}`](/api/endpoints/patterns).
## Next steps [#next-steps]
* [Pattern detections](/api/endpoints/pattern-detections) — the
one-shot equivalent of a tracking agent.
* [Datasets](/api/endpoints/datasets) — the dataset an agent re-scrapes.
* [Reference types](/api/reference-types) — how alert references
resolve to underlying resources.
# Tools reference (/mcp/tools/reference)
The MCP server exposes **15 tools**. They fall into two kinds:
* **The assistant flow** — `ask` → `get_message` → `render`. This is
where the work happens. `ask` hands a prompt to the buzzabout
assistant, which writes the search query, previews it, collects
posts, profiles audiences, detects patterns, and analyses — then
returns the answer as text or an interactive widget.
* **Read-only lookups** — list and fetch the datasets, runs, mentions,
audience profiles, and tracking agents the account already has.
There are no create / update / delete tools. Anything that **makes**
or **runs** something — collecting a dataset, profiling an audience,
detecting patterns — happens through `buzzabout__ask`. The read tools
only surface what already exists. (Programmatic CRUD lives on the
[REST API](/api/overview).)
All tools require auth — see [Authentication](/mcp/auth). Both
`x-api-key` and OAuth/JWT callers can use every tool, including `ask`.
## The assistant flow: `ask` → `get_message` → `render` [#the-assistant-flow-ask--get_message--render]
`ask` is asynchronous — research can run for minutes, past a host's
tool-call timeout — so it returns immediately with an id, and you poll
`get_message` for the answer.
### `buzzabout__ask` [#buzzabout__ask]
Hand a prompt to the assistant. Returns right away; does **not** wait
for the answer.
| Field | Type | Required | Notes |
| ------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `prompt` | string | yes | Free-form question or instruction. |
| `chat_id` | string | no | Continue a prior chat. Omit to start fresh. |
| `dataset_ids` | string\[] | no | Scope the assistant to specific datasets. A fresh chat has none linked — pass these when the question is about a known dataset. |
| `post_refs` | `{ id, source }[]` | no | Pin specific posts as context (cap 50). |
```json
{
"chat_id": "01H...",
"message_id": "01H...",
"status": "working"
}
```
Keep the `chat_id` to continue the conversation; pass `chat_id` +
`message_id` to `get_message` to retrieve the answer.
### `buzzabout__get_message` [#buzzabout__get_message]
Poll for the answer to an `ask`. **Long-polls** — one call holds for up
to \~45s, returning the moment the turn settles, so you call it
back-to-back rather than waiting between calls.
| Field | Type | Required |
| ------------ | ------ | -------- |
| `chat_id` | string | yes |
| `message_id` | string | yes |
```json
{
"chat_id": "01H...",
"message_id": "01H...",
"status": "working", // or "completed" / "failed"
"stop_reason": null, // non-null once finished
"blocks": [
{ "block_id": "b1", "type": "text", "render": false, "text": "...markdown..." },
{ "block_id": "b2", "type": "openui", "render": true }
]
}
```
`blocks` arrive only once the turn settles. Walk them in order: a
`render: true` block is an interactive widget — call `render`; a
`render: false` block already carries its `text` — relay it to the user
as-is.
If a run is genuinely long and you're low on tool calls, stop polling
and tell the user — the chat is saved, and you (or they, next turn) can
resume with the same `chat_id` + `message_id`.
### `buzzabout__render` [#buzzabout__render]
Render one `render: true` block as an interactive **MCP App** widget
(hosts that support the `io.modelcontextprotocol/ui` extension). Bound
to the `ui://buzzabout/message` UI resource.
| Field | Type | Required |
| ------------ | ------ | -------- |
| `message_id` | string | yes |
| `block_id` | string | yes |
Returns the block's OpenUI as `structuredContent` the host renders
natively. Only call it on `render: true` blocks — a `render: false`
block has no widget to draw.
Hosts **without** the MCP Apps extension can't draw widgets. For them
the assistant returns the answer as plain markdown (relayed via
`get_message`), so no `render` call is needed.
## Read-only lookups [#read-only-lookups]
These look up entities the account already owns — they never create or
charge. All `list_*` tools are cursor-paginated (see below).
### Datasets [#datasets]
| Tool | Required parameters | Returns |
| ---------------------------- | ---------------------- | -------------------------------- |
| `buzzabout__list_datasets` | — | `{ content: Dataset[], cursor }` |
| `buzzabout__get_dataset` | `dataset_id` | `Dataset` or `{ error }` |
| `buzzabout__get_dataset_run` | `dataset_id`, `run_id` | `DatasetRun` (status envelope) |
### Audience [#audience]
| Tool | Required parameters | Returns |
| ------------------------------------- | ------------------------------- | ---------------------------------------- |
| `buzzabout__list_audience_datasets` | — | `{ content: AudienceDataset[], cursor }` |
| `buzzabout__get_audience_dataset` | `audience_dataset_id` | `AudienceDataset` |
| `buzzabout__get_audience_dataset_run` | `audience_dataset_id`, `run_id` | `AudienceDatasetRun` (status envelope) |
| `buzzabout__list_audience_profiles` | — | `{ content: Profile[], cursor }` |
`list_audience_profiles` defaults to all account-owned audience
datasets. Mirrors [POST /v1/audience\_profiles](/api/endpoints/audience-profiles).
### Mentions [#mentions]
| Tool | Required parameters | Returns |
| -------------------------- | ------------------- | -------------------------------- |
| `buzzabout__list_mentions` | — | `{ content: Mention[], cursor }` |
Defaults to all account-owned datasets; pass `dataset_ids` to narrow.
Filters, sort, order, cursor, limit mirror the
[REST mentions endpoint](/api/endpoints/mentions).
### Patterns [#patterns]
| Tool | Required parameters | Returns |
| -------------------------------------- | ------------------- | ------------------------------------------------ |
| `buzzabout__get_pattern_detection_run` | `run_id` | `{ run_id, status, pattern_id }` (polling shape) |
Pattern detection is **started** through `ask`; this read polls a run's
status. The pattern's content flows back through the assistant.
### Tracking agents [#tracking-agents]
| Tool | Required parameters | Returns |
| --------------------------------- | ------------------- | -------------------------------------- |
| `buzzabout__list_tracking_agents` | — | `{ content: TrackingAgent[], cursor }` |
| `buzzabout__get_tracking_agent` | `agent_id` | `TrackingAgent` |
### Account [#account]
| Tool | Required parameters | Returns |
| ------------------- | ------------------- | ------------------------------------------------- |
| `buzzabout__get_me` | — | `User` with `account`, `plan`, `members`, `teams` |
## Pagination model [#pagination-model]
All `list_*` tools return:
```json
{
"content": [ /* rows */ ],
"cursor": "eyJ...="
}
```
Pass the cursor back as the `cursor` argument to fetch the next page. A
`null` cursor means you've hit the end. Cursors on filtered list
endpoints (mentions, audience profiles) encode the sort dimension, so
don't reuse a cursor across `sort` changes.
## Polling runs [#polling-runs]
Two things to poll, both covered above:
* **An `ask` turn** → `get_message` (long-polls; settles at
`stop_reason` non-null).
* **An existing run's status** → the matching `get_*_run`
(`get_dataset_run`, `get_audience_dataset_run`,
`get_pattern_detection_run`) until `status.type` is `completed` or
`failed`. These carry the same status envelope as the REST API:
```json
{
"status": {
"type": "working",
"steps": [ { "name": "scraping", "completed_at": 1714564890 } ]
}
}
```
## Error shape [#error-shape]
Tool errors come back as a JSON object with an `error` field — same
`error_code` taxonomy as the REST API:
```json
{
"error": {
"code": "dataset_not_found",
"message": "Dataset not found",
"status": 404
}
}
```
Match on `code` (stable); show `message` to humans. `status` mirrors
the HTTP status the equivalent REST call would return.
## Next steps [#next-steps]
* [Use in your agent](/mcp/use-in-your-agent) — wire MCP into Claude,
Claude Code, Codex, Cursor, ChatGPT, or your own SDK.
* [Reference types](/api/reference-types) — how `references[]` and
inline post links resolve.
* [API reference](/api/overview) — the REST surface, including
programmatic CRUD.