Blog / The rival names on your report were never typed in

The rival names on your report were never typed in

Lantad does produce a comparative view of who answer engines name instead of you, and it does it with no competitor field at all: every rival name is extracted from the answer text, through screens we built after shipping two pieces of output that should never have passed, one a name and one a question.

In short

  • Lantad's prompt tracking has no competitor input anywhere: the form posts a URL and an email, and every rival name on the report is extracted from the answer text rather than checked against a list you supplied.
  • Lantad's rival-name extractor keeps at most eight names per answer and discards any sequence longer than three words, both precision rules with no incident behind them; the separate rule that strips ordinary capitalised words is the one the source dates to a customer's report that once published "Below, Feel, Clarify Who You" as their competitors.
  • Lantad's share figure is a share of the names those answers produced, and the report states in body copy that it is not market share, not revenue share and not audience share.
  • Lantad's own monthly counter on the grounded Gemini engine is 4,500 calls, set 500 below Google's 5,000-call free tier, while Lantad's free traffic alone would ask 15,000 a month, 3.3 times that counter, so at ceiling the engine reports as budget_stopped rather than quietly measuring one engine fewer.
  • Lantad never queries the ChatGPT, Claude, Perplexity or Gemini consumer apps: its five answer engines are APIs and open-weight models, and the report names the model that answered rather than an app.

Short answer: yes, partly, and the honest version of that answer is narrower than the question. Lantad has a surface that puts questions to up to five answer engines, two of which every plan carries including the free one, records whether each engine names your brand, and lists the other brand names those same answers produced. That is a comparison against rivals. It is not a monitoring platform, it does not watch the consumer apps people actually type into, and there is nowhere to enter a competitor you want watched.

The two halves live in different places, and conflating them would be the first false claim available here. What AI says about you asks one open-weight model two questions about your brand, once from memory with no web access and once after being handed the crawler-visible text of your page. It has no competitor dimension at all. Prompt tracking is the surface that produces rival names, and it produces them by reading them out of the answers rather than by checking a list you supplied. Both sit inside the same wider job, generative engine optimization, but only one of them ever prints a name that is not yours.

This post is about that second surface. Specifically: how a rival's name gets onto a report, every screen that stands between a model and that name, the two occasions we shipped output that should never have passed, one a name and one a question, and the ceiling we wrote down about our own coverage before anyone else could find it.

Everything the run is given

  • A URL
  • An email address, or the signed-in session that already proved that address
  • A human check, on anonymous submissions only
  • No competitor field on the form, in the handler, or in the account

What the report produces

  • Questions derived from the page's own crawler-visible text
  • Whether each engine's answer named you
  • The other brand names those same answers produced
  • A share of the names produced, with its denominator printed beside it
What a prompt tracking run is given, and what it produces. The form in site/src/pages/prompts.astro carries two inputs; the handler in worker/src/api.ts takes the address from the signed-in session when there is one.

What one run actually reports

A run takes one URL and one email. From the page's crawler-visible text it derives candidate questions, screens them, scores each by how much of the answer the page itself can ground, discards everything under the floor, and puts the survivors to the answer engines. Four numbers come back, and every one of them carries a basis string that names its exact denominator. That string is body copy printed next to the number, not a tooltip and not debug output.

Visibility is how many answers named you over how many answers came back, where one answer is one question put to one engine. Share of names produced is your name count over the total of every brand name those same answers produced. Citations counts the source hosts a citation-capable engine handed back, how many of those were your own domain, and how many were opaque redirects that hide the publisher. Sentiment is a fixed word list applied to the sentence that mentions you. None of the four costs a model call: they are aggregations over fields the run already persisted, which is why adding a metric cannot move the spend ledger.

Five engines sit in the registry, and each is named as a model rather than as an app. The Workers AI open-weight chain runs with retrieval set to none, meaning no web access at all; Cloudflare's Workers AI model catalogue is where those models come from. Gemini runs with Google Search grounding and returns citations. Perplexity Sonar, GPT-4o mini with web search, and Claude Haiku 4.5 with web search are the three paid rows, all live and all citation-capable. The rule is written into the registry itself: the human label for the report never says ChatGPT, it says the model. We call APIs and open-weight models. We do not query the assistant products people use at their own keyboards, and no number on this report should be read as though we did.

