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.
- Kind
- Workflow
- Price
- 98¢ per 20 questions
- Your time
- 10 minutes
- Approval
- Runs on its own
- Deepens
- Content marketing
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.
curl -X POST "https: //api.sb/ leaseline.app/ keywords/ audit? mode= try" \
-H "Authorization: Bearer $SB_TOKEN" \
-H "Content-Type: application/ json" \
-d '{"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"}}'
npx startup-builder do Keyword.audit --try --data '{"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"}}'
{
"name": "do",
"arguments": {
"mode": "try",
"code": "return await $.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' } })"
}
}
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' } })
{
"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"
}
}
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. · 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, oranswers:.false readiness· Whether robots.txt lets answer engines read the site, whetherllms.txtexists, 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.
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 | 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 | 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 | 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 | answers: with the quote code finds on your page, or answers: | 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
Each failure, and what happens next
| 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 |
| Write an answer page for every question no page of mine answers. | Page.answer |
| Ask these questions again every week and tell me what changed. | Keyword.track |
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: and base(), or compose your own from these steps.
Works with
Plays that order it: Answer engine optimization, Make your API easy for agents to find, Developer relations, Free tools.
It serves Check AI answers, and runs in Launch and search. It deepens Content marketing.
For agents
For agents: the guide, its approvals, retries and lookups
| 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: |
| 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 |
|---|
| 1. Ask each engine each question three times |
| 2. Read the 20 pages answers cite most |
| 3. Audit your key pages for answer readiness |
| 4. Check whether your page answers each question |
| 5. Count share and the gaps |
The amounts live once, on the hub (approvals).
Who does each step, and how it is checked
| 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, |
| 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 agent | Code finds the quoted evidence on the page | measured | $0.site, |
| 5. Count share and the gaps | code | Code | Code checks each result against its declared type | measured | $1, |
The doer is never the checker, and the weakest assurance on the path is the whole call’s.
Under the hood
Under the hood: the Systems, Nouns and Events it touches
| Kind | What it touches |
|---|---|
| Systems | None. |
| Nouns | Keyword, Page, Domain, Collection |
| Events | Domain.verified, Collection.queried |
Reference
Inputs, outputs, its Event and its errors
| Name | Type | Default | Meaning |
|---|---|---|---|
questions | string[] | { fromMap: | 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', | 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 before it spends, and with the Data calls and Accounts groups (refusals).