# Track your brand in AI answers

> Measure how ChatGPT, Gemini, Copilot, AI Mode and Brave answer about your brand: prompt sets, track and mentions, batches, monitors and run-to-run variance.

AI visibility (also called GEO, generative engine optimisation) asks a simple question: when someone asks an AI assistant about your category, does the answer name you, cite your site, or show your products? The [AI assistant endpoints](https://serpkite.com/docs/ai-assistants) answer it with data. Each call asks one assistant one prompt as a logged-out visitor, and `track` checks the answer for your brands and domains.

The workflow:

1. Write a **prompt set**: the questions your buyers ask.
2. Run it across assistants and countries with **batches**, several times each.
3. Read **`mentions`** and the **sources** to measure share of answers and which pages get cited.
4. Save the prompts that matter as **monitors** to follow visibility over time.

## Write a prompt set

Use the questions people actually ask, in their words, not your product name:

- Category questions: "What are the best CRMs for a 10-person startup?"
- Comparisons: "HubSpot vs Pipedrive for a small sales team"
- Problems: "How do I stop deals slipping through the cracks in a spreadsheet?"
- Local and shopping questions, which bring back `places` and `products`: "best espresso machine under $500"

Keep the set stable once you start measuring, so runs stay comparable. A prompt can be up to 4,000 characters.

## Track brands and domains

Send up to 20 terms in `track`. A term with a dot (`hubspot.com`) is a **domain**: it matches sources and product links on that domain and its subdomains, and the answer text when it names the domain. Any other term (`Pipedrive`) is a **brand**: it matches whole words in the answer text, source titles and domains, and product titles, brands and merchants, ignoring case. Track a brand and its domain separately when you want both signals.

cURL:

```bash
curl https://api.serpkite.com/v1/chatgpt \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"What are the best CRMs for a 10-person startup?","track":["hubspot.com","HubSpot","Pipedrive","pipedrive.com"]}'
```

TypeScript:

```ts
import { SerpKite } from "serpkite";

const sk = new SerpKite(); // reads SERPKITE_API_KEY
const res = await sk.chatgpt({ prompt: "What are the best CRMs for a 10-person startup?", track: ["hubspot.com","HubSpot","Pipedrive","pipedrive.com"] });
console.log(res.markdown);
for (const m of res.mentions ?? []) console.log(m.term, m.mentioned, m.cited, m.sources);
```

Python:

```python
from serpkite import SerpKite

sk = SerpKite()  # reads SERPKITE_API_KEY
res = sk.chatgpt(prompt="What are the best CRMs for a 10-person startup?", track=["hubspot.com","HubSpot","Pipedrive","pipedrive.com"])
print(res.markdown)
for m in res.mentions or []:
    print(m.term, m.mentioned, m.cited, m.sources)
```

Each term comes back in `mentions`, in the order you sent them:

```json
"mentions": [
  { "term": "hubspot.com", "mentioned": false, "cited": true, "sources": [2], "text_position": -1 },
  { "term": "HubSpot", "mentioned": true, "cited": true, "sources": [2], "text_position": 0.041 },
  { "term": "Pipedrive", "mentioned": true, "cited": false, "sources": [], "text_position": 0.071 },
  { "term": "pipedrive.com", "mentioned": false, "cited": false, "sources": [], "text_position": -1 }
]
```

| Field | Meaning |
| --- | --- |
| `mentioned` | The answer text names the term. |
| `cited` | A source the answer cites inline matches the term. |
| `sources` | Positions of every matching source, cited or only listed. Look them up in `sources[]`. |
| `products` | Positions of matching product cards, when the answer showed any. |
| `text_position` | Where the text first names the term: `0` is the first words, `1` the end, `-1` not named. Earlier usually means more prominent. |

Named but not cited means the assistant knows you but grounded its answer elsewhere; cited but not named means your page informed the answer without your brand getting credit. The `sources` list tells you which pages do get cited, which is often the most useful part: those are the pages to earn a place on.

With `format: "markdown"`, the answer ends with a **Mentions** section in plain words ("named and cited", "listed as a source", "not mentioned"), which is handy for an agent or a report.

## Run the prompt set with batches

Queue up to 100 prompts per call with [`POST /v1/batches`](https://serpkite.com/docs/batch). Every request in a batch goes to one endpoint, so send one batch per assistant. AI answers keep their full price in a batch (ChatGPT 4, Gemini 3, Copilot Search 3, Google AI Mode 2 and Brave AI 2 credits); the batch lane spares you from holding 100 requests open for a minute each, and delivers every answer to a signed webhook.

```bash
curl https://api.serpkite.com/v1/batches \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "chatgpt",
    "requests": [
      { "prompt": "What are the best CRMs for a 10-person startup?", "track": ["hubspot.com", "Pipedrive"], "country": "us" },
      { "prompt": "What are the best CRMs for a 10-person startup?", "track": ["hubspot.com", "Pipedrive"], "country": "gb" },
      { "prompt": "HubSpot vs Pipedrive for a small sales team", "track": ["hubspot.com", "Pipedrive"], "country": "us" }
    ],
    "webhook_url": "https://example.com/hooks/serpkite"
  }'
```

Repeat the same batch for `gemini`, `copilot`, `ai_mode` and `brave_ai`. Each finished job arrives as a `batch.completed` webhook (or poll `GET /v1/batches/{id}`), with the answer in the job's `result`, shaped like the realtime response. See [Webhooks](https://serpkite.com/docs/webhooks).

A batch reruns a prompt only if you send it again: results are cached for at most an hour, and only a request with `max_age` reads the cache, so repeated prompts are asked live.

## Read the variance

Assistants are not deterministic. The same prompt can name three brands in one run and five in the next, cite different pages, or skip web search. Answers also differ by country: ChatGPT and Gemini localise to the visitor's location, Copilot Search and Brave answer for the market you set, and AI Mode for the country it is asked from (we prefer the `country` you send). So measure rates, not single answers:

- **Sample each prompt several times** (five or more per assistant and country is a reasonable start) and at different times of day.
- **Share of answers:** the fraction of runs where `mentioned` is true. Compute it per prompt, per assistant and per country.
- **Citation share:** the fraction of runs where `cited` is true, and which of your URLs appear in `sources`.
- **Prominence:** the median `text_position` over the runs that name you.
- **Competitors:** track them in the same call and compare their rates to yours.

Treat a change of a few points between two small samples as noise. Trends over weeks, from monitors, are more reliable than any single day.

## Follow it over time with monitors

A monitor with an AI assistant `endpoint` asks its `prompt` every run and reports **every** answer, not only changes, so each run is one sample in your time series.

```bash
curl https://api.serpkite.com/v1/monitors \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "chatgpt",
    "prompt": "What are the best CRMs for a 10-person startup?",
    "track": ["hubspot.com", "Pipedrive"],
    "country": "us",
    "interval": "daily",
    "name": "CRM shortlist · ChatGPT US",
    "webhook_url": "https://example.com/hooks/serpkite"
  }'
```

AI assistant monitors take `prompt`, `country`, `language` (not chatgpt), `web_search` (chatgpt) and `track`; search options such as `q`, `num` or `engine` are rejected. Each run's result is one answer object: `text`, `markdown`, `model`, `sources`, `new_sources` (links not cited or listed in earlier runs), `search_queries`, `products` and, with `track`, `mentions`. Read it from `GET /v1/monitors/{id}/runs`, or take the signed `monitor.results` webhook, which carries `prompt` instead of `q` and the run's answer as the single item of `new_results`. See [Scheduled monitoring](https://serpkite.com/docs/guides/scheduled-monitoring).

Each run costs the endpoint's price, and failed runs are free. A daily ChatGPT monitor costs 4 × 30 = 120 credits a month; a daily Brave AI monitor 60. Monitor history keeps result bodies for 24 hours, so store the answers you need.

## Budget

A prompt set of 50 prompts, asked 5 times on each of the five assistants in one country, is 250 answers per assistant: 3500 credits in all. Start with one or two assistants and a handful of prompts, check the answers look the way you expect, then scale up. Set a [spend cap](https://serpkite.com/docs/spend-controls) or a dedicated [API key](https://serpkite.com/docs/api-keys) with a monthly limit for recurring runs.

## Next steps

- [AI assistants](https://serpkite.com/docs/ai-assistants): Which assistants answer, what they return and how we ask.
- [ChatGPT reference](https://serpkite.com/docs/endpoints/chatgpt): Parameters, response fields and errors of /v1/chatgpt.
- [Monitors reference](https://serpkite.com/docs/endpoints/monitors): Schedules, run history and monitor.results webhooks.
- [Batch requests](https://serpkite.com/docs/batch): Queue up to 100 requests per call, results by webhook.