Breadth is what a plan buys. A free run is 5 prompts and zero paid engines, which is not zero engines: it still carries both always-on rows, so it can come back with real answers from two. Pro Monitor is 25 prompts and one paid engine. Business and Retainer are 50 prompts and three paid engines, which is the entire paid registry. What each plan costs is on the pricing page. So "covers every major engine" is a claim this product cannot make and does not make, and the report says which engines answered on every single run rather than leaving you to assume.

One scoping statement, because the query that brings people here usually means something bigger. This is narrower than an AI brand monitoring platform. Those platforms monitor assistant output against a competitor roster you configure, and Profound states on its own site that it captures AI answers from the front-end browser experiences real users see rather than from APIs. Lantad does neither. There is no roster to configure, no front-end capture of any kind, and no region or language dimension anywhere in a run. What follows is what it does instead, and why the difference is a design choice rather than a roadmap gap we are hiding. If your first question is whether crawlers can read your pages at all, that is the AI visibility layer and it is measured separately, with the weights set out on the methodology page.

  • Free run 2 engines 5 prompts, zero paid engines. Zero paid is not zero engines: both always-on rows are carried on every plan.
  • Pro Monitor 3 engines 25 prompts, one paid engine, which is Perplexity Sonar in registry order.
  • Business 5 engines 50 prompts, three paid engines, the whole paid registry.
  • Retainer 5 engines 50 prompts, three paid engines. Identical to Business, because there is nothing above it to grant.
Answer engines a plan carries on one run. Prompt counts and paid-engine counts read from PLAN_LIMITS in core/src/config.ts; the two always-on rows are the non-paid tiers of the registry in core/src/engines.ts.

There is no competitor field

The form on the prompt tracking page has two inputs. One is your page. The other is your email. The handler on the other side reads the URL, the email or the signed-in session that already proved that address, and a human check that only anonymous submissions carry. A signed-in caller skips the human check entirely, and the session's address wins over anything typed into the form, so a submission cannot attach a run to somebody else's inbox. None of those inputs is a competitor. There is no third field, no roster, no watchlist, and no place in the account where a competitor is configured. Nothing in the run knows the name of a single rival before the answers come back.

The rival names are extracted from the answer text. When an engine answers a question your page could have answered, the extractor walks the answer looking for proper-noun sequences, strips the ones that are grammar rather than names, drops the brand's own name when it recognises it, and keeps what is left. Those are the names on your report. They are the names the model reached for on questions derived from your own page, which is a different and more useful fact than whether a list of five companies you already think about got mentioned.

This is the part worth checking against any other tool you are evaluating, because it is checkable in one screenshot: does the product ask you who your competitors are? If it does, the competitor set is yours and the tool is confirming or denying it. If it does not, the set is discovered and the tool can surprise you. Both are legitimate. They answer different questions, and the second one is the one we built, because the interesting failure mode is not "we lost to the rival we track", it is "the model names three companies we had never heard of".

The questions are derived from your page too, and that has a limit we state plainly. Relevancy scores how much of a question the page's crawler-visible text can actually ground. It is deliberately not search volume, not difficulty, and not a prediction of being cited: there is no prompt-volume dataset in this product, and we will not invent one. Anything below 45 is discarded and never displayed, because showing a question the page cannot answer invites a measurement we already know is noise. At 70 and above a question is banded grounded; between 45 and 69 it is partial. Relevancy is stable across reruns unless the page changes, which means relevancy drift is page drift and nothing else.

One question sits outside all of that. The branded control asks the model directly what it knows about your brand and your domain, and it is asked outside the ranked set and outside the score. It exists so the report can say, honestly, that a model does not name you even when asked about you by name. It is also excluded from the visibility denominator, because a question that names you is answered by naming you, and counting it would flatter the number. This is closely related to what answer engine optimization is trying to influence, and to the platform-specific work on getting cited by Perplexity, but the control is a measurement, not a tactic.

  • The URL Read from the form, then put through the same guard the crawler scan uses before anything is queued.
  • An email address The signed-in session's address when a session cookie is present, otherwise the one typed into the form. The session wins, so a run cannot be attached to another inbox.
  • A human check Read only when there is no session. An authenticated caller skips it, because the magic-link session is the stronger proof of the same thing.
  • A competitor, roster or watchlist No such field exists on the form, in the handler, or anywhere in the account. Rival names arrive later, out of the answers.
