# AI Visibility Tracker - ChatGPT, Perplexity, Claude Mentions (`maksym_kotenko/ai-visibility-tracker`) Actor

Track whether OpenAI, Perplexity and Claude mention and cite your brand for the prompts your buyers ask: rank, list position, cited domains, competitors, share of voice and changes since the last run. Official APIs with your own keys, small fee per check.

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

## Pricing

from $6.00 / 1,000 checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Visibility Tracker - ChatGPT, Perplexity, Claude Mentions

Find out whether AI search recommends **your brand** or your competitors. Give the Actor your brand, your competitors and the questions your buyers ask; it asks **OpenAI (web search)**, **Perplexity** and **Claude (web search)** through their official APIs and tells you, for every answer:

- whether your brand is **mentioned**, and its **rank** among all tracked brands,
- its **position in the answer's list** or table ("recommended as #2"),
- whether the answer **cites your website**, and at which position,
- which **competitors** appear, where, and which of their sites are cited,
- every **cited domain** and the searches the AI ran,
- what **changed since your last run**: gained, lost, moved up or down, new and lost cited domains.

A summary row adds **mention rate, citation rate, average rank, share of voice and top cited domains** per engine, with deltas to the previous run. Schedule it weekly and you have a GEO / AEO visibility report without a SaaS subscription.

### Bring your own keys, pay the providers at cost

The Actor uses **your own OpenAI, Perplexity and Anthropic API keys**, any one of them is enough. The providers bill you directly at their published prices; the Actor charges only a small fee per check (see the Pricing tab). Typical provider cost of one check in October 2026:

| Engine | What runs | Provider cost per check |
|---|---|---|
| OpenAI | Responses API, `web_search` tool, `gpt-6-luna` | about $0.011 ($0.01 per web search call plus tokens) |
| Perplexity | Agent API, `fast` preset | about $0.002 ($0.001 per search plus tokens) |
| Claude | Messages API, `web_search` tool, `claude-haiku-5-5` | about $0.012-0.035 ($0.01 per search, 1-3 searches, plus tokens) |

Most trackers in the Store bundle the model cost into $0.04-$0.30 per check. With your own keys you pay the provider price plus the Actor fee, and you can see the exact usage on your provider dashboard. Perplexity reports the cost of each answer; it is in `usage.providerCostUsd` of each row.

Keys are **secret inputs**: Apify stores them encrypted, the Actor never logs them, never writes them to the dataset or key-value store, and masks anything that looks like a key in provider error messages. OpenAI requests are sent with `store: false`. For Claude, web search must be allowed for your organization in the Claude Console (it is unless an admin switched it off).

### Quick start

1. Add your brand, e.g. `HubSpot`, and your domain `hubspot.com`.
2. Add competitors, one per line: `Zoho CRM | zoho.com`, `Pipedrive | pipedrive.com`.
3. Add 5-20 prompts your buyers ask: `What is the best CRM for a small business?`.
4. Paste at least one API key and run. Without any key the run returns only free `MISSING_KEY` rows and a status message naming the key to add.

### Input

| Field | What it does |
|---|---|
| `brand` | Brand name as people write it. A capitalised name (HubSpot) matches Hubspot and HUBSPOT but not the plain word; a lowercase name (ahrefs) matches any case. |
| `brandDomains` | Your domains; subdomains count. Used for citations. A domain written in the answer text also counts as a mention. |
| `brandAliases` | Product names, abbreviations, old names. |
| `competitors` | `Name`, `Name | domain.com` or just `domain.com`, up to 25. |
| `prompts` | Up to 200 questions. Each prompt x engine x run is one check. |
| `engines` | Any of `openai`, `perplexity`, `claude`; all three by default. Engines without a key are skipped with a free error row. |
| `openaiApiKey`, `perplexityApiKey`, `anthropicApiKey` | Your keys, secret. |
| `country` | Two-letter code (US, DE, GB...). Every engine searches as if the user were there. |
| `openaiModel` | Default `gpt-6-luna`. Any Responses API model that supports web search, e.g. `gpt-6.1-sol`. |
| `forceWebSearch` | On by default: every OpenAI answer searches the web, and Claude is told to search before it answers. Off: the model decides, like ChatGPT and claude.ai. |
| `perplexityPreset` | `fast` (default, successor of Sonar) or `low` (multi-step search). |
| `claudeModel` | Default `claude-haiku-5-5`, the cheapest. `claude-sonnet-5-5` (about $0.05 per check) or `claude-opus-5-5` (about $0.09) are closer to claude.ai. |
| `claudeMaxSearches` | 1-10, default 3: the most web searches Claude may run for one answer. |
| `runsPerPrompt` | 1-5. Answers vary between requests; 2-3 runs give a steadier rate. |
| `maxChecks` | Safety cap, default 100. Checks above it are not asked and not charged. |
| `trackChanges`, `stateKey` | Compare with the previous run of the same brand and key. |
| `includeAnswer` | Full answer text in each row, on by default. |

