White-label AI visibility: client-facing answer tracking
Agencies and SEO platforms can report whether clients show up in ChatGPT and Gemini answers inside their own product, under their own brand, without collecting answers themselves: the backend calls an API, stores structured answers, and dashboards and reports are built on that data. Below: what to build, the multi-tenant architecture, TypeScript for scheduling and collecting per-client runs, cost attribution, and the terms and pitfalls to know before selling it.
Definition
White-label AI visibility is AI answer monitoring offered under an agency’s or platform’s own brand, where a third-party API performs the answer collection and returns structured data that the provider turns into client-facing dashboards, reports and alerts.
The division of labor:
| Layer | Who owns it |
|---|---|
| Client relationship, prompt strategy, recommendations | You |
| Dashboards, reports, alerts, client portal | You |
| Prompt sets, schedules, metrics, history | You (your database) |
| Running prompts on engines and returning answers as JSON | The API |
What you can sell
- Client dashboards. Per-client prompt sets with mention rate, citation share and competitor columns per engine and market, trended over weeks. The AI share of voice framework defines the metrics.
- Scheduled reports. A weekly or monthly job computes changes and renders a PDF or email. An AI visibility report template gives a layout.
- Pre-sales audits. Run a prospect’s category and comparison prompts before the pitch and show where competitors are named and they are not.
- Alerts. Notify an account manager when a client drops out of an answer they held, or a competitor appears. Brand crisis monitoring covers alert design.
- A platform module. SEO and content platforms can add an “AI answers” tab next to rank tracking, fed from the same keyword-to-prompt mapping. See extending an SEO program to AI answers.
What the data gives a client report
Each completed answer arrives as JSON under result. The fields that matter for client work:
| Report element | Field | Engines |
|---|---|---|
| Verbatim answer to quote | text, markdown (with include.markdown) |
All assistants and AI Mode |
| Who is cited | sources[] (url, label, position) |
All assistants and AI Mode |
| Inline citation placement | citationPills[] |
ChatGPT, Perplexity, Gemini, Copilot, AI Mode |
| Brands named | entities[] (type, name) |
ChatGPT |
| Why the answer said it | searchQueries[] |
ChatGPT (with include.searchQueries; empty today), Grok; coming on Copilot |
| Products recommended | entities[] (type product), inlineProducts[] (with include.shopping: price, link and merchant offers) |
ChatGPT (shoppingCards[] comes back empty today); shopping fields on other engines vary |
| Ads shown | ads[] with rendered |
ChatGPT (with include.ads; empty today) |
| Local businesses | places[] / map[] |
Varies by engine |
| Google AI Overview | aioverview (text, sources[]) |
Google Search with include.aioverview |
ChatGPT’s searchQueries[] and ads[] come back empty on the answers served today; on engines without entities[], find brand names in text. For reports, label every quoted answer with its engine, market and collection date: answers vary between runs, and a client comparing your report to their own screen on another day will see differences.
Multi-tenant architecture
One API account, many clients. The pieces:
- Tenant and prompt tables. Each client has prompt sets, each prompt a stable ID, engines, markets (
country; ChatGPT, Gemini, AI Mode and Google Search answer from 213 countries, Copilot, Perplexity and Grok take any country, and Gemini also takes a US state) and a cadence. - Scheduler. For each due client, build tasks and submit them with
POST /v1/async/task/batch(up to 500 tasks per call). - Idempotency keys that carry the tenant. A key like
t42-p117-CHATGPT-US-2026-09-16makes retries safe and lets the webhook handler route the result without a lookup. Keys are unique across your account, and the finished task echoestask.idempotencyKey. - Webhook receiver. Verifies the signature, stores the raw JSON and
credits.creditsChargedagainst the tenant, and acknowledges within 15 seconds. - Metrics job. Computes per-tenant metrics from stored answers, so every number traces back to a response.
- Presentation. Dashboards and reports read only your database; the API key never reaches a browser.
Scheduling a client run
TypeScript with the @answerline/sdk package:
import { Client, type TaskInput } from "@answerline/sdk";
const client = new Client({ apiKey: process.env.ANSWERLINE_API_KEY! });
type Prompt = { id: string; text: string; country: string };
type Tenant = { id: string; prompts: Prompt[]; engines: Array<"CHATGPT" | "GEMINI"> };
function buildTasks(tenant: Tenant, day: string): TaskInput[] {
return tenant.prompts.flatMap((p) =>
tenant.engines.map((engine) => ({
taskType: engine,
payload: { prompt: p.text, country: p.country },
idempotencyKey: `t${tenant.id}-p${p.id}-${engine}-${p.country}-${day}`,
webhook: { url: "https://reports.your-agency.example/hooks/answers" },
})),
);
}
export async function runTenant(tenant: Tenant, day: string) {
const tasks = buildTasks(tenant, day);
for (let i = 0; i < tasks.length; i += 500) {
const chunk = tasks.slice(i, i + 500);
const batch = await client.createBatch(chunk);
for (const item of batch.results) {
if (item.success) continue;
// RESOURCE_ALREADY_EXISTS means this task was already submitted today: safe to ignore.
if (item.error.code !== "RESOURCE_ALREADY_EXISTS") {
console.warn(chunk[item.index].idempotencyKey, item.error.code);
}
}
}
}
Collecting results per tenant
The webhook body is the same JSON GET /v1/async/task/{taskId} returns. Verify the raw bytes before parsing, then route by the tenant prefix in the idempotency key:
import express from "express";
import { verifyWebhook } from "@answerline/sdk";
const app = express();
app.post("/hooks/answers", express.raw({ type: "application/json" }), async (req, res) => {
if (!(await verifyWebhook(req.body, req.get("webhook-signature"), process.env.WEBHOOK_SECRET!))) {
return res.sendStatus(400);
}
const delivery = JSON.parse(req.body.toString("utf8"));
if (delivery.test) return res.sendStatus(204); // dashboard test delivery
const { task, credits, response } = delivery;
const tenantId = /^t([^-]+)-/.exec(task.idempotencyKey ?? "")?.[1];
if (!tenantId) return res.sendStatus(204);
// Upsert by task.id: deliveries can repeat and arrive out of order.
await saveAnswer({
taskId: task.id,
tenantId,
key: task.idempotencyKey,
status: task.status, // COMPLETED or FAILED
creditsCharged: credits.creditsCharged ?? 0,
result: task.status === "COMPLETED" ? response?.result : null,
});
res.sendStatus(204);
});
declare function saveAnswer(row: Record<string, unknown>): Promise<void>;
Deliveries are retried up to 10 times with increasing waits when your endpoint fails, and the same task can be delivered more than once, which is why the handler upserts by task.id. Webhook reliability design covers buffering and replays.
Cost attribution and economics
Cost per task
At the Starter tier:
| Engine and options | Cost |
|---|---|
| ChatGPT | $0.0006 (every include flag free) |
| Gemini | $0.0006 |
| Perplexity | $0.0015 |
| Copilot | $0.00274 |
| Grok | $0.00218 |
| Google AI Mode | $0.00206 |
| Google Search | $0.00103, +$0.00071 per page beyond the first, +$0.00071 with include.aioverview |
| Google News | $0.0002, pages beyond the first free |
A task reserves its maximum cost at creation (credits.creditsToCharge, in dollars) and is charged the actual cost when it completes (credits.creditsCharged). Failed tasks are not charged. Store creditsCharged per tenant and you have exact cost per client.
Example client
A client with 40 prompts on ChatGPT ($0.0006) and Gemini ($0.0006) costs $0.0012 per prompt per run: $0.048 per weekly run and $0.192 over four runs. Fifteen such clients use $2.88 over four weekly runs. A pre-sales audit of 20 prompts on ChatGPT and Gemini is $0.024.
To price a module, compare your cost per client, at your tier’s prices on the pricing page, with what you charge. The balance is shared across the account, so read GET /v1/credits (remaining, your balance in dollars) before each scheduled wave and hold back low-priority runs when the balance is short, or turn on auto top-up in the dashboard. Cost planning covers budgeting.
Sharing capacity fairly between clients
All clients share the account’s queue and balance. Three controls help:
priority(1 to 10, higher first) on each task. Give on-demand audits a higher priority than overnight scheduled runs so a salesperson is not waiting behind a client’s weekly batch.GET /v1/async/statusshowsqueuedTasks,processingTasks, apriorityBreakdown, and how many tasks are pending.DELETE /v1/async/queueremoves every still-QUEUEDtask (never charged), useful when a misconfigured schedule submits far too much. It is account-wide, not per tenant.
A submission that would exceed your pending-task limit is rejected whole with 429 QUEUE_LIMIT_EXCEEDED, so stagger large tenants across the night rather than submitting everything at once. See rate limits.
Access, terms and security
- Keys stay server-side. A key grants every endpoint and spends the account’s balance. Create and revoke keys on the API keys page of the dashboard; a revoked key stops working within a minute. Use separate keys per service so you can rotate one without downtime.
- Team access. Invite colleagues to the account from the dashboard’s team page instead of sharing a login.
- Terms. The terms of service prohibit reselling raw access to the API without a written agreement, and misrepresenting results as coming directly from a third-party service. Building your own product, analysis and reports on the data is the intended use; if your plan is to expose API access itself to customers, arrange an agreement first.
- Third-party terms. The engines’ own terms may restrict how their content is used; complying with them is your responsibility, as the terms of service note.
Build it yourself or run on an API
Collecting answers in-house means maintaining automation for every engine, geo-targeting, parsers that break when interfaces change, and job scheduling. Build vs buy for AI visibility and the build vs buy comparison walk through the trade-off. For agencies, the question is whether engineering time goes into collection infrastructure or into the client-facing product.
Getting there in a week
- Day 1: follow the quickstart; run one client’s top 10 prompts synchronously and read the JSON.
- Day 2: create the tenant and prompt tables; write the key format.
- Day 3: submit the client’s set as an async batch with a webhook; store raw answers and charged dollars.
- Day 4: compute mention rate and citation share per engine; compare with a manual reading of a few answers.
- Day 5: render the first report and review it with the account team.
Teams without a backend can start with the published n8n node for scheduled runs, and analysts can explore prompts ad hoc through the MCP server, where each tool call costs the engine price.
Pitfalls
- Quoting single runs as fact. Report rates over repeated runs and date every quote.
- Random idempotency keys. They make retries create duplicates. Derive keys from tenant, prompt, engine, market and day. See idempotency keys explained.
- Counting failed tasks as “not mentioned”. A
FAILEDtask says nothing about visibility; resubmit it. - One blended score per client. Engines differ; keep per-engine columns.
- Running every client at the same minute. A shared queue means one large tenant delays everyone; stagger and prioritize.
- Skipping signature verification. Anyone can post to a public URL; verify
Webhook-Signaturewith the account secret. See verifying webhook signatures.
For the agency workflow end to end, see AI answer tracking for agencies and the competitor analysis use case.
Questions
What is white-label AI visibility tracking?
It is AI answer monitoring that an agency or software platform offers under its own brand, with answer collection handled by an API in the background. Clients see your dashboards and reports; your backend calls the API.
Can I resell access to the API itself?
Not without a written agreement: the terms of service prohibit reselling raw access to the API without one. Building your own dashboards, reports and features on the data is the intended use.
How do I attribute API cost to each client?
Put the client ID in each task's idempotencyKey or your own task table, and store credits.creditsCharged from the finished task. Summing the charged dollars per client gives exact cost per client per month.
Can client-facing browser code call the API directly?
No. An API key spends your account's balance, so keep it on your servers. Your frontend calls your backend, which calls the API.
What does a typical client cost?
It depends on prompts, engines and cadence. As an illustration, 40 prompts run weekly on ChatGPT ($0.0006) and Gemini ($0.0006) costs $0.048 per run and $0.192 over four runs at the Starter tier.
Do I need engineers to offer this?
For a custom dashboard, yes. For lighter reporting, the published n8n community node can run monitors and create tasks, and the MCP server lets analysts query engines from an MCP-capable assistant.