Every input the prompt tracking handler reads from a submission, from the api.post("/api/prompts") route in worker/src/api.ts.

The screens between a model and a rival name

A model produced the text. A model does not decide what ships. Every consequential step in this module is deterministic code, and a name has to survive all of it before a customer reads it.

The first screen runs before any answer exists, on the questions themselves. A candidate question that names your brand or your domain is rejected outright, with the reason recorded as names_brand. A question that hands the model the answer makes the naming measurement circular, and a circular measurement that looks like a result is worse than no result. The second screen is the hallucination screen: every proper-noun sequence in a candidate question must be attested somewhere on the page, or the candidate is discarded as unattested_entity. The model cannot put a competitor's name into a question unless your own page already mentions it. That screen is biased hard toward rejecting, because a false reject costs one candidate slot and a false accept invents a competitor.

On the answer side the extractor's own doc comment states the trade: a missed competitor costs one row of insight, an invented one is false information on a customer's report. So it is built for precision over recall, and it loses real names to get there. Sentence-initial capitals are skipped, because a capital at the start of a sentence is usually grammar. Ordinary capitalised words are stripped off both edges of a sequence, and any sequence with sentence glue left inside it is discarded entirely, because real product names are not built from sentence glue. Any sequence longer than three words is dropped. At most eight rival names are kept per answer, so a long list is truncated rather than padded out.

Two rules in this module exist because we shipped the bug first, one on each side of the run. On the answer side, a customer's report once published "Below, Feel, Clarify Who You" as their competitors. Those are ordinary English words that took a capital because they opened sentences and imperative advice lines in a model's answer, and the extractor treated capitalisation as evidence of a brand. The list of ordinary capitalised words that now strips them sits in the source with that incident written above it, and it is the only rule the repository attaches to that incident. On the question side, "cases resources" once shipped as a published question, assembled from two adjacent navigation headings that never appeared next to each other in any block of real text. Phrase checks now run against the token sequences of individual blocks rather than the whole page, because whole-page adjacency invents phrases across block boundaries, and a phrase no single block contains is an artifact rather than a topic.

Both bugs have the same shape, and it is the shape worth watching for in any tool that reports what AI says about you. The output looked like data. It was formatted like data, ranked like data and sat in a table like data. What it actually was, in one case, was the model's grammar mistaken for the market's structure. This is the same class of error as scoring a page's structure from an error page body, which is why the extraction step is worth understanding before trusting anything downstream of it: what a crawler meets is the raw material, as one storefront teardown showed at the page layer, and the five structural signals work is the same discipline applied to identity. If you want to see the input for yourself before reading anything about the output, what GPTBot sees shows you the text the extractor is working from, and entity confidence is the structural half of the same question.

extractOtherNames, one sequence

  • properNounSequences(answer, true) sentence-initial capitals skipped
  • strip ordinary capitalised words off both edges "The Mailreach" becomes "Mailreach"
  • nothing left, or more than three words discarded
  • an ordinary capitalised word still inside discarded
  • matches the brand name or the domain label discarded, it is not a rival
  • already seen in this answer discarded, counted once
  • eight names kept stop, the rest of the answer is not read
The screens extractOtherNames in core/src/prompts.ts applies to one candidate proper-noun sequence, in source order. The "The Mailreach" example is the one written into the code comment.

What each number is a share of

Share of voice is the phrase the category uses, and it is the phrase we refuse to use unqualified. What this product computes is a share of the names these answers produced, and the basis string says so in the customer's own report: not market share, not revenue share, not audience share, and it says nothing about how many people asked these questions. It says how often you were one of the names an engine reached for, on questions derived from a page you chose. Your name counts once per answer that named you. Each rival name counts once per answer that produced it. The extractor keeps at most eight rival names per answer, so a very long list is truncated rather than invented, and the metric says that too.

An errored answer leaves the denominator entirely. "The engine did not answer" and "the engine answered without naming you" are different facts, and averaging them together turns an outage into a visibility problem. Errors are counted and reported separately on their own line. A zero denominator returns null and never zero, so a surface can print "not measured on this run" in place of a figure. That rule was argued at the scan layer first, in why we withhold a grade, and this is the same rule applied one layer up: a number produced when the measurement did not happen is not a low number, it is a false one.