### Output

One row per check:

```json
{
  "type": "check",
  "prompt": "What is the best CRM for a small business?",
  "engine": "perplexity",
  "model": "openai/gpt-6-luna",
  "preset": "fast@2026-10-16.0",
  "run": 1,
  "country": null,
  "brand": "HubSpot",
  "brandMentioned": true,
  "brandRank": 2,
  "brandListPosition": 2,
  "brandCited": true,
  "brandCitationPosition": 4,
  "brandInSources": true,
  "brandMentions": 2,
  "brandContext": "2. HubSpot CRM - the easiest start: a free CRM with contacts, deals and email tracking, though paid tiers climb quickly.",
  "change": { "status": "up", "previousCheckedAt": "2026-10-14T08:00:12.000Z", "wasMentioned": true, "previousRank": 3, "rankChange": 1, "wasCited": false, "newCitedDomains": ["hubspot.com"], "lostCitedDomains": [] },
  "mentionedBrands": ["Zoho CRM", "HubSpot", "Pipedrive", "Salesforce"],
  "competitors": [
    { "name": "Zoho CRM", "mentioned": true, "rank": 1, "listPosition": 1, "cited": true },
    { "name": "Pipedrive", "mentioned": true, "rank": 3, "listPosition": 3, "cited": true }
  ],
  "citations": [
    { "position": 1, "url": "https://www.pcmag.com/picks/the-best-crm-software", "domain": "pcmag.com", "title": "The Best CRM Software for 2026 | PCMag", "owner": null },
    { "position": 4, "url": "https://www.hubspot.com/products/crm", "domain": "hubspot.com", "title": "Free CRM Software | HubSpot", "owner": "brand" }
  ],
  "citedDomains": ["pcmag.com", "g2.com", "zoho.com", "hubspot.com", "pipedrive.com"],
  "sourcesCount": 8,
  "searchQueries": ["best CRM for small business"],
  "answer": "The best CRM for a small business depends on ...",
  "answerLength": 640,
  "incomplete": false,
  "usage": { "inputTokens": 3121, "outputTokens": 236, "searchCalls": 1, "providerCostUsd": 0.00156 },
  "checkedAt": "2026-10-21T08:00:03.000Z"
}
```

- `brandRank` - order of first mention among your brand and the competitors you track (1 = mentioned first).
- `brandListPosition` - the number of the list item, heading or table row whose line names your brand; `null` when the answer is not a list.
- `change.status` - `new` (first time), `gained`, `lost`, `up`, `down`, `same` or `absent` (not mentioned either time).
- Error rows (`"type": "error"`) are free: `AUTH_FAILED`, `QUOTA_EXCEEDED`, `RATE_LIMITED`, `PROVIDER_ERROR`, `TIMEOUT`, `NO_ANSWER`, `PARSE_ERROR`, `REFUSED`, `INVALID_REQUEST`, `MISSING_KEY`. An answer the provider has already billed is never requested again. A rejected key or empty balance stops that engine after the first error, so you are not charged for checks that cannot run.
- The summary row (`"type": "summary"`, free) and the `SUMMARY` record of the key-value store hold `overall` and `byEngine` metrics: `brandMentionRate`, `brandCitationRate`, `brandVisibilityRate`, `brandTopRate`, `averageRank`, `shareOfVoice`, `topCitedDomains`, plus `change` against the previous run.

