URL: /capabilities/check-ai-answers/ai-answer-audit · Id: `page:/capabilities/check-ai-answers/ai-answer-audit`

# AI answer audit

> Twenty buyer questions in: who ChatGPT, Perplexity, Gemini and Google’s AI Mode name and cite for each, and whether any page of yours answers it.

Twenty buyer questions in: who ChatGPT, Perplexity, Gemini and Google’s AI [Mode](https://startupbuilder.dev/business/nouns/mode) name and cite for each, and whether any page of yours answers it.

```text title="Run it · Ask"
Check whether ChatGPT, Perplexity, Gemini and Google’s AI Mode name Leaseline for the 20 questions landlords ask most, spend up to $2, and show me the plan first.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Keyword.audit({ goal: 'Check whether ChatGPT, Perplexity, Gemini and Google’s AI Mode name Leaseline for the 20 questions landlords ask most, spend up to $2, and show me the plan first.', budget: { amount: 2, currency: 'USD' } })
```

```json title="Run it · Response"
{
  "mode": "try",
  "stored": false,
  "estimate": "About 98¢ per 20 questions",
  "sample": {
    "question": "What is the best way for a small landlord to track rent?",
    "names you": "0 of 12 answers",
    "brands named": "keyrent.example, a spreadsheet",
    "cited most": "landlord-forum.example (9)",
    "your page": "none answers it"
  }
}
```

- **Kind:** Workflow
- **Price:** 98¢ per 20 questions
- **Your time:** 10 minutes
- **Approval:** Runs on its own
- **Deepens:** [`process:content-marketing`](https://startupbuilder.dev/workflows/processes/content-marketing)

## What you get
- **20 questions** · Twenty buyer questions in: who ChatGPT, Perplexity, Gemini and Google’s AI Mode name and cite for each, and whether any page of yours answers it. · [`noun:keyword`](https://startupbuilder.dev/business/nouns/keyword)
- `share` · Answers that name you, over all answers: 0.04 is 4 of every 100. A new domain reads 0 until a cited page of its own exists.
- `questions[].answers` · For each engine: whether it names you, the brands it names, and the pages it cites.
- `questions[].yourPage` · Your page that answers the question, with the quote that shows it does, or `answers: false`.
- `readiness` · Whether robots.txt lets answer engines read the site, whether `llms.txt` exists, and the schema each key page carries.
- `citedDomains` · The domains answers cite most, with counts: the pages to be listed on, or to pitch.

**How long:** About 2 minutes; ChatGPT answers take about 30 seconds each, asked in parallel.

## Trigger
It runs when you call it. Search readout re-asks the saved questions every week.

```ts
every.week(($) => $.Keyword.track({ site: 'leaseline.app', terms: 'saved', questions: 'saved' }))
```

## Steps
Your agent does these steps, one row per step; each step’s check is part of its row and its price.

| Step | Verb | Returns | Price | Approval |
| --- | --- | --- | --- | --- |
| 1. Ask each engine each question three times | [`Keyword.ask`](/code/data/keywords/ask) | Each answer: the brands it names and the pages it cites | About 96¢ | Runs on its own |
| 2. Read the 20 pages answers cite most | [`Page.audit`](/code/data/pages-and-sites/audit-page) | Each cited page’s content, for what it says that yours does not | About 0.4¢ | Runs on its own |
| 3. Audit your key pages for answer readiness | [`Page.audit`](/code/data/pages-and-sites/audit-page) | robots.txt, `llms.txt`, schema and the first-60-words answer test on 10 pages | About 0.2¢ | Runs on its own |
| 4. Check whether your page answers each question | [`Domain.verify`](/code/data/domains/verify) | `answers: true` with the quote code finds on your page, or `answers: false` | About 1¢ | Runs on its own |
| 5. Count share and the gaps | `Collection.query` | Share across every answer, and the questions no page of yours answers | Free | Runs on its own |

Calls: `Keyword.ask`, then `Page.audit`, then `Domain.verify`, then `Collection.query`.

About 98¢ per 20 questions, each time it runs, capped at $1.50.

## Example: give it a goal
> Check whether ChatGPT, Perplexity, Gemini and Google’s AI Mode name Leaseline for the 20 questions landlords ask most, spend up to $2, and show me the plan first.

The plan it shows runs 5 steps, priced before it spends anything; Run it above shows the result it returns.

## When something fails

| When | Then |
| --- | --- |
| An engine refuses or times out on every route | It is left out of `share` and named under `skipped`; share is never computed over a missing engine. |
| An engine’s three answers disagree | All three are kept on the Event, and share counts each; in goal mode the agent may ask that engine twice more and records the Decision with its cost. |
| Your site blocks answer engines in robots.txt | `readiness.robotsAllowsAnswerEngines` reads `false` and the readout leads with it: no page fix matters until crawlers can read the site. |
| You call it again the same day | It returns the stored audit at $0, keyed on questions, site, engines and day. |

Each step retries three times, then falls through to the next route; one item's failure lands in `skipped` with its reason, never failing the call. Before a step would cross `maxCost` it stops and returns what it has, with a `resume` link. Each step's idempotency key is the call's key plus the step and the item: `leaseline-keyword-audit-1-<step>-<item>`.

## Change it
| Ask | Compiles to |
| --- | --- |
| Add Claude and Copilot to the engines. | [`Keyword.audit`](/capabilities/check-ai-answers/ai-answer-audit) |
| Write an answer page for every question no page of mine answers. | [`Page.answer`](/capabilities/make-content/answer-pages) |
| Ask these questions again every week and tell me what changed. | [`Keyword.track`](/capabilities/measure/search-readout) |

```ts
import { $, workflow } from 'startup-builder'

export default workflow({
  name: 'keyword-audit',
  verb: 'Keyword.audit',
  input: { questions: 'string[]', site: 'string', engines: 'string[]', runs: 'integer' },
  maxCost: 1.5,
  execute: async (ctx, { questions, site, engines = ['chatgpt', 'perplexity', 'gemini', 'google-ai-mode'], runs = 3 }) => {
    const answers = await ctx.step('answers', () => $.Keyword.ask({ questions, venues: engines, runs, maxCost: 1.1 }))
    const cited = await ctx.step('cited', () => $.Page.audit({ urls: topCited(answers, 20), fields: ['content'], maxCost: 0.02 }))
    const ready = await ctx.step('readiness', () => $.Page.audit({ site, pages: 10, checks: ['robots', 'llms', 'schema', 'first-answer'], maxCost: 0.01 }))
    const yours = await ctx.step('yours', () => $.Domain.verify({ hostname: site, answers: questions, fields: ['quote'], maxCost: 0.02 }))   // a checked extraction
    return auditOf(questions, answers, cited, ready, yours)
  },
})
```

Extend it with `extends: 'Keyword.audit'` and `base()`, or [compose your own](/code/compose) from these steps.

## Works with
**Plays that order it:** [Answer engine optimization](/plays/aeo), [Make your API easy for agents to find](/plays/agent-legibility), [Developer relations](/plays/developer-relations), [Free tools](/plays/free-tools).

It serves [Check AI answers](/capabilities/check-ai-answers), and runs in [Launch and search](/strategy/launch-and-search). It deepens [`process:content-marketing`](https://startupbuilder.dev/workflows/processes/content-marketing).

## For agents

| Fact | Value |
| --- | --- |
| Guide | `Keyword.audit` |
| Guide approval | `limits` |
| Goal | Check whether ChatGPT, Perplexity, Gemini and Google’s AI Mode name Leaseline for the 20 questions landlords ask most, spend up to $2, and show me the plan first. It may change counts, the order of steps, soft filters and the route a read takes, and it stops early when the goal is met. It never relaxes your words, raises its own budget, answers its own approval, calls a Play or acts outside your standing approval. |
| Trigger | `every.week(($) => $.Keyword.track({ site: 'leaseline.app', terms: 'saved', questions: 'saved' }))` |
| Retry | Three times with backoff, then the next route; the same idempotency key never charges, sends or posts twice |
| Idempotency key | `leaseline-keyword-audit-1` |
| Lookups | A `find:` input asks unless exactly one record fits |

| Step | Action class | Seat rule that would hold it |
| --- | --- | --- |
| 1. Ask each engine each question three times | None | None. |
| 2. Read the 20 pages answers cite most | None | None. |
| 3. Audit your key pages for answer readiness | None | None. |
| 4. Check whether your page answers each question | None | None. |
| 5. Count share and the gaps | None | None. |

The amounts live once, on the hub ([approvals](https://startupbuilder.dev/agents/approvals)).

| Step | Function | Doer | Checker | Assurance | Inputs |
| --- | --- | --- | --- | --- | --- |
| 1. Ask each engine each question three times | `code` | Code | Code checks each result against its declared type | `measured` | `$0.questions, $0.engines, $0.runs` |
| 2. Read the 20 pages answers cite most | `code` | Code | Code checks each result against its declared type | `measured` | `$1.cited` |
| 3. Audit your key pages for answer readiness | `code` | Code | Code checks each result against its declared type | `measured` | `$0.site` |
| 4. Check whether your page answers each question | `agentic` | The [Content lead](/capabilities/agents/content-lead) agent | Code finds the quoted evidence on the page | `measured` | `$0.site, $0.questions` |
| 5. Count share and the gaps | `code` | Code | Code checks each result against its declared type | `measured` | `$1, $2, $3, $4` |

The doer is never the checker, and the weakest assurance on the path is the whole call’s.

## Under the hood

| Kind | What it touches |
| --- | --- |
| Systems | None. |
| Nouns | [`noun:keyword`](https://startupbuilder.dev/business/nouns/keyword), [`noun:page`](https://startupbuilder.dev/business/nouns/page), [`noun:domain`](https://startupbuilder.dev/business/nouns/domain), [`noun:collection`](https://startupbuilder.dev/business/nouns/collection) |
| Events | `Domain.verified`, `Collection.queried` |

## Reference

| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `questions` | `string[] \| { fromMap: KeywordMap; take: number }` | Required | The questions buyers ask, in their words, or the question-form terms from a Keyword opportunity map. |
| `site` | `Hostname` | Required | Your site. |
| `engines` | `VenueId[]` | `['chatgpt', 'perplexity', 'gemini', 'google-ai-mode']` | The answer engines asked. Claude adds about 2.5¢ a question. |
| `runs` | `integer` | `3` | Asks per question per engine. Answers vary between asks; share is read across all of them. |
| `maxCost` | `number` | `1.50` | The most this call spends each time it runs, in USD. It stops before a step would cross it and returns what it has, with a `resume` link. |

Emits `Keyword.audited`. Refuses with [`max-cost`](/code/refusals#max-cost) before it spends, and with the Data calls and Accounts groups ([refusals](/code/refusals)).