The engine table is where non-answers get their own vocabulary. There are five states. Answered means the engine was asked and returned at least one answer. Not configured means no API key exists in that environment, so it was never asked, which is a missing engine rather than an engine that had nothing to say. Not included means the plan does not carry it. Budget stopped means the spend ledger or a vendor free-tier counter stopped it, either before the run or partway through. Failed means it was asked and every call errored. Each state renders a plain sentence written by the code that knows the numbers, so the line cannot drift from what it describes.

The paid cap is disclosed inside the report rather than in a footnote somewhere. Paid engines answer only the top 10 prompts of a run. On a 50-prompt Business run that means the open-weight line reads "answered 50" and the Perplexity line reads "answered 10", and without disclosure a reader concludes the paid engine failed on 40. So the line itself says only the top 10 of this run's 50 prompts went to it, that paid engines are capped at 10 prompts per run, and that the other 40 were never sent, not answered and lost. That is a limit we chose, and a limit you chose to pay for or not, which is a different thing from a limit that quietly ate your data.

The same discipline governs the account dashboard. When the full per-engine run documents cannot be read, the dashboard falls back to a rollup of the baseline engine only, and the copy says one engine only and says why, rather than presenting a narrower measurement as full coverage. Nothing in this stack is allowed to widen silently. The aggregate picture across scans lives on our research page, which withholds the survey entirely until the sample clears the minimum in the code rather than publishing a figure it cannot stand behind.

  • answered asked, returned at least one answer The only state whose answers enter the visibility and share denominators.
  • not configured no API key in this environment Never asked. A missing engine, not an engine that had nothing to say.
  • not on this plan the plan does not carry this engine Breadth is what a plan buys, so this state is a purchase decision made visible.
  • budget stopped the spend ledger or a vendor free-tier counter stopped it Before the run or partway through, and the line says how many prompts it did cover.
  • errored asked, and every call errored Counted and reported on its own line. An outage must not read as a visibility problem.
The five EngineRunStatus values in core/src/engines.ts, with the chip text from ENGINE_STATUS_LABEL. Only the first puts an engine's answers into a denominator.

Citations and sentiment, and where each one stops

Only engines that report their sources can produce a citation row, and the report knows which ones those are from a flag on the registry rather than from a guess. That produces three distinct rendered states, and collapsing them is the mistake this section exists to avoid. Sources listed means the engine handed back URLs. A citing engine that returned an empty list is a measured zero. A citing engine whose answer carried no source list at all is not a zero: it is unread, and printing nothing for it would read as "there were none". Perplexity's Sonar API returns its search results on every answer, which is the reason that engine is worth wiring at all: the citation metric costs no extra call. OpenAI's web search tool exposes its sources as citation annotations on the output text, and the Anthropic engine's search results arrive in their own tool-result blocks.

Then there is the case that would quietly ruin the metric. Google's grounding returns source URLs as redirect links on vertexaisearch.cloud.google.com and grounding-api-redirect.googleapis.com, so the host of a cited URI is often Google's redirector rather than the site that actually grounded the answer. Aggregating those by host would produce a citation table that is one Google row and nothing else, and would report every customer as never cited. They are counted as opaque, reported separately, attributed to nobody, and never counted as evidence that you were not cited. A citation you cannot attribute is missing information, not an absence.

Sentiment is the metric most likely to be oversold, so here is the whole method. It is a fixed word list: 41 positive terms, 39 negative terms, 22 negators and 8 clause-breaking words, applied to the sentence or sentences of an answer that mention your brand. A negator within three tokens before a hit flips its polarity, a clause breaker stops that backward scan so that "not cheap but reliable" does not read as "not reliable", and the sign of the total picks one of four coarse labels. That is all of it.

A word list was chosen over a model pass for two reasons, and only one of them is cost. The other is that you can read the list, see which term fired on which sentence, and disagree with the number. You cannot do that with a model score. The config states what the method cannot do, in the same file as the list: sarcasm, comparison, conditionals, and any sentence whose polarity lives in structure rather than vocabulary. "Better than X" is positive about the sentence's subject, which may not be you. It reads one sentence, so a paragraph that praises then qualifies is scored on whichever sentence names you. Several obvious words were considered and rejected for flipping meaning in exactly the sentences we score: "problem" and "issue" both appear in praise, "free" is usually a selling point, "unknown" describes pricing rather than a view of a brand, and "simple" and "basic" are praise or criticism depending on the buyer.