### Tracking over time

With `trackChanges` on, the Actor keeps the last result of every check in your named key-value store `ai-visibility-tracker-state`, one record per tracking key and brand. The summary compares with the last complete run that asked the same prompts on the same engines; a run stopped by the spending limit or a failed engine is not used as the baseline. Create a schedule (Saved tasks - Schedule) that runs the same task weekly: each row shows what moved, and the summary shows how your mention and citation rates changed. Use a different `stateKey` per client or project.

### Good to know

- These are answers of the **official APIs**, not screenshots of the consumer apps. ChatGPT, the Perplexity app and claude.ai use their own prompts and models, so their answers can differ; the APIs give a stable, repeatable signal of what the engines retrieve and recommend.
- AI answers can be wrong, incomplete or out of date. Check facts in an answer before you rely on them; the Actor measures visibility, it does not verify what the AI says.
- AI answers are not deterministic. Use `runsPerPrompt` 2-3 for decisions, and compare rates over several runs rather than single answers.
- Mention matching is by name, alias and domain on word boundaries. It does not judge sentiment: read `brandContext` to see how you are described.
- Citations are shown as links to the original sources; when you publish results, keep the citations visible, as OpenAI and Anthropic ask for answers based on web search.
- Claude splits an answer into cited passages; `citations` keeps their order and `searchQueries` lists the searches it ran. The text Claude writes before or between its searches ("I'll look that up") is not part of the analysed answer.
- Gemini is not supported: the Gemini API terms do not allow monitoring or analysing grounded search results.

### Pricing

Pay per event: one `check` = one answer of one engine to one prompt, analysed and stored. Error rows, skipped checks and the summary are free. The run stops before any check that your run spending limit cannot pay for, so no provider call is made that the Actor cannot finish. See the Pricing tab for the per-check price on your plan.

### Support

Open an issue on the Issues tab with the run ID. Never paste your API keys into an issue.

# Actor input Schema

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

The brand name exactly as people write it, e.g. HubSpot. A name with a capital letter matches HubSpot, Hubspot and HUBSPOT but not the plain word, so Notion skips "a notion of". A lowercase name matches any case.

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

Domains you own, e.g. hubspot.com. Subdomains count too. Used to tell when an AI answer cites your site as a source, the strongest visibility signal.

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

Other names the AI may use for your brand: product names, abbreviations, a former name. Each one counts as a mention of your brand.

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

One competitor per line as Name | domain, e.g. Zoho CRM | zoho.com, or just a name or a domain. Up to 25. Each row shows whether and where every competitor appears, and the summary gives share of voice.

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

One question per line, the way your buyers ask AI assistants: best CRM for a small business, HubSpot alternatives, which CRM integrates with Gmail. Up to 200. Each prompt is asked on every selected engine.

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

Engines to ask. OpenAI = the official Responses API with web search, Perplexity = the official Agent API, Claude = the official Anthropic Messages API with web search. Each prompt on each engine is one check. Engines without an API key below are skipped.

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

Your own key from platform.openai.com. Stored encrypted by Apify, never logged or written to the output. OpenAI bills you directly for the tokens and web search calls of each check.

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

Your own key from console.perplexity.ai. Stored encrypted by Apify, never logged or written to the output. Perplexity bills you directly for each answer.

## `anthropicApiKey` (type: `string`):

Your own key from platform.claude.com (starts with sk-ant-). Stored encrypted by Apify, never logged or written to the output. Anthropic bills you directly for the tokens and web searches of each check. Web search must be allowed for your organization in the Claude Console.

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

Optional two-letter country code such as US, GB or DE. Every engine searches as if the user were there. Write your prompts in that country's language.

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

Model used with web search. The default gpt-6-luna is the cheapest; the web search call itself costs the same on every model. Use a larger model such as gpt-6.1-sol to get closer to ChatGPT answers.

## `forceWebSearch` (type: `boolean`):

On (default): every OpenAI answer is grounded in a fresh web search, and Claude is told to search before answering, so citations are almost always there. Off: the model decides, like ChatGPT and claude.ai do; answers from memory have no citations and cost less.

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

