AI Search Visibility Tracker (ChatGPT, Perplexity, Gemini)
Pricing
Pay per event
AI Search Visibility Tracker (ChatGPT, Perplexity, Gemini)
Is your brand mentioned, ranked and cited in AI search answers? Asks OpenAI, Perplexity, Gemini and Anthropic through their official APIs with your own keys. Share of voice vs competitors; monitor mode reports only changes plus a weekly summary.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Benjamin Cojocaru
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Share
AI Search Visibility Tracker (ChatGPT, Perplexity, Gemini, Claude APIs)
Find out whether AI search mentions your brand, where it ranks it against competitors, and whether it cites your website. You give the questions your buyers ask ("What is the best CRM for a small business?"); the Actor asks each AI engine through its official API with your own API key and records, per prompt and engine: brand mentioned or not, rank among the brands named, tone, cited URLs, whether your domain is cited, and which competitors appear. A summary row gives share of voice per engine.
Schedule it in monitor mode and it remembers the last result for every prompt x engine, then outputs only what changed (brand dropped from an answer, citation lost, rank moved, a new competitor showing up), plus a weekly summary.
Pricing at a glance (our fee, on top of your own API cost): prompt-checked per prompt x engine answered and stored (suggested $0.01), change-detected per monitor row with changes (suggested $0.02), summary-generated per summary row (suggested $0.05). Failed calls are free. Try it free first with dry run (no keys, no calls).
Official APIs only, your keys
Engine (engines) | API | Web grounding | Key input |
|---|---|---|---|
openai | OpenAI Responses API (/v1/responses) | web_search tool | openaiApiKey |
perplexity | Perplexity Agent API (/v1/agent, preset fast by default) | preset's web search | perplexityApiKey |
gemini | Google Gemini API (generateContent) | Grounding with Google Search | geminiApiKey |
anthropic | Anthropic Messages API | web_search server tool | anthropicApiKey |
The Actor never opens chatgpt.com, perplexity.ai or any other chat website, and never logs in anywhere. API answers are close to, but not identical with, what a person sees in the consumer apps (those add personalization, location and their own system prompts); they are consistent from run to run, which is what trend tracking needs.
Your keys are secret inputs (stored encrypted by Apify), sent only in a request header to that provider's API host, and removed from every error message. They are never written to the dataset, the SUMMARY or the monitor store. You pay each provider for your own calls (roughly $0.005-0.04 per call depending on engine and model; web-search and grounding fees apply, see each provider's pricing). SUMMARY.apiCalls and SUMMARY.apiTokens show what was used per engine so you can check your bill.
Model defaults: gpt-5-mini, Perplexity preset fast, gemini-2.5-flash, claude-haiku-4-5 (change them with openaiModel, perplexityModel, geminiModel, anthropicModel). Please check that gpt-5-mini still exists and supports web_search on your account: OpenAI's guide now recommends newer models, and the defaults have not been tested with a real key. perplexityModel takes a preset (fast, low, medium, high, xhigh) or a direct provider/model (sent with the web_search tool). A sonar* value uses the legacy Sonar Chat Completions API, which Perplexity is retiring in favour of the Agent API (check their docs for the date). That route is kept only as a fallback while Perplexity still serves it. Anthropic web search is on by default; if an admin disabled it for your organization, the engine stops with web_search_disabled (free).
Input
{"brandName": "Acme","brandAliases": ["Acme Cloud"],"brandDomains": ["acme.com"],"competitors": ["Globex | globex.io", "Initech | Initrode | initech.com"],"prompts": ["What is the best CRM for a small business?"],"seedTopics": ["CRM software"],"variantsPerTopic": 3,"engines": ["openai", "perplexity", "gemini"],"openaiApiKey": "<your key>","perplexityApiKey": "<your key>","geminiApiKey": "<your key>","mode": "check","confirmRuns": 2,"minRankChange": 2,"discoverBrands": false,"dryRun": false}
- Prompts: write them as a buyer would, without your brand name.
seedTopicsturns each topic into up to 8 fixed question templates ("What are the best {topic}?", "Which {topic} have the best reviews?", ...); the same text every run so history stays comparable. Up to 100 prompts per run in total. - Competitors:
Name, orName | alias | domain.com. Entries that look like domains are used to detect that competitor's citations. - Matching: whole words, case-insensitive (
Acmematches "acme" but not "Acmeville"); your domains also count as mentions when written in the answer. - Schedule: use Apify Console > Schedules (e.g. daily or weekly) with
mode: monitor. The Actor cannot schedule itself.
Output
One row per prompt x engine (check mode, or monitor rows with changes):
{"type": "answer","promptId": "3f1c0a9b2d4e","prompt": "What is the best CRM for a small business?","engine": "perplexity","model": "openai/gpt-6-luna","brand": "Acme","status": "ok","brandMentioned": true,"brandRank": 2,"brandsMentionedInOrder": ["Globex", "Acme", "Initech"],"brandsMentionedCount": 3,"sentiment": "positive","brandCited": true,"brandCitedUrls": ["https://www.acme.com/crm"],"citedUrls": ["https://www.acme.com/crm", "https://globex.io/pricing", "https://review-site.example/best-crm"],"citedDomains": ["acme.com", "globex.io", "review-site.example"],"competitorsMentioned": ["Globex", "Initech"],"competitorsCited": ["Globex"],"answerText": "For small businesses, Globex is the most popular ... Acme is a great choice if ...","checkedAt": "2026-10-14T08:00:00+00:00","error": null}
brandRank: position of your brand among the tracked brands (yours plus competitors), by first mention in the answer.nullwhen not mentioned.sentiment(optional,analyzeSentiment):positive,negative,mixedorneutral, from a small word list applied to the sentences that mention your brand ("not reliable" counts as negative). It is a hint, not a verdict, and costs no extra API call.- Citations: OpenAI
url_citationannotations, the Perplexitysearch_resultsitems referenced by[n]markers in the answer (all of them if the answer has no markers), Gemini grounding chunks, Anthropic cited search results, plus plain URLs in the answer. Gemini cites throughvertexaisearch.cloud.google.comredirect links whose title is the source domain; that domain is used forcitedDomainsandbrandCited. - With
discoverBrands: true, the summary row also hasdiscoveredBrands: the top 15 capitalised, brand-like names that answers mentioned but you did not track, with the number of answers and engines (a heuristic for English text: common words and all-caps acronyms are skipped, so expect some noise). Use it to find competitors to add. No extra charge; never in the per-answer rows. - A summary row (
"type": "summary") ends each check run: per engineanswers,brandMentionRate,brandCitationRate,averageRank,shareOfVoice(your mentions / all tracked-brand mentions) andshareOfVoiceByBrand. - Failed checks get
status: "error"witherror.code(api_key_rejected,api_no_credit,bad_model,web_search_disabled,truncated_answer,empty_answer,rate_limited,api_unavailable,invalid_request, ...) and are free. A rejected key (including Gemini's HTTP 400 "API key not valid"), no credit, an unknown model or preset, a disabled web search, or 3 empty answers in a row stops that engine for the rest of the run (the others continue). Only rate limits, 5xx errors and network failures are retried (twice, honouringRetry-After). Empty or malformed answers are not retried, so you never pay the provider 3 times for one error. An answer the provider cut off (OpenAIincomplete, Anthropicmax_tokens/pause_turn, GeminiMAX_TOKENS, Perplexity notcompleted) is never counted as a real answer: it is a freetruncated_answerrow, so a cut-off answer cannot create a false "brand lost" alert.
Run-summary row (free). When a run produces no other row (for example a monitor run where nothing changed, or a run stopped at once by your maximum charge or the run timeout), the Actor adds one row {"type": "run_summary", "status": "run_summary", "message": "...", "stopReason": ..., "warnings": [...], "summary": {...}} (summary is the same as the SUMMARY record), so the dataset is never empty. It is never charged. Skip it with type != "run_summary".
Monitor mode (the reason to schedule it)
Set "mode": "monitor" and create a schedule. Each run:
- asks every prompt x engine as above;
- reads
state-<engine>-<promptId>from the named key-value storemonitorStoreName(defaultai-visibility-tracker), compares, and writes the new state. The state is small: mentioned, rank, cited, competitor names, tone, cited domains. No answer text is stored. - appends to
history-<engine>-<promptId>(last 100 runs: time, mentioned, rank, cited) for charts; - outputs a row only when something changed (and on the first run, as a baseline).
emitUnchanged: truegives a row every time.
Each row then has monitor: firstRun, previousCheckAt, previousRank, alertLevel (none, info, warning, critical) and changes, most severe first:
| Change kind | Alert |
|---|---|
mention_lost (brand no longer in the answer) | critical |
citation_lost, rank_down, competitor_appeared, sentiment_turned_negative | warning |
mention_gained, citation_gained, rank_up | info |
You do not pay for flicker. AI answers vary between runs, so by default a mention, citation, rank or new-competitor change is reported (and charged as change-detected) only once it is seen on 2 consecutive runs (confirmRuns, 1-5; 1 = report at once). On the first sighting nothing is output; if the row is output anyway (emitUnchanged) the field is listed in monitor.pendingConfirmation. A change that does not repeat is dropped silently, and the stored state keeps the last confirmed value. Rank moves smaller than minRankChange places (default 2) are ignored, and a rank move must keep the same direction on both runs. A competitor newly appearing goes through the same check (it must appear on 2 runs in a row; a competitor that disappears is dropped silently and never charged). A tone turning negative goes through the same check too, so a tone that alternates between neutral and negative is never charged. history-* always records what was actually observed on each run, flicker included, for your own charts.
Weekly summary: on the first run and then every summaryEveryDays (default 7) the run ends with a summary row, which also has changeSincePreviousSummary (difference in mention rate, citation rate, share of voice and average rank per engine) and changesSincePreviousSummary (number of changed checks in between).
One schedule per monitor store. A run takes a LOCK record and a second run on the same store fails at once while the lock is fresh (older than 6 hours = crashed run, taken over). Use one monitorStoreName per brand or client.
Alerts (Apify integrations; nothing is sent by this Actor)
Actor > Integrations > HTTP webhook (Slack, Zapier, Make) or email on ACTOR.RUN.SUCCEEDED, then read the run's dataset and filter on monitor.alertLevel. In monitor mode an empty dataset means nothing changed.
Dry run
"dryRun": true (pre-ticked in the Console form) needs no keys, makes no API call, charges nothing and never writes the monitor store: built-in sample answers in each API's real response format go through the full analysis, so you see exactly what the output looks like. Untick it after adding your keys; a warning appears in SUMMARY if keys were given while dry run was on.
Pricing
Pay per event, our fee only; your AI-provider API usage is billed to you by the provider.
prompt-checked: once per prompt x engine answer that was stored (a row in check mode; the state record in monitor mode, charged after it was saved).change-detected: once per monitor row with changes, charged with that row (in addition toprompt-checked).summary-generated: once per summary row.- Free: failed calls, skipped engines, error rows, dry runs. Before every API call the Actor checks that your maximum charge per run still covers that check (and the change and summary it may produce), so your API money is never spent on an answer that cannot be delivered.
Example: 25 prompts x 3 engines (75 checks per run).
| Schedule | Checks | Confirmed changes (typical, after the 2-run filter) | Summaries | Our fee per month |
|---|---|---|---|---|
| daily | 75 x 30 = $22.50 | about 1-3 per day = $0.60-1.80 | 4-5 x $0.05 | about $23-25 |
| weekly | 75 x 4.3 = $3.23 | about 2-5 per week = $0.17-0.43 | 4-5 x $0.05 | about $3.60-3.90 |
Without the flicker filter (confirmRuns: 1, minRankChange: 1) a daily run of 75 noisy answers can easily produce 10+ change rows per day (about $6/month more), most of them noise. Plus your own API cost in both cases.
Why this price. Dedicated AI-visibility SaaS tools cost far more and are subscription-locked: Profound is sales-led with an entry price around $499/month, Peec AI starts around EUR 89/month for a small prompt set, and Ahrefs Brand Radar's AI coverage is a paid add-on to an Ahrefs plan (figures as last seen, check their sites). The existing Apify option, apify/chatgpt-search-scraper (rated 3.7 with about 249 users in 30 days at the time of writing; not re-checked), scrapes the ChatGPT website, which breaks when the UI changes and covers one engine. This Actor uses four official APIs, pays per check with no subscription, and keeps your data in your own Apify account.
Good behaviour and privacy
- Calls go only to the four official API hosts above, one at a time, with
delayBetweenCallsMs(default 500 ms) between them. - No personal data is collected: the input is brand names, domains and questions; the output is AI answers about brands.
- Your keys never appear in URLs, logs, rows, SUMMARY or the store.
Limits
100 prompts, 25 competitors and 10 aliases/domains per run. Rank and mention use exact names: misspellings or brand names that are ordinary words (e.g. "Notion", "Monday") can over- or under-count; add aliases, or use a distinctive form ("monday.com"). Sentiment is rule-based English only. API answers can differ from the consumer apps. Provider request/response formats were implemented from their public documentation; if a provider changes its API, that engine returns error rows (free) until the Actor is updated.