None of this tells you whether an assistant will cite you tomorrow. The platform-specific work on that lives elsewhere: getting cited by ChatGPT, by Claude, and in Google AI Overviews each have their own mechanics, and structured data is the part of it a scanner can measure directly.

  • Positive terms 41 A term is admitted only if it carries the same polarity in ordinary product prose.
  • Negative terms 39 "problem", "issue", "free", "simple" and "basic" were considered and rejected for flipping meaning.
  • Negators 22 Flip a hit that falls within three tokens after them.
  • Clause breakers 8 Stop that backward scan, so "not cheap but reliable" is not read as "not reliable".
  • Model calls the metric costs 0 It is a deterministic function of text the run already persisted.
The entire sentiment method, counted from ANSWER_METRICS.lexicon in core/src/config.ts. Four lists and a three-token window, applied only to the sentences that name your brand.

The ceiling we wrote down about ourselves

Here is the fact that makes this a blog post rather than a landing page. The grounded Gemini engine is metered in calls, not dollars. Google's free grounding tier is 5,000 grounded prompts a month, verified on the vendor's published pricing on 22 July 2026, and our own counter sits at 4,500 to leave headroom for counter lag. That counter is what holds the Gemini bill at exactly zero, because the paid tier is never entered. Gemini is always-on, so it answers every prompt of every run on every plan. Free traffic alone, at the daily cap of 100 runs a day times 5 prompts times 30 days, is 15,000 calls a month. That is 3.3 times the counter, from the free tier by itself, before a single paying account is counted.

So at ceiling the grounded engine goes dark part-way through the month and every run after that measures one engine fewer than the plan sold. That is a measurement overrun rather than a money one: the counter stops the spend at zero cost. The honesty machinery for it already exists and has to stay wired, which is exactly why budget_stopped is a distinct state with its own sentence. A share number computed over fewer engines than the plan promised is a different measurement, and a zero from an engine that never ran must never render like a zero from an engine that ran and did not name you. The repository records this, a test asserts the overrun so it cannot be forgotten, and the fix is a coverage decision rather than a spending one. We are publishing it because a limit you find yourself is worth less than a limit the vendor told you about.

There is a second caveat in the same spirit, and it is smaller but sharper. The report shows whether you were named first, and that flag is not an exact ranking. The extractor deliberately skips sentence-initial capitals, because a capital at the start of a sentence is usually grammar. When the brand is not found among the extracted names, its position defaults to 1. Put those together and a brand that opens a sentence can be recorded as named first without actually being first in any ordering a human would recognise. The framing for this is the one already argued in a user agent is a claim, not an identity: a figure everyone quotes is often a claim nobody verified, and our own figures are not exempt from that.

Tracking over time carries the same rule. When two runs of the same prompt set are compared, a null answer never counts as a flip in either direction, because an engine that errored is not an engine that stopped naming you. Alerting on that difference would manufacture a scare out of a timeout. An account can carry up to 10 distinct URLs on the weekly rerun cadence, which is a deliberate ceiling rather than an oversight: every tracked URL multiplies against prompts per run and engines per run, and the arithmetic that decides whether the product survives its own bill is written down next to the constant.

Publishing an inconvenient measurement is not new for this blog. What the evidence says about llms.txt argued against a feature we ship, and this is the same posture pointed at the engine ladder. The scoring rules that sit underneath all of it are on the methodology page, and the per-crawler behaviour that decides whether any of this input exists is in the AI crawler list.

  • Google free grounding tier 5000 calls Verified on the vendor's published pricing, 22 July 2026.
  • Our monthly counter 4500 calls 500 under the free tier for counter lag. This is what holds the Gemini bill at zero.
  • Free traffic alone, at ceiling 15000 calls 100 runs a day times 5 prompts times 30 days, and Gemini answers every prompt on every plan.
  • Reference paid fleet, on top 6495 calls The modelled paying accounts at their full weekly rerun cadence.
Grounded Gemini calls a month: our counter against the demand written down beside it in core/src/config.ts. Free traffic alone is 3.3 times the counter, before any paying account is counted.

What this is not, and what it would take

