# AI Search Visibility Tracker: ChatGPT, Gemini, Perplexity (`layerwiselabs/ai-visibility-tracker`) Actor

See how often ChatGPT, Gemini and Perplexity name and cite your brand versus competitors, with a confidence range for every rate and changes since the last run. Official APIs, 41 countries, full answers and sources.

- **URL**: https://apify.com/layerwiselabs/ai-visibility-tracker.md
- **Developed by:** [Layerwise Labs](https://apify.com/layerwiselabs) (community)
- **Categories:** AI, SEO tools, Marketing
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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: ChatGPT, Gemini, Perplexity

When buyers ask ChatGPT, Gemini or Perplexity "what is the best CRM for a small agency?", some brands get named and others don't. This Actor asks your buyers' questions, reads every answer, and tells you how often your brand is named, where it appears, which sites are cited, and how you compare to your competitors.

What makes it different:

- **Every rate comes with a range.** AI answers change from one ask to the next. The Actor asks each prompt several times and reports "named in 4 of 6 answers, likely between 30 % and 90 %", not a single number that may be luck.
- **Real changes are marked as real.** Run it weekly and each rate is compared with the previous run. A statistical test (Fisher's exact test) tells you whether a drop is a real change or just noise.
- **Plain rules, no AI judging AI.** Mentions are found with fixed matching rules: whole words only, case, umlauts and accents ignored ("Mueller" finds "Müller"), other names and domains included, source links left out (a cited hubspot.com page is a citation, not a mention). The same answer always gives the same result, and you can check every row against the full answer text.
- **41 countries, every engine.** Set a country and city, and the question is asked as a user from there: on ChatGPT and Perplexity through the search location, on Gemini through the instructions.
- **Fair, transparent pricing.** A small price per answer plus only the web searches the engine really runs, so simple questions stay cheap. $0.003 per answer with your own API key. No start fee, no report fee, and requests that fail at the provider are free.

### What you get

**One row per answer** (prompt × engine × sample):

| Field | Meaning |
|---|---|
| `brandMentioned`, `brandMentions` | Whether and how often your brand (or one of its other names or domains) is named |
| `brandListRank` | Your position in the first list item that is about you (1 = first item). An item is about the tracked brand it names first, so in "1. HubSpot, better than Pipedrive" the item is HubSpot's. Only top-level items count: numbered or bulleted lines, numbered headings and bold numbered lines, not their descriptions or nested points |
| `brandMentionOrder` | 1 if your brand is the first tracked brand named in the answer, 2 if second, and so on |
| `brandFirstMentionAt` | Where you are first named, as a share of the answer (0 = very start) |
| `brandCited`, `brandCitedUrls` | Whether the engine cites a page on your domains as a source, and which pages |
| `competitors` | For every competitor: mentioned, mentions, list rank, mention order and cited |
| `brandsInOrder` | All tracked brands in the order they are named |
| `citations` | Sources the answer cites (as links or numbered source markers), with domain and title |
| `sourcesConsulted` | Everything the engine's search returned or read, cited or not |
| `searchQueries`, `searched`, `webSearches` | What the engine searched for, and how many web searches it ran |
| `answerText` | The full answer |
| `model`, `answeredAt`, `country`, `city` | Exact model version, time and location |

**A summary** in the `OUTPUT` record of the run's key-value store, for all answers, per engine and per prompt × engine:

- brand mention rate, citation rate and "named first" rate, each with a 95 % range (Wilson interval)
- change since the previous run with p-value and `significant: true/false`
- share of voice: how the answers that name tracked brands divide among them (each answer counts once per brand it names, so one long answer repeating a name cannot dominate)
- average list rank, competitor rates, the 15 most cited domains

Example (shortened):

```json
{
  "brand": "HubSpot",
  "engines": {
    "chatgpt": {
      "answers": 6,
      "brandMentionRate": {
        "rate": 0.6667, "ci95": [0.3, 0.9032], "hits": 4, "samples": 6,
        "change": {"previousRate": 0.8333, "delta": -0.1667, "pValue": 1.0, "significant": false}
      },
      "brandCitedRate": {"rate": 0.3333, "ci95": [0.0968, 0.7], "hits": 2, "samples": 6},
      "brandAverageListRank": 2.0,
      "shareOfVoice": {"HubSpot": 0.4, "Pipedrive": 0.4, "Zoho CRM": 0.2},
      "topCitedDomains": [{"domain": "capterra.com", "answers": 3}]
    }
  }
}
```

### How to use it

1. Enter your **brand**, its **other names** and **domains**.
2. Add **competitors**, one per line. Other names and domains go after a `|`: `Pipedrive | Pipedrive CRM | pipedrive.com`. The more of your market you add, the sharper the list ranks: each list item is credited to the brand it is about.
3. Add the **prompts** your buyers ask, in their language. Keep the list stable to see trends.
4. Choose the **engines**, the **samples per prompt** (3 is a good start) and optionally a **country** and **city**.
5. Run it once, or save it as a task and schedule it weekly. Each saved task keeps its own history. Changing the brand, its other names or domains, competitors, prompts, engines, models, location, match case or switching to or from your own API key starts a new one.

### Pricing

You pay for the answers you receive. Requests that fail at the provider (errors, outages, a rejected key) are free. ChatGPT and Gemini decide for each question whether to search the web, and you pay only for the searches they actually run (the `webSearches` field of every answer shows them).

| Engine | Price per answer | Per web search |
|---|---|---|
| ChatGPT | $0.02 | $0.0125 |
| Gemini | $0.03 | $0.0175 |
| Perplexity | $0.025 | included |
| Any engine with your own API key | $0.003 | billed by the provider |

Examples: a ChatGPT answer with 2 web searches costs $0.045, a Gemini answer that needs no search $0.03. 10 prompts × Perplexity × 3 samples = 30 answers = $0.75 per run, or $0.09 with your own key.

The listed prices cover normal answers, including long lists. Only unusually large requests, such as an answer cut off at the length limit or a prompt asking for pages of text, are charged at cost as `provider-cost` events ($0.001 each): what the AI provider bills, plus the platform's share, the run time and a 10% margin for rounding. The same at-cost rule applies to an answer the provider has already billed but that arrives too late for the run timeout or cannot be stored, so for such an answer you pay its cost, never the full price. With your own key the same applies to unusually slow answers (some reasoning models think for minutes), whose run time is charged at cost. If the platform restarts a run, the extra run time is charged at cost too, and answers already collected are never charged again.

Your costs stay under control:

- The run never goes over the maximum cost you set, and keeps everything collected up to that point.
- If an AI provider rejects the API key, the whole run stops at once, so you can fix the key and start again. During an outage of one engine the run stops after a few failed answers instead of carrying on, and the failed requests themselves are not charged. Everything collected so far stays in the dataset and the summary.
- An answer starts only when a long answer with several web searches still fits your maximum cost.
- No new answers start in the last 5 minutes before the run timeout. Keep the timeout at 10 minutes or more, and give large setups enough time to complete: only a complete run is saved for the next comparison.
- At the standard price a prompt can be up to 1,000 characters, and an answer up to about 8,000 tokens, with one search round on Perplexity: plenty for a full answer with a long list. With your own key you set the limits.

### Official APIs: clean, repeatable measurements

This Actor uses the official APIs of OpenAI, Google and Perplexity with web search switched on. That makes it reliable, fast and free of logins or browser tricks. It also means you measure the models themselves, so answers can differ from what one person sees in their ChatGPT, Gemini or Perplexity app:

- The apps may use a different or newer model than the API. The model of every answer is in the `model` field. At the standard price the Actor uses gpt-5-mini (ChatGPT), gemini-3.8-flash (Gemini) and Sonar (Perplexity); with your own API key you can choose any model.
- The apps personalise answers with chat history, memory and the user's account. The API answers a fresh, anonymous user.
- Every engine decides itself whether a question needs a web search, as in the apps. The `searched` field shows when it did.

The result is a consistent, repeatable measurement of how these models talk about your market, rather than a screenshot of one person's app. For tracking trends and comparing brands that is exactly what you want: the same questions, asked the same way, every week.

### Your own API keys

With your own key, the provider bills you directly for the answer and this Actor charges only $0.003 per answer. Keys are stored encrypted by Apify and never written to the dataset or log.

- OpenAI: platform.openai.com, API keys
- Gemini: aistudio.google.com, Get API key (turn on billing for Google Search)
- Perplexity: perplexity.ai, API settings

### FAQ

**How many samples do I need?** For a quick look, 1. For numbers you report, 3 to 5. The range in `ci95` shows how sure a rate is: with 3 samples it is wide, with 10 it gets narrow.

**Which run is a new run compared with?** With the last complete run, one that answered every prompt on every engine, so you always compare like with like.

**Why is a change marked as not significant?** With few samples, 3 of 5 one week and 1 of 5 the next can happen by chance. The Actor only marks a change as significant when chance is an unlikely explanation (p < 0.05). Add samples to see smaller changes.

**My brand is a common word.** Turn on **Match case**, so "Notion" counts but "notion" does not.

**Does it work for other languages?** Yes. Prompts can be in any language, and matching handles accents and umlauts. In languages that inflect names, add the common forms as other names, one per line (Polish: `HubSpota`, `HubSpotem`), and every form counts as your brand. For competitors they go after a `|`: `Pipedrive | Pipedrive'a`.

**Can I use it with Make, Zapier, n8n or an AI agent?** Yes, like any Apify Actor: through the API, integrations, webhooks or the Apify MCP server.

# Changelog

This Actor's version history is a separate document: https://apify.com/layerwiselabs/ai-visibility-tracker/changelog.md

# Actor input Schema

## `brand` (type: `string`):

The brand, company or product you want to find in AI answers.

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

Other names that count as your brand, e.g. "HubSpot CRM" or inflected forms such as "HubSpota". Case, umlauts and accents are ignored ("Mueller" finds "Müller").

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

Your websites, e.g. "hubspot.com". An answer that links to them (or a subdomain) counts as citing you.

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

One competitor per line. Add other names and domains after a "|": "Pipedrive | Pipedrive CRM | pipedrive.com".

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

The questions your buyers ask, in their language. Keep the same list over time to see trends.

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

Each answer is billed per engine.

## `samplesPerPrompt` (type: `integer`):

How often each prompt is asked per engine. AI answers change from one ask to the next; more samples give a narrower range for each rate.

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

Ask as a user in this country. Leave empty for no location.

## `city` (type: `string`):

Optional, e.g. "Munich". Makes local answers more precise.

## `compareWithPreviousRun` (type: `boolean`):

Show how each rate changed since the previous run with the same brand, competitors, names, matching rules, prompts, engines, models, location and API keys (yours or ours), and whether the change is larger than chance. A saved task keeps its own history; changing these settings starts a new one. Runs with this option off are not kept as history.

## `matchCase` (type: `boolean`):

Only count names written with the same capital letters. Use it for brands that are also common words, like "Notion" or "Apple".

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

Optional. With your own key OpenAI bills you directly and each answer costs only the lower own-key price.

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

Optional, same as above. Keys at aistudio.google.com, with billing turned on for Google Search.

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

Optional, same as above. Keys at perplexity.ai, API settings.

## `chatgptModel` (type: `string`):

Without your own key: gpt-5-mini or gpt-5-nano. With your own key: any OpenAI model with web search.

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

Without your own key: gemini-3.8-flash or gemini-3.1-flash-lite. With your own key: any Gemini model with Google Search grounding.

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

Without your own key: perplexity/sonar. With your own key: any Agent API model.

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

Lower it if your own API key has tight rate limits.

## Actor input object example

```json
{
  "brand": "HubSpot",
  "brandAliases": [
    "HubSpot CRM"
  ],
  "brandDomains": [
    "hubspot.com"
  ],
  "competitors": [
    "Pipedrive | pipedrive.com",
    "Salesforce | salesforce.com",
    "Zoho CRM | Zoho | zoho.com"
  ],
  "prompts": [
    "What is the best CRM for a small marketing agency?",
    "Which CRM has a good free plan?"
  ],
  "engines": [
    "chatgpt",
    "gemini"
  ],
  "samplesPerPrompt": 3,
  "compareWithPreviousRun": true,
  "matchCase": false,
  "chatgptModel": "gpt-5-mini",
  "geminiModel": "gemini-3.8-flash",
  "perplexityModel": "perplexity/sonar",
  "maxConcurrency": 5
}
```

# Actor output Schema

## `answers` (type: `string`):

One item per answer (prompt × engine × sample): brand and competitor mentions, list rank, citations, sources and the full answer.

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

One item per link cited in an answer, with domain and title.

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

Mention, citation and named-first rates with 95 % ranges, changes since the previous run, share of voice and top cited domains.

# 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 = {
    "brand": "HubSpot",
    "brandAliases": [
        "HubSpot CRM"
    ],
    "brandDomains": [
        "hubspot.com"
    ],
    "competitors": [
        "Pipedrive | pipedrive.com",
        "Salesforce | salesforce.com",
        "Zoho CRM | Zoho | zoho.com"
    ],
    "prompts": [
        "What is the best CRM for a small marketing agency?",
        "Which CRM has a good free plan?"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("layerwiselabs/ai-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 = {
    "brand": "HubSpot",
    "brandAliases": ["HubSpot CRM"],
    "brandDomains": ["hubspot.com"],
    "competitors": [
        "Pipedrive | pipedrive.com",
        "Salesforce | salesforce.com",
        "Zoho CRM | Zoho | zoho.com",
    ],
    "prompts": [
        "What is the best CRM for a small marketing agency?",
        "Which CRM has a good free plan?",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("layerwiselabs/ai-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 '{
  "brand": "HubSpot",
  "brandAliases": [
    "HubSpot CRM"
  ],
  "brandDomains": [
    "hubspot.com"
  ],
  "competitors": [
    "Pipedrive | pipedrive.com",
    "Salesforce | salesforce.com",
    "Zoho CRM | Zoho | zoho.com"
  ],
  "prompts": [
    "What is the best CRM for a small marketing agency?",
    "Which CRM has a good free plan?"
  ]
}' |
apify call layerwiselabs/ai-visibility-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,layerwiselabs/ai-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/4T7hqawpJdG9e6eBy/builds/lHlBGuxufMkZqUSZ1/openapi.json
