# AI Search Visibility Tracker - ChatGPT, Perplexity, Gemini (EU) (`prevailing_glow/ai-search-visibility-tracker`) Actor

Track if ChatGPT, Perplexity & Gemini mention, rank and cite your brand. Native Dutch, German, French, Spanish, Italian & Polish prompts. Your own API keys.

- **URL**: https://apify.com/prevailing\_glow/ai-search-visibility-tracker.md
- **Developed by:** [Dave West](https://apify.com/prevailing_glow) (community)
- **Categories:** AI, SEO tools, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 ai answer checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## AI Search Visibility Tracker: brand mentions in ChatGPT, Perplexity & Gemini (Dutch & EU languages)

**Track whether ChatGPT, Perplexity and Gemini mention, rank and cite your brand when customers ask them for advice, in Dutch, German, French, Spanish, Italian, Polish, Portuguese or English.** Get share of voice against your competitors, the rank of your first mention, the sources the AI cites and whether your own website is one of them. Built for **generative engine optimization (GEO)**, **AI search visibility** monitoring and **brand monitoring in AI answers** for European markets. It uses the official APIs with **your own API keys**: you pay the AI providers directly, and the Actor fee is **$0.01 per successful answer check**.

> **Engine status:** **Gemini** is tested against the live Gemini API. **ChatGPT and Perplexity are beta (not yet tested against the live APIs)**: they are built from the official API docs and tested with mocked responses only.

### Use cases

- **GEO / AI search visibility:** see whether AI assistants recommend your brand for the questions your customers ask, and track it weekly.
- **Brand monitoring in AI answers:** mention rate, rank, sentiment and share of voice versus up to 25 competitors, per engine.
- **Citation and PR targeting:** see which websites ChatGPT and Perplexity cite (your PR and content targets) and whether your own domain is cited.
- **Local EU markets:** native-language prompts and matching for the Netherlands, Belgium, Germany, Austria, Switzerland, France, Spain, Italy, Poland, Portugal and more.
- **Agencies:** one saved task per client and market, scheduled weekly, exported to Sheets, Looker Studio or BI tools.

### What you get

✅ **Brand mention tracking per AI engine**: ChatGPT (OpenAI Responses API with web search, beta), Perplexity (Agent API with web search, beta) and Gemini (Gemini API, model knowledge)
✅ **Share of voice** against up to 25 competitors, per engine and overall
✅ **Rank tracking**: was your brand named first, second or third, and at which position in the AI's top-5 list?
✅ **Citations / sources** (ChatGPT, Perplexity): every URL the AI cites, the domains it relies on, and whether **your domain is cited**
✅ **Native EU-language prompts**: realistic, unbranded customer questions generated in nl, de, fr, es, it, pl, pt or en, for 16 countries
✅ **Language-aware matching**: *Coolblue's*, *Zalandos*, *d'Amazon*, *dell'Esselunga*, *w Biedronce*, *L’Oréal* and *Mueller/Müller* all count as mentions; *Bolton* never counts as *Bol*
✅ **Simple, documented sentiment** about your brand (positive / neutral / negative / mixed) in each language
✅ **History & trends**: compare every run with the previous one (mention rate, share of voice, visibility score, prompts won or lost). Ideal with a weekly schedule
✅ **Bring your own keys**: keys are encrypted secret inputs and never logged or stored in the output
✅ **Reliable**: retries with exponential backoff, Retry-After / 429 handling (also for Gemini's free-tier limits), timeouts, clear errors for invalid keys or empty credit, and a cost cap you control

### Why EU languages matter for AI search visibility

AI answers differ by language and country. Someone in the Netherlands asks *"Wat zijn de beste webwinkels voor elektronica?"*, not *"best electronics stores"*, and gets different brands and sources back. Most AI visibility tools only send English prompts and match English spellings. This Actor:

- generates prompts **in the target language** with grammar handled per language and country (*in den Niederlanden*, *aux Pays-Bas*, *w Polsce*, *negli Stati Uniti*);
- sends the user's **country** to ChatGPT web search and Perplexity (`user_location`) and Perplexity's `language_preference`, plus an optional locale hint in the target language;
- matches brand names **the way each language writes them**: possessives and genitives (nl/de/en), elision (fr/it), hyphenated compounds (*Coolblue-bezorger*, *Zalando-Shop*), Polish case endings (*Biedronka → Biedronki, Biedronce, Biedronką*), German umlaut spellings, curly apostrophes and diacritics.

| Language | Example generated prompt |
|---|---|
| Dutch (NL/BE) | Wat zijn de beste webwinkels voor elektronica in Nederland? |
| German (DE/AT/CH) | Welche Online-Shops für Elektronik sind in Österreich am zuverlässigsten? |
| French (FR/BE/CH/LU) | Quel est le top 5 des banques en ligne en Belgique en 2026 ? |
| Spanish | ¿Qué tiendas online de electrónica me recomiendas para un portátil gaming? |
| Italian | Quali sono delle buone alternative a MediaWorld? |
| Polish | Jakie są najlepsze sklepy internetowe z elektroniką w Polsce? |
| Portuguese (PT) | Quais são as opções mais fiáveis de lojas online de eletrónica em Portugal? |

### Quick start

1. Get the API key(s) for the engines you want: [Google AI Studio (Gemini)](https://aistudio.google.com/apikey), [OpenAI](https://platform.openai.com/api-keys), [Perplexity](https://www.perplexity.ai/account/api). One key is enough to start; a free Gemini key works within Google's free-tier limits.
2. Enter your **brand name**, your **domain** and a few **competitors** (`Name, alias, domain` per line).
3. Pick a **language** and **country**, then either type your own prompts or enter a **category** (e.g. `webwinkels voor elektronica`) and some **keywords**.
4. Paste your keys into the secret key fields and click **Start**. Results appear in the dataset; the share-of-voice summary is in the `SUMMARY` record.

Without any key the Actor runs in **preview mode**. It lists every planned prompt × engine check (status `skipped`) so you can review the prompts, sends nothing and charges nothing. **Dry run** does the same even when keys are filled in.

### How each engine is queried

| Engine | Status | Official API | Live web search | Citations | Locale |
|---|---|---|---|---|---|
| Gemini | ✅ tested against the live API | Gemini API **`generateContent`** (default) or the **Interactions API** (beta at Google), default model `gemini-3.5-flash` | ❌ no (model knowledge only) | none | locale hint (system instruction) |
| ChatGPT | beta, not yet tested against the live API | OpenAI **Responses API** (`/v1/responses`), default model `gpt-6-luna` | ✅ `web_search` tool (the model decides when to search, like ChatGPT) | `url_citation` annotations + all consulted sources | `user_location.country` + locale hint |
| Perplexity | beta, not yet tested against the live API | Perplexity **Agent API** (`/v1/agent`), preset `fast` | ✅ `web_search` tool | numbered citations mapped to search results | `language_preference`, `user_location.country` |

**Gemini answers reflect the model's own knowledge, not live search.** The Actor calls Gemini without Google Search grounding, so a Gemini check measures how well the model "knows" and recommends your brand, has no cited URLs (`citedUrls` is empty and `brandDomainCited` is `null`), and may not reflect very recent changes. ChatGPT and Perplexity measure live AI search visibility.

The Actor never scrapes chat interfaces, Google AI Overviews or search result pages.

### Input example

Keys are secret inputs: paste them in the Console form. Never put keys in prompts, task names or shared JSON.

```json
{
    "brandName": "Coolblue",
    "brandAliases": ["Cool Blue"],
    "brandDomains": ["coolblue.nl", "coolblue.be"],
    "competitors": ["Bol, bol.com", "MediaMarkt, Media Markt, mediamarkt.nl", "BCC, bcc.nl", "Amazon, amazon.nl"],
    "language": "nl",
    "country": "NL",
    "category": "webwinkels voor elektronica",
    "keywords": ["een nieuwe wasmachine", "een gaming laptop"],
    "maxGeneratedPrompts": 5,
    "engines": ["gemini"],
    "runsPerPrompt": 1,
    "historyStoreName": "ai-visibility-coolblue",
    "geminiApiKey": "<your Gemini API key>"
}
```

| Option | What it does | Default |
|---|---|---|
| `brandName`, `brandAliases`, `brandDomains` | Brand to track, other spellings, your website domain(s) | required |
| `competitors` | `Name, alias, domain` per line (max 25) | none |
| `language`, `country` | Prompt and matching language; market sent to the engines | `en` / main country of the language |
| `prompts` | Your own prompts (max 200). If set, category/keywords are ignored | none |
| `category`, `keywords`, `maxGeneratedPrompts` | Generate prompts in the chosen language | 5 prompts |
| `includeBrandPrompts` | Also generate prompts that name your brand (*"What do you think of …?"*) | off |
| `engines` | `chatgpt` (beta), `perplexity` (beta), `gemini` | all three |
| `runsPerPrompt` | Ask each prompt several times to measure *how often* you appear | 1 |
| `openaiModel`, `openaiWebSearch`, `openaiSearchContextSize` | ChatGPT model and web search settings | `gpt-6-luna`, on, `medium` |
| `perplexityPreset`, `perplexityModel` | Perplexity Agent API preset or model | `fast` |
| `geminiModel`, `geminiEndpoint` | Gemini model and API endpoint | `gemini-3.5-flash`, `generateContent` |
| `geminiFallbackModel` | Second Gemini model, used only while the main one keeps answering 503 "high demand" (`none` = off) | `gemini-3.5-flash-lite` |
| `localeHint` | "The user is in <country>, answer in <language>" instruction (ChatGPT, Gemini) | on |
| `maxChecks` | Safety cap on prompt × engine × run checks | 200 |
| `maxConcurrency`, `maxConcurrencyPerEngine` | Parallel API calls overall / per provider | 4 / 2 |
| `requestTimeoutSecs`, `maxRetries` | Per-call timeout and retries | 120 s / 3 |
| `historyStoreName` | Named key-value store for run-over-run comparison | none |
| `includeAnswerText`, `dryRun` | Store full answers; plan only | on / off |

**Gemini model choice:** `gemini-3.5-flash` is the default because it works on Google's free tier (tested Oct 2026; `gemini-3.8-flash` was repeatedly "busy" for free-tier keys). With a paid key, `gemini-3.8-flash` (newest Flash, introductory price until 31 Dec 2026) or `gemini-3.1-flash-lite` (cheapest) are good alternatives. Free-tier users: set *Max concurrency per engine* to 1.

### Output

One dataset row per **prompt × engine × run** (views: *Visibility overview*, *Citations*, *Answers*). Real Gemini example (answer shortened):

```json
{
    "engine": "gemini",
    "model": "gemini-3.5-flash",
    "language": "nl",
    "country": "NL",
    "prompt": "Wat zijn de beste webwinkels voor elektronica in Nederland?",
    "run": 1,
    "status": "ok",
    "answerText": "Wat de \"beste\" webwinkel is voor elektronica in Nederland, hangt erg af van wat je zoekt … ### 1. De Allrounders (Beste Service & Snelheid) *   **Coolblue** …",
    "brandMentioned": true,
    "brandMentionCount": 2,
    "brandFirstMentionRank": 1,
    "brandListPosition": 1,
    "brandDomainCited": null,
    "sentiment": "positive",
    "sentimentScore": 1,
    "competitorsMentioned": ["Bol", "MediaMarkt", "BCC"],
    "competitorMentions": [{ "name": "Bol", "mentioned": true, "mentionCount": 2, "firstMentionRank": 2, "listPosition": 2, "domainCited": false }],
    "citedUrls": [],
    "webSearchUsed": false,
    "inputTokens": 30,
    "outputTokens": 1954,
    "durationMs": 18002
}
```

ChatGPT and Perplexity rows have the same fields, plus `citedUrls`, `citedDomains`, `brandCitationUrls`, `brandDomainCited` (`true`/`false`), `searchQueries` and, for Perplexity, `providerCostUsd`.

The **`SUMMARY`** record (key-value store) contains, overall and per engine: mention rate, share of voice, visibility score, average first-mention rank and list position, domain citation rate, a sentiment breakdown, statistics for each competitor, the top cited domains, tokens used, a prompt × engine matrix and, with a history store, the change since the previous run. It is written even when a run is cut short: shortly before the run timeout the Actor stops starting new checks and saves the results so far (`status: "partial"`, `stopReason: "timeout"`); an aborted run and a platform migration also leave a SUMMARY of the finished checks (`stopReason` `"aborted"` / `"migrating"`).

Failed calls (`status: "error"`, e.g. invalid key or timeout) and skipped checks (`status: "skipped"`, e.g. missing key) are listed too, with a clear `errorMessage`, and are **not charged**.

### Metrics explained

| Metric | Definition |
|---|---|
| Brand mentioned | Brand name, alias or domain appears in the answer text. Citation links and footnote markers alone do not count. |
| First-mention rank | 1 = your brand was the first tracked name (brand or competitor) in the answer. |
| List position | Position of the first numbered / bulleted / table item that names your brand ("#2 in the AI's top 5"). Numbering continues across description paragraphs and restarts at a new "1."; bullets nested under numbered items are treated as details. |
| Mention rate | Answers mentioning the brand ÷ successful answers. |
| Share of voice | Answers mentioning your brand ÷ the sum of answers mentioning your brand and each competitor (presence-based, so a long answer repeating one name does not inflate it). |
| Visibility score | 100 × the average of 1/first-mention rank over all answers (0 when not mentioned). 100 = always named first. |
| Domain citation rate | Answers citing a URL on your domain (subdomains included) ÷ successful answers from engines that cite URLs (ChatGPT, Perplexity). `null` for Gemini. |
| Sentiment | Lexicon-based, per language: positive and negative words in the sentences that mention your brand, with negation handling (*niet*, *nicht*, *pas*, *no*, *nie* …). score = (pos − neg) / (pos + neg). Good for spotting trends, not a full classifier; a sentence that also names competitors counts fully. |

### History and scheduling

Set **History store name** (e.g. `ai-visibility-coolblue`) and create a weekly **Schedule** for a saved task. Each run is compared with the previous run for the same brand + language + country: deltas per engine, prompts where your brand **newly appears** or **dropped out**, and `brandMentionedPreviously` on every row. The last 30 runs are kept. To track several markets (for example Dutch for NL plus French for BE), create one task per market.

### What does it cost?

**Actor fee: $0.01 per successful answer check** (`answer-check` event = one prompt answered by one engine, analysed and saved). Failed and skipped checks are free. You set the maximum cost per run, and the Actor never starts an AI call that the remaining budget could not pay for.

**Your own AI API costs** are billed by the providers to your own key (typical per check with the default settings, Oct 2026 list prices):

| Engine | Typical cost on your key |
|---|---|
| Gemini, `gemini-3.5-flash` | **$0 on Google's free tier** (within its rate limits). Paid tier ≈ $0.01–0.02 (answers use ~2,000 output tokens including thinking); `gemini-3.8-flash` ≈ $0.005–0.008, `gemini-3.1-flash-lite` ≈ $0.002–0.004 |
| ChatGPT (beta), `gpt-6-luna` + web search | ≈ $0.011–0.02 (OpenAI charges $10 per 1,000 web search calls + tokens) |
| Perplexity (beta), `fast` preset | ≈ $0.002–0.004 (the exact cost per call is in `providerCostUsd`) |

Example: 10 prompts × 3 engines = 30 checks = $0.30 Actor fee plus roughly $0.15–0.45 on your own API keys.

### Methodology and limitations

- **API answers are not identical to the consumer apps.** ChatGPT, Perplexity and Gemini apps add their own system prompts, personalisation, memory and model routing. The APIs are the closest *official*, reproducible way to measure the same models and search, which is how GEO tools measure AI visibility. For answers closer to ChatGPT itself, use a larger model such as `gpt-6.1-sol`.
- **Answers vary between calls.** Use `runsPerPrompt` > 1 and track trends over time rather than single answers.
- **Gemini answers come from model knowledge** (no live web search, no citations). That measures how well the model "knows" your brand, while ChatGPT and Perplexity measure live AI search visibility.
- **ChatGPT and Perplexity are beta**: the request and response handling follows the official API docs and is covered by mocked tests, but has not yet been run against the live APIs.
- Matching is literal (with language-aware variants). Add aliases for product names and old names, and avoid generic words as aliases.

### Privacy and data

- The Actor collects **no personal data**. It sends only your prompts to the AI providers and stores their answers and citations. Do not put personal data in prompts, and track brands and companies, not private individuals.
- API keys are **secret inputs** (encrypted by Apify, never logged, and removed from error messages). The Actor developer cannot see them.
- OpenAI and Gemini Interactions requests are sent with `store: false`. Each provider's own data policy applies; on Google's *free* Gemini tier, Google may use prompts and answers to improve its products.
- Gemini is called without Google Search grounding, so no Google Search results are stored or analysed.

### FAQ

**Do I need all three API keys?** No. Engines without a key are skipped and listed with status `skipped`.

**What happens with an invalid key or empty credit?** The first call to each engine runs on its own as a probe. If the key is rejected (401/403), the account is out of credit, or the model does not exist, that engine stops immediately with a clear message, and the other engines continue. If nothing succeeds, the run fails with the reason.

**What about rate limits?** HTTP 429 and 5xx responses (including Gemini's "high demand" 503) are retried with exponential backoff and jitter. Retry-After headers and Gemini's retry delay ("retry in 54 s") are respected, and the engine pauses so parallel calls don't pile up. Gemini gets a longer backoff (5 s doubling up to 60 s), and if its model stays overloaded it switches to a second Flash model (`geminiFallbackModel`). Free-tier 429s with a retry hint are waited out and retried; only when Google still refuses does Gemini stop for the run with the message *"daily free-tier quota reached"* (the quota resets at midnight Pacific time). Lower *Max concurrency per engine* (1 for free tiers).

**Is this generative engine optimization (GEO) software?** It is the measurement part: it shows where you stand in AI answers, which sources the engines trust (your PR and content targets) and how that changes after you optimise.

**Can I track only one engine?** Yes. Select only `gemini`, `chatgpt` or `perplexity` as the engine.

**Why does Gemini show no citations?** Gemini runs without Google Search grounding (Google's terms restrict storing and analysing grounded results), so its answers come from model knowledge and contain no source links.

**Can I export to Google Sheets or Looker Studio?** Yes, via the dataset export (CSV/Excel/JSON), the Apify API, or integrations such as Make, Zapier and n8n.

### Support

Found a bug or need another language, country or engine? Open an issue on the Actor's **Issues** tab. Feature requests for EU markets are very welcome.

# Actor input Schema

## `brandName` (type: `string`):

The brand you want to track, e.g. <code>Coolblue</code>. Short all-caps names (2-4 letters, e.g. <code>ING</code>, <code>KPN</code>) are matched case-sensitively.

## `brandAliases` (type: `array`):

Other names the AI might use: product names, old names, spelling variants (e.g. <code>Cool Blue</code>). Avoid generic words: every alias counts as a brand mention.

## `brandDomains` (type: `array`):

Your website domain(s), e.g. <code>coolblue.nl</code>. Used to detect whether the AI <b>cites your site</b> as a source (subdomains count) and as extra mention aliases.

## `competitors` (type: `array`):

One competitor per line: <code>Name, alias, domain</code> (comma or | separated), e.g. <code>MediaMarkt, Media Markt, mediamarkt.nl</code>. Used for share of voice, ranking and competitor citations. Max 25.

## `language` (type: `string`):

Language of the generated prompts, the locale hint and the mention/sentiment matching. Custom prompts should be written in this language.

## `country` (type: `string`):

Market to simulate: sent as the user's approximate location to ChatGPT web search and Perplexity, and mentioned in the locale hint. Default: the main country of the language (nl → Netherlands, de → Germany, ...). Use e.g. Dutch + Belgium for Flanders.

## `prompts` (type: `array`):

Questions to ask the AI engines, exactly as a customer would type them (max 200). <b>If set, category/keywords are ignored.</b> Leave empty to auto-generate prompts.

## `category` (type: `string`):

Your product/service category as a <b>plural noun phrase in the chosen language</b>, e.g. nl <code>webwinkels voor elektronica</code>, de <code>Online-Shops für Elektronik</code>, fr <code>boutiques d'électronique en ligne</code>.

## `keywords` (type: `array`):

Topics or needs, in the chosen language, e.g. <code>een nieuwe wasmachine</code>, <code>een gaming laptop</code>. Each keyword adds prompts like <i>"Wat zijn de beste opties voor {keyword} in Nederland?"</i>.

## `maxGeneratedPrompts` (type: `integer`):

How many prompts to generate from category/keywords/competitors.

## `includeBrandPrompts` (type: `boolean`):

Also generate prompts that name your brand (<i>"What do you think of {brand}?"</i>, <i>"{brand} or {competitor}?"</i>). Useful for sentiment; these always mention the brand, so they are excluded from discovery-style tracking by default.

## `localeHint` (type: `boolean`):

Tell ChatGPT and Gemini (via system instructions) where the user is and to answer in the chosen language, e.g. <i>"De gebruiker bevindt zich in Nederland. Antwoord in het Nederlands."</i> Perplexity gets <code>language\_preference</code> and location parameters instead.

## `engines` (type: `array`):

Which AI engines to ask. Each prompt is sent to each selected engine (one <b>check</b> each). Gemini is tested against the live API. <b>ChatGPT and Perplexity are beta</b>: built from the official API docs but not yet tested against the live APIs.

## `openaiApiKey` (type: `string`):

Your key from <a href='https://platform.openai.com/api-keys' target='_blank'>platform.openai.com/api-keys</a> (starts with <code>sk-</code>). Needed for ChatGPT checks (beta, not yet tested against the live API).

## `perplexityApiKey` (type: `string`):

Your key from the <a href='https://www.perplexity.ai/account/api' target='_blank'>Perplexity API portal</a> (starts with <code>pplx-</code>). Needed for Perplexity checks (beta, not yet tested against the live API).

## `geminiApiKey` (type: `string`):

Your key from <a href='https://aistudio.google.com/apikey' target='_blank'>Google AI Studio</a> (starts with <code>AIza</code> or <code>AQ.</code>). Needed for Gemini checks. A free-tier key works within Google's free limits (note: on the free tier Google may use prompts and answers to improve its products).

## `runsPerPrompt` (type: `integer`):

AI answers vary between calls. Ask each prompt several times per engine to measure how <i>often</i> the brand appears (each run is a separate check).

## `openaiModel` (type: `string`):

ChatGPT is <b>beta</b> (not yet tested against the live API). Any OpenAI model that supports the Responses API web search tool, e.g. <code>gpt-6-luna</code> (cheapest), <code>gpt-6.1-sol</code> (closer to ChatGPT's own answers).

## `openaiWebSearch` (type: `boolean`):

Give the model OpenAI's <code>web\_search</code> tool (it decides when to search, like ChatGPT). Required for cited URLs. OpenAI bills web search calls per call on your key.

## `openaiSearchContextSize` (type: `string`):

How much web content OpenAI retrieves per search.

## `perplexityPreset` (type: `string`):

Perplexity is <b>beta</b> (not yet tested against the live API). Agent API preset. Default <code>fast</code>, or none when a model is set below.

## `perplexityModel` (type: `string`):

Optional Agent API model override, e.g. <code>perplexity/sonar</code>. Leave empty to use the preset's model.

## `geminiModel` (type: `string`):

Gemini model ID. Default <code>gemini-3.5-flash</code> (works on the free tier). Alternatives: <code>gemini-3.8-flash</code> (newest; cheaper on paid keys until 31 Dec 2026, but often busy on the free tier), <code>gemini-3.1-flash-lite</code> (cheapest). Gemini runs <b>without</b> Google Search grounding, so its answers reflect the model's own knowledge, not live search, and contain no cited URLs.

## `geminiFallbackModel` (type: `string`):

Used only when the Gemini model above still answers HTTP 503 "high demand" after all retries (after two such checks in a row it is tried first for the rest of the run). Default <code>gemini-3.5-flash-lite</code> (works on the free tier). Each row's <code>model</code> field shows the model that actually answered. Enter <code>none</code> to disable the fallback.

## `geminiEndpoint` (type: `string`):

Which Gemini API endpoint to call. <code>generateContent</code> is Google's stable endpoint; the Interactions API is marked beta by Google. Both were tested against the live API.

## `maxOutputTokens` (type: `integer`):

Optional cap on answer length per call (reduces cost on your key). Leave empty for the provider default; note that reasoning models count reasoning tokens toward this limit.

## `maxChecks` (type: `integer`):

Safety cap on prompt × engine × run checks (protects your API budget and the run cost). The run's <b>Maximum cost per run</b> setting is also respected: no AI call is started that the remaining budget could not pay for.

## `maxConcurrency` (type: `integer`):

How many API calls run in parallel overall.

## `maxConcurrencyPerEngine` (type: `integer`):

Parallel calls per provider. Lower it if your API tier has low rate limits; HTTP 429 responses are retried with backoff and pause that engine.

## `requestTimeoutSecs` (type: `integer`):

Timeout per API call (web search answers can take 10-60 s).

## `maxRetries` (type: `integer`):

Retries for timeouts, network errors, HTTP 429 and 5xx, with exponential backoff + jitter and Retry-After support. Gemini waits longer (5 s doubling up to 60 s per wait, and Google's "retry in N s" hints of up to 90 s), because its 503 "high demand" spells and free-tier limits need time to clear. Invalid keys, exhausted credits and a reached daily free-tier quota are not retried further: that engine is stopped with a clear error.

## `historyStoreName` (type: `string`):

Name of a key-value store to keep results between runs (e.g. <code>ai-visibility-coolblue</code>). Each run is compared with the previous one: deltas in mention rate, share of voice and visibility score, plus prompts where the brand newly appeared or disappeared. Ideal with a weekly Schedule.

## `includeAnswerText` (type: `boolean`):

Store the full AI answer in each row. Turn off for smaller datasets.

## `dryRun` (type: `boolean`):

Only build and list the planned prompt × engine checks; nothing is sent to the AI providers and nothing is charged.

## Actor input object example

```json
{
  "brandName": "Coolblue",
  "brandAliases": [
    "Cool Blue"
  ],
  "brandDomains": [
    "coolblue.nl",
    "coolblue.be"
  ],
  "competitors": [
    "Bol, bol.com",
    "MediaMarkt, Media Markt, mediamarkt.nl",
    "BCC, bcc.nl"
  ],
  "language": "nl",
  "country": "NL",
  "prompts": [],
  "category": "webwinkels voor elektronica",
  "keywords": [
    "een nieuwe wasmachine",
    "een gaming laptop"
  ],
  "maxGeneratedPrompts": 5,
  "includeBrandPrompts": false,
  "localeHint": true,
  "engines": [
    "chatgpt",
    "perplexity",
    "gemini"
  ],
  "runsPerPrompt": 1,
  "openaiModel": "gpt-6-luna",
  "openaiWebSearch": true,
  "openaiSearchContextSize": "medium",
  "geminiModel": "gemini-3.5-flash",
  "geminiFallbackModel": "gemini-3.5-flash-lite",
  "geminiEndpoint": "generateContent",
  "maxChecks": 200,
  "maxConcurrency": 4,
  "maxConcurrencyPerEngine": 2,
  "requestTimeoutSecs": 120,
  "maxRetries": 3,
  "includeAnswerText": true,
  "dryRun": false
}
```

# Actor output Schema

## `results` (type: `string`):

One row per prompt x engine x run: answer, brand mentioned, rank, competitors, citations, sentiment.

## `visibility` (type: `string`):

Same dataset, compact visibility view (mention, rank, list position, citation, sentiment).

## `citations` (type: `string`):

Same dataset, cited URLs and sources per answer.

## `summary` (type: `string`):

Share of voice, mention rate, visibility score and top cited domains per engine, per-prompt matrix and history comparison.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "brandName": "Coolblue",
    "brandAliases": [
        "Cool Blue"
    ],
    "brandDomains": [
        "coolblue.nl",
        "coolblue.be"
    ],
    "competitors": [
        "Bol, bol.com",
        "MediaMarkt, Media Markt, mediamarkt.nl",
        "BCC, bcc.nl"
    ],
    "language": "nl",
    "country": "NL",
    "prompts": [],
    "category": "webwinkels voor elektronica",
    "keywords": [
        "een nieuwe wasmachine",
        "een gaming laptop"
    ],
    "engines": [
        "chatgpt",
        "perplexity",
        "gemini"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("prevailing_glow/ai-search-visibility-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "brandName": "Coolblue",
    "brandAliases": ["Cool Blue"],
    "brandDomains": [
        "coolblue.nl",
        "coolblue.be",
    ],
    "competitors": [
        "Bol, bol.com",
        "MediaMarkt, Media Markt, mediamarkt.nl",
        "BCC, bcc.nl",
    ],
    "language": "nl",
    "country": "NL",
    "prompts": [],
    "category": "webwinkels voor elektronica",
    "keywords": [
        "een nieuwe wasmachine",
        "een gaming laptop",
    ],
    "engines": [
        "chatgpt",
        "perplexity",
        "gemini",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("prevailing_glow/ai-search-visibility-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "brandName": "Coolblue",
  "brandAliases": [
    "Cool Blue"
  ],
  "brandDomains": [
    "coolblue.nl",
    "coolblue.be"
  ],
  "competitors": [
    "Bol, bol.com",
    "MediaMarkt, Media Markt, mediamarkt.nl",
    "BCC, bcc.nl"
  ],
  "language": "nl",
  "country": "NL",
  "prompts": [],
  "category": "webwinkels voor elektronica",
  "keywords": [
    "een nieuwe wasmachine",
    "een gaming laptop"
  ],
  "engines": [
    "chatgpt",
    "perplexity",
    "gemini"
  ]
}' |
apify call prevailing_glow/ai-search-visibility-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,prevailing_glow/ai-search-visibility-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hFSlvcKqe9pmpXdKA/builds/z1KP2qWI4l9dbNqxx/openapi.json
