AnswerLine Start free

, Agencies · GEO

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

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:

  1. 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.
  2. Scheduler. For each due client, build tasks and submit them with POST /v1/async/task/batch (up to 500 tasks per call).
  3. Idempotency keys that carry the tenant. A key like t42-p117-CHATGPT-US-2026-09-16 makes retries safe and lets the webhook handler route the result without a lookup. Keys are unique across your account, and the finished task echoes task.idempotencyKey.
  4. Webhook receiver. Verifies the signature, stores the raw JSON and credits.creditsCharged against the tenant, and acknowledges within 15 seconds.
  5. Metrics job. Computes per-tenant metrics from stored answers, so every number traces back to a response.
  6. 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:

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

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

  1. Day 1: follow the quickstart; run one client’s top 10 prompts synchronously and read the JSON.
  2. Day 2: create the tenant and prompt tables; write the key format.
  3. Day 3: submit the client’s set as an async batch with a webhook; store raw answers and charged dollars.
  4. Day 4: compute mention rate and citation share per engine; compare with a manual reading of a few answers.
  5. 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

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.

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