AnswerLine Start free

, Brand Monitoring · GEO

Monitor what AI answers say about your competitors

Competitor AI answer monitoring is the practice of running the prompts your buyers ask through AI engines on a schedule and recording which competitors each answer recommends, which of their pages it cites, and when either changes. If a rival starts being described as the best option for enterprise teams, you want to know which prompts that happens on, in which engines and markets, and which page of theirs the engine relied on.

The competitive prompt set

Build the set around buying moments rather than your own brand. Four groups cover most categories:

Group Example prompts What it tells you
Category “best tools”, “top for ” Who the engine considers the default shortlist
Comparison “ vs ”, “alternatives to ”, “alternatives to ” How you are positioned head to head, and who is suggested when a buyer is leaving you
Problem “how do I ” Which vendor gets recommended as the solution when no category is named
Evaluation “is worth it”, “ pricing”, “ reviews” Tone and the objections the engine repeats

Keep each prompt’s wording fixed and give it an ID; history is only comparable when the input is identical. Prompt set design covers coverage and size.

What to extract per run, by engine

Field availability differs by engine, and several fields are omitted from the response when empty or not requested, so read them with a default.

Signal Question it answers ChatGPT Perplexity Gemini Copilot Grok AI Mode
Brands named Who is recommended, in what order? entities[]; order from text match in text match in text match in text match in text match in text
Cited pages Whose content feeds the answer? sources[] sources[] sources[] sources[] sources[] sources[]
Searches run Which searches did the engine run, and do you rank for them? searchQueries[] (empty today) none none coming searchQueries[] none
Product cards Whose products appear with prices? inlineProducts[] (shoppingCards[] empty today) none none coming none shoppingCards[]

Definitions:

The pipeline

  1. Define competitors and aliases. For each rival: brand name, product names, domain(s). Short or generic names need word-boundary matching and occasional manual review.
  2. Write the prompt set across the four groups above, per market.
  3. Choose engines and markets. ChatGPT, Gemini and AI Mode answer from 213 countries; Copilot, Perplexity and Grok take any country; Gemini also takes a US state.
  4. Submit runs as async batches with deterministic idempotencyKeys and a webhook. One batch request holds up to 500 tasks.
  5. Store the raw result of each completed task (response.result) keyed by prompt, engine, market and run date.
  6. Extract signals with per-engine field mapping.
  7. Diff each run against the previous one for the same prompt, engine and market, and alert only on transitions.

Submitting the matrix

curl -X POST https://api.answerline.dev/v1/async/task/batch \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "taskType": "CHATGPT",
      "idempotencyKey": "comp:c07:chatgpt:US:2026-09-21",
      "webhook": { "url": "https://intel.example.com/hooks/answers" },
      "payload": {
        "prompt": "best invoicing software for freelancers",
        "country": "US"
      }
    },
    {
      "taskType": "GEMINI",
      "idempotencyKey": "comp:c07:gemini:US:2026-09-21",
      "webhook": { "url": "https://intel.example.com/hooks/answers" },
      "payload": { "prompt": "best invoicing software for freelancers", "country": "US" }
    }
  ]'

Cost for this one prompt at the Starter tier: ChatGPT $0.0006, Gemini $0.0006, so $0.0012 per run. A 60-prompt set run weekly (4 runs) on these two engines is 60 x 4 x $0.0012 = $0.288 a month. Prices are on the billing page.

Extracting signals per engine

import re
from urllib.parse import urlparse

COMPETITORS = {
    "you": ["Ledgerly"],
    "rival_a": ["InvoiceNinja Pro", "InvoicePro"],
    "rival_b": ["BillFox"],
}

SEARCH_FIELD = {"GROK": "searchQueries"}

def brand_order(text):
    firsts = {}
    for brand, aliases in COMPETITORS.items():
        hits = [m.start() for a in aliases for m in re.finditer(rf"\b{re.escape(a)}\b", text, re.IGNORECASE)]
        if hits:
            firsts[brand] = min(hits)
    return [b for b, _ in sorted(firsts.items(), key=lambda kv: kv[1])]

def product_labels(engine, result):
    if engine == "AIMODE":  # AI Mode cards are flat product entries
        return [f"{c.get('title')} @ {c.get('store')}" for c in result.get("shoppingCards", [])]
    if engine == "CHATGPT":  # inline products, one record each, offers per merchant
        products = (i.get("product", {}) for i in result.get("inlineProducts", []))
        return [f"{p.get('title')} @ {(p.get('offers') or [{}])[0].get('merchant_name')}" for p in products]
    return []

def signals(engine, result):
    text = result.get("text") or ""
    return {
        "order": brand_order(text),
        "cited_domains": sorted({urlparse(s.get("url", "")).hostname or "" for s in result.get("sources", [])}),
        "cited_urls": [s.get("url") for s in result.get("sources", [])],
        "searches": result.get(SEARCH_FIELD[engine], []) if engine in SEARCH_FIELD else None,
        "products": product_labels(engine, result),
    }

