AnswerLine Start free

, GEO · Brand Monitoring · Fundamentals

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.

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 good for, pricing is good for agencies 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

  1. 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.
  2. 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.
  3. Keep non-branded prompts neutral. Do not name yourself, and do not add qualifiers that only you satisfy.
  4. 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.
  5. 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).
  6. 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.

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.

Pitfalls

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.

Try it on your own prompts

100 free requests on any engine, no card. One POST returns the answer, sources and citations as JSON.

Keep reading