Prompt set design: build a prompt set worth monitoring
A prompt set is the fixed, versioned list of questions your AI-visibility monitoring asks, and every metric computed from the answers inherits its choices. A set of questions nobody asks produces precise numbers that mean nothing. Below: sourcing prompts, clustering by intent, phrasing, sizing, cost and versioning, with code that mines candidate prompts through the API.
What a prompt record contains
Treat each prompt as a record, not a string:
| Field | Example | Why |
|---|---|---|
id |
cmp-014 |
Stable key for trends and idempotency keys |
text |
hubspot vs pipedrive for a 10-person sales team |
Exact wording; any edit makes a new prompt |
cluster |
comparison |
Metrics are reported per cluster |
markets |
US |
Sent as country; ChatGPT and Gemini answer from 213 countries, Copilot, Perplexity and Grok from any |
engines |
CHATGPT, GEMINI |
Not every prompt belongs on every engine |
source |
sales-calls-2026-q3 |
Lets you audit bias in the set |
added / retired |
2026-09-20 / empty |
Version history |
Store the set in version control (CSV or YAML) and tag the version used for every run.
Step 1: source prompts from real demand
Prompts should sound like buyers, not like a keyword tool. Collect candidates from several sources, then filter.
- Sales calls, demos and support tickets. The best source, because it holds the exact phrasing of people who bought or nearly bought. Pull the questions asked before a purchase decision.
- On-site search and chat logs. What visitors type when your navigation fails them.
- People Also Ask and related searches.
POST /v1/monitor/googlereturnsresult.peopleAlsoAsk[].questionandresult.relatedSearches[].queryfor a seed query in a chosen market. Mining People Also Ask covers the technique in depth. - AI engines’ own fan-out. ChatGPT’s
result.searchQueries(withinclude.searchQueries, which is free) comes back empty on the answers served today, so it gives no candidates (query fan-out). - Community threads. Titles of forum threads in your category are questions real people typed. Google’s “What people are saying” module comes back as
result.peopleAreSaying[].titlewhen it appears.
Mine candidates with the API
import os, requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['ANSWERLINE_API_KEY']}"}
def post(path: str, body: dict) -> dict:
r = requests.post(f"{API}{path}", json=body, headers=HEADERS, timeout=360)
r.raise_for_status()
return r.json()["result"]
def normalize(q: str) -> str:
return " ".join(q.lower().strip(" ?").split())
def candidates(seed: str, country: str = "US") -> dict[str, set[str]]:
found: dict[str, set[str]] = {}
serp = post("/v1/monitor/google", {"query": seed, "country": country})
for q in [p.get("question", "") for p in serp.get("peopleAlsoAsk", [])]:
found.setdefault(normalize(q), set()).add("paa")
for q in [r.get("query", "") for r in serp.get("relatedSearches", [])]:
found.setdefault(normalize(q), set()).add("related")
for q in [c.get("title", "") for c in serp.get("peopleAreSaying", [])]:
found.setdefault(normalize(q), set()).add("discussions")
found.pop("", None)
return found
These are synchronous calls, which is fine for a handful of seeds. Per seed at the Starter tier, a one-page Google Search call costs $0.00103. Twenty seeds cost $0.0206. For larger mining runs, submit tasks (sync, async and webhooks).
A candidate found by several sources (for example both PAA and related searches) is likely a recurring question. Related searches are search strings, not prompts: rewrite them as a person would ask the engine before adding them.
Step 2: cluster by intent, not keyword
Group prompts by what the asker wants, because each cluster fails for different reasons and needs a different fix.
| Cluster | Pattern | Example | What it measures |
|---|---|---|---|
| Category | best X for Y | best CRM for a small agency | Unprompted recommendation |
| Comparison | X vs Z, alternatives to X | pipedrive vs hubspot for startups | Presence when a competitor is named |
| Problem | how to solve P | how to stop leads going cold after a demo | Whether you are the answer to the job |
| Branded | is |
is |
Accuracy of what engines say about you |
| Local | X near Y, X in city | payroll accountant in Austin | Market- and state-level presence |
Report each cluster separately. A strong branded cluster with a weak category cluster means engines describe you correctly but do not recommend you, a different problem from the reverse. Gemini takes a US state; on ChatGPT, which answers at country level, local prompts need a local phrasing; see state-level AI answers.
Step 3: phrase prompts the way buyers type them
- Fix the exact text. “best earbuds” and “what are the best earbuds” are different samples. Never edit a live prompt; retire it and add a new id.
- Write as a person asks. “best crm small agency” is a search string. “What’s the best CRM for a small marketing agency?” is a prompt.
- Keep non-branded prompts neutral. Do not name yourself, and do not add qualifiers that only you satisfy.
- Include the constraints buyers state. Team size, budget, industry and integration needs change which products get named. Split them into separate prompts rather than stuffing them into one.
- Localize the wording as well as
country. For a non-English market, write the prompt in that market’s language as a buyer there would ask it (multilingual AI answers). - Add paraphrase groups deliberately. If you want to know how sensitive answers are to wording, add two or three paraphrases of a few core prompts under a shared group id, and report them as a sensitivity check, not as extra coverage.
Step 4: size the set
A rate computed over a prompt set is a proportion, and its worst-case 95% margin of error from n prompts is 1.96 × √(0.25 / n): about ±18 points at 30 prompts, ±10 at 100, ±7 at 200. That margin applies per reported cell (engine × market × cluster), so the number of prompts you need grows with the number of ways you slice the report.
- Minimum: about 30 prompts across your core clusters, one market, one or two engines. Enough to see direction and catch large changes.
- Reported program: 100 or more prompts per cell you report on, across your top markets and engines.
- Repetition first: a stable set run every week is worth more than a larger set run once, because a trend needs the same questions asked repeatedly.
Repeated runs of each prompt matter too, because answers vary between runs; sampling vs census covers how to split a budget between more prompts and more runs.
Worked cost example
From the billing docs, requests cost ChatGPT $0.0006 and Gemini $0.0006 at the Starter tier. A 60-prompt set on those two engines in one market is 60 × $0.0012 = $0.072 per weekly run, about $0.288 over four weeks. Each market you add multiplies that. See pricing for the tiers and cost planning for budgeting.
Step 5: run it and key everything by prompt id
Submit the set as an async batch with idempotency keys built from prompt id, engine, market and run date. The key then doubles as the join key between the stored answer and the prompt record.
import { Client } from "@answerline/sdk";
type PromptRecord = { id: string; text: string; cluster: string; markets: string[]; engines: ("CHATGPT" | "GEMINI")[] };
const client = new Client({ apiKey: process.env.ANSWERLINE_API_KEY! });
const setVersion = "v7";
const day = new Date().toISOString().slice(0, 10);
export async function runSet(prompts: PromptRecord[]) {
const tasks = prompts.flatMap((p) =>
p.markets.flatMap((country) =>
p.engines.map((taskType) => ({
taskType,
payload: { prompt: p.text, country },
idempotencyKey: `${setVersion}:${p.id}:${taskType}:${country}:${day}`,
webhook: { url: "https://example.com/hooks/answerline" },
})),
),
);
for (let i = 0; i < tasks.length; i += 500) {
const batch = await client.createBatch(tasks.slice(i, i + 500));
for (const item of batch.results) {
if (!item.success && item.error.code !== "RESOURCE_ALREADY_EXISTS") console.warn(tasks[i + item.index].idempotencyKey, item.error.code);
}
}
}
When results arrive, the share-of-voice framework turns them into metrics per cluster.
Step 6: version and refresh without breaking trends
- Core set: the prompts you report trends on. Wording never changes. Retire a prompt only when the question no longer exists (a discontinued product, a renamed category).
- Exploration set: new candidates run for a few cycles alongside the core. Promote a prompt once it has proven relevant, and start its trend line from the promotion date.
- Quarterly review: add prompts for new competitors, product lines and markets; retire dead ones; record the reason for each change.
- Report the version with every number. A rate from set v6 and a rate from set v7 are comparable only on the prompts they share.
Pitfalls
- Keyword strings instead of questions. They measure how engines handle search syntax, not how buyers ask.
- Branded prompts in category metrics. Naming yourself inflates mention rate.
- Sourcing only from queries you already rank for. The set then confirms existing strength and hides gaps.
- One blended rate. Clusters with opposite trends cancel out.
- Silent edits. Changing a word mid-series creates a step change that looks like an engine change.
- Too many prompts run once. Breadth without repetition gives no trend.
Start with the quickstart, and see the keyword research use case for the discovery side of this work.
Questions
What is a prompt set in AI visibility monitoring?
A fixed, versioned list of prompts, each with an id, exact wording, intent cluster and target markets, that you run on a schedule across AI engines. Every metric you report is computed over it, so it defines what the metric means.
How many prompts should I monitor?
About 30 prompts across your core intents are enough to see direction in one market. For a rate you report per engine and market with a margin of about plus or minus 10 points, plan on roughly 100 prompts per reported cell.
Where do good monitoring prompts come from?
From how buyers ask: sales call notes, support tickets, on-site search, Google's People Also Ask questions and related searches, and the titles of community threads in your category.
Should I include my brand name in prompts?
Only in the branded cluster. Category, comparison and problem prompts should not name you, otherwise they measure recall of a name you supplied rather than whether the engine recommends you unprompted.
How often should a prompt set change?
Review it quarterly and version every change. Keep a stable core that never changes wording so trends stay comparable, and test new prompts in a separate exploration set before promoting them.