None means the engine does not provide that signal; an empty list means it provides it and returned nothing. Keeping that distinction stops dashboards from showing “0 searches” for Gemini or Perplexity. ChatGPT is left out of SEARCH_FIELD because its searchQueries list comes back empty on the answers served today, and Copilot because its search queries are not returned yet.

Detecting transitions

Alert on changes in state for a fixed prompt, engine and market, not on mentions:

Transition Rule Why it matters
Rival entered rival in order now, not in previous run They won a buying moment
You left you absent now, present before Direct loss of visibility
Rival overtook you rival’s index in order now lower than yours, previously higher Shortlist order changed
Citation displaced one of your URLs left cited_urls and a rival-domain URL entered Their page replaced yours as evidence
New search a string in searches not seen for this prompt before A new query to rank for

Answers vary between runs even when nothing has changed in the world, so require a transition to persist across two consecutive runs before paging anyone, or compare rates over a window. Answer volatility covers how to set that threshold for your data.

def transitions(prev, curr):
    events = []
    for brand in COMPETITORS:
        was, now = brand in prev["order"], brand in curr["order"]
        if now and not was:
            events.append(("entered", brand))
        if was and not now:
            events.append(("left", brand))
    lost = set(prev["cited_urls"]) - set(curr["cited_urls"])
    gained = set(curr["cited_urls"]) - set(prev["cited_urls"])
    if lost or gained:
        events.append(("citations_changed", sorted(lost), sorted(gained)))
    if curr["searches"] is not None and prev["searches"] is not None:
        new = set(curr["searches"]) - set(prev["searches"])
        if new:
            events.append(("new_searches", sorted(new)))
    return events

Turning signals into a competitive view

Per-run events feed alerts; a monthly view needs rates. For each competitor, per engine and market:

  1. Presence rate: runs where the competitor is named, divided by completed runs.
  2. First-named rate: runs where the competitor appears first in text, divided by runs where any tracked brand is named.
  3. Citation share: URLs on the competitor’s domains divided by all cited URLs.
  4. Prompt wins: prompts where the competitor is named in most runs of the period and you are not.

Illustrative example: across 4 weekly runs of a 60-prompt set on Gemini (240 runs), a rival named in 132 runs has a presence rate of 132 / 240 = 55%. If some tracked brand is named in 200 of those runs and the rival is named first in 90, its first-named rate is 90 / 200 = 45%. These numbers are invented to show the arithmetic.

The prompt-wins list is the most useful output for a content team: each entry is a concrete question plus the pages the engine cited for the rival.

Cadence

The trade-offs are in monitoring cadence.

Reading the counterplay

When a competitor starts winning a prompt, the cited URLs are the explanation you can act on. Open the rival page the engine cited and note:

  1. Format: comparison table, listicle, documentation page, pricing page, forum thread.
  2. The claim the answer repeated, often a single sentence the engine paraphrased.
  3. Freshness signals: a visible date, a current year in the title, recent pricing.
  4. Where it lives: their own domain, or a third-party review or community site.

That page is the brief. If it is on their domain, publish a page that answers the same question more completely and specifically. If it is third-party, the work is outreach or participation there. Then keep the prompt in the set and measure whether the citation moves over the next several runs. How AI engines choose citations and Reddit citations in AI answers go further.

Pitfalls

The share-of-voice framework turns these signals into reportable numbers, and the competitor analysis use case covers the SERP side. Field details per engine are on the ChatGPT and Gemini engine pages.

Questions

What is competitor AI answer monitoring?

It is running a fixed set of buyer prompts through AI engines on a schedule and recording which competitors each answer names, which of their pages it cites, and when that changes. The output is a per-prompt, per-engine, per-market history you can alert on.

Which engines return the brands named in an answer as structured data?

ChatGPT. Its entities array lists the brands and products an answer names, each with a type and name. On Gemini and the other engines, detect competitors by matching their names and aliases in the answer text or markdown.

Which engines return the searches they ran?

ChatGPT has a searchQueries field (include.searchQueries, free), but it comes back empty on the ChatGPT answers served today. Grok returns searchQueries: its web and X searches. Gemini and Perplexity return none. Copilot's searchQueries is coming.

Which engines return product cards with prices?

Google AI Mode (shoppingCards) and ChatGPT. With include.shopping, ChatGPT's shoppingCards comes back empty on the answers served today, and inlineProducts carries the products from its shopping search, with price, link and merchant offers. Copilot's shopping cards are coming. The product fields inside differ per engine, so map them separately.

How often should competitor prompts be run?

Weekly suits a core prompt set; increase to daily for a limited set around launches or pricing changes. Alert on transitions, such as a competitor entering an answer, rather than on every mention.

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