The honest close is a list of things this product does not do, because the search that brings people to this page usually means all of them.

It does not capture what a real user sees in a consumer assistant. There is no front-end browser session, no logged-in app, no screenshot of an answer as rendered to a person. Every answer here comes from an API or an open-weight model, and the report names the model. It does not run multi-region or multi-language. A run is one language and one place, and there is no location dimension anywhere in the schema. It does not track a competitor set you define, because there is nowhere to define one. It does not carry a dataset of real user prompt volumes, so nothing here can tell you how many people asked. And it does not publish customer outcomes: there are no stored prompt-run captures in this repository at all, and the sample output shown on the product page is labelled as a sample because it is one.

What it does instead is measure the layer underneath, which is the layer that decides whether any of the above is even possible. If a crawler cannot fetch or parse a page, nothing downstream can quote it. That is the argument in two layers decide if AI can read your site, and it is why prose parity is the heaviest single weight in the score. A head-to-head against a rival's page on that readability score is a separate and simpler measurement, and it lives at compare: it asks whose page is easier for a crawler to read, which is not the same question as whose brand a model names, and the two must not be quoted as if they were.

If you are choosing between products, the useful test is not the feature list. It is whether each number tells you its denominator. Ask what a share of voice figure is a share of. Ask what happens to an answer that errored. Ask whether an engine that was never asked is visually distinguishable from an engine that answered and did not name you. Ask whether a citation that resolves to a redirector is counted as a citation, dropped, or attributed to the redirector. Those four questions separate a measurement from a dashboard, and they are answerable in a minute on any tool, including this one.

The rest of the surface area is documented rather than pitched. The multi-page scan covers a set of your own pages at the readability layer, our crawler's conduct rules set out how it identifies itself and what it respects, the robots.txt tester shows per-crawler access decisions, and the fix work is what happens after a report says something specific is broken. None of those claim to know what an assistant said about you last Tuesday. This post exists so that the one surface that does make a comparative claim can be read with the exact size of that claim attached.

  • Consumer assistant sessions No front-end browser capture and no logged-in app. Every engine in the registry is an API or an open-weight model.
  • Regions and languages One language and one place per run. There is no location dimension anywhere in the schema.
  • A competitor roster you configure No field on the form, in the handler, or in the account. Rival names are extracted from the answers instead.
  • Real user prompt volumes No prompt-volume dataset exists in this product, and relevancy is explicitly not search volume.
  • Published customer outcomes No stored prompt-run captures exist in this repository, and the output on the product page is labelled a sample.
  • A printed denominator on every number The basis string is body copy next to the figure, not a tooltip and not debug output.
The boundary of prompt tracking. Every absent line is traced to the absence in the repository that makes it true, not to a roadmap.

Related

Common questions

Can I tell Lantad which competitors to track?

No. There is no competitor field anywhere in prompt tracking. The form posts a URL and an email, and the handler reads the URL, the email or the signed-in session that already proved that address, and a human check on anonymous submissions. None of those is a competitor. Every rival name on the report is extracted from the answer text itself, so the set is discovered rather than configured. If you need a tool that watches a roster you define, this is not that tool.

Does this show me what ChatGPT says about my brand?

No, and the product is built so it cannot accidentally imply that. Lantad calls APIs and open-weight models: a Cloudflare Workers AI chain with no web access, Gemini with Google Search grounding, Perplexity Sonar, GPT-4o mini with web search, and Claude Haiku 4.5 with web search. The report names the model that answered, never a consumer app, because we never query the consumer apps.

Is the share figure the same as share of voice or market share?

No. It is a share of the brand names those specific answers produced, over the questions derived from your own page, and the report states that in body copy next to the number. It is not market share, not revenue share and not audience share, and it says nothing about how many people asked those questions.

How many engines answer on a free run?

Two are carried. A free run is 5 prompts with zero paid engines, which is not zero engines: both always-on rows are on every plan. Whether both actually answer depends on the grounded engine having a key configured and room on its monthly counter, and the engine table reports that per run. Pro Monitor adds one paid engine at 25 prompts; Business and Retainer reach all five at 50 prompts, and the three paid engines see only the top 10 prompts of that run, which the report line says explicitly.

See what AI can read on your site

Run a free scan and get a graded report of exactly what AI crawlers can and cannot read, with ranked fixes.