fast (default) is the successor of the Sonar model: one search, cheapest. low runs a few search steps like Pro Search and costs more.

## `claudeModel` (type: `string`):

Model used with web search. The default claude-haiku-5-5 is the cheapest; a web search costs the same on every model. Use claude-sonnet-5-5 or claude-opus-5-5 to get closer to claude.ai answers, at 20-40 times the token price.

## `claudeMaxSearches` (type: `integer`):

Upper limit on web searches Claude may run for one answer; each search is billed by Anthropic ($0.01 each in October 2026). Comparison prompts use more searches when allowed.

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

AI answers vary between requests. Ask each prompt 2-3 times for a steadier mention rate. Every run is a separate check.

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

Safety cap on prompts x runs x engines. Checks above the cap are not asked and not charged.

## `trackChanges` (type: `boolean`):

Keeps the last result of every check in your named key-value store ai-visibility-tracker-state, so each row and the summary show what changed: gained, lost, moved up or down, new and lost cited domains.

## `stateKey` (type: `string`):

Separates tracking histories, e.g. one per client or project. Runs with the same brand and key compare with each other.

## `includeAnswer` (type: `boolean`):

Adds the complete AI answer as Markdown to each row. Switch off for smaller datasets.

## `includeSummaryRow` (type: `boolean`):

Adds one free row at the end with mention rate, citation rate, average rank, share of voice and top cited domains per engine. The same summary is always in the key-value store as SUMMARY.

## `concurrency` (type: `integer`):

How many checks run at the same time. Lower it if your API key has tight rate limits.

## Actor input object example

```json
{
  "brand": "HubSpot",
  "brandDomains": [
    "hubspot.com"
  ],
  "competitors": [
    "Zoho CRM | zoho.com",
    "Pipedrive | pipedrive.com",
    "Salesforce | salesforce.com"
  ],
  "prompts": [
    "What is the best CRM for a small business?",
    "Which CRM is easiest for a startup sales team?"
  ],
  "engines": [
    "openai",
    "perplexity",
    "claude"
  ],
  "openaiModel": "gpt-6-luna",
  "forceWebSearch": true,
  "perplexityPreset": "fast",
  "claudeModel": "claude-haiku-5-5",
  "claudeMaxSearches": 3,
  "runsPerPrompt": 1,
  "maxChecks": 100,
  "trackChanges": true,
  "stateKey": "default",
  "includeAnswer": true,
  "includeSummaryRow": true,
  "concurrency": 4
}
```

# Actor output Schema

## `checks` (type: `string`):

One row per AI answer: brand mentioned, rank, list position, citation, competitors, cited domains and the change since the previous run.

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

Mention rate, citation rate, average rank, share of voice and top cited domains per engine, with deltas to the previous run.

# 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",
    "brandDomains": [
        "hubspot.com"
    ],
    "competitors": [
        "Zoho CRM | zoho.com",
        "Pipedrive | pipedrive.com",
        "Salesforce | salesforce.com"
    ],
    "prompts": [
        "What is the best CRM for a small business?",
        "Which CRM is easiest for a startup sales team?"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maksym_kotenko/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",
    "brandDomains": ["hubspot.com"],
    "competitors": [
        "Zoho CRM | zoho.com",
        "Pipedrive | pipedrive.com",
        "Salesforce | salesforce.com",
    ],
    "prompts": [
        "What is the best CRM for a small business?",
        "Which CRM is easiest for a startup sales team?",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("maksym_kotenko/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",
  "brandDomains": [
    "hubspot.com"
  ],
  "competitors": [
    "Zoho CRM | zoho.com",
    "Pipedrive | pipedrive.com",
    "Salesforce | salesforce.com"
  ],
  "prompts": [
    "What is the best CRM for a small business?",
    "Which CRM is easiest for a startup sales team?"
  ]
}' |
apify call maksym_kotenko/ai-visibility-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maksym_kotenko/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/92Bod6HXWd3icGvEj/builds/eAZfcZfKaARCaS5fy/openapi.json
