# AI Overview Citation Tracker (`zinin/ai-overview-tracker`) Actor

For each query that matters, see which sources and domains AI assistants cite in their answer — grounded via Perplexity Sonar, GPT or Gemini, no API key needed. GEO citation tracking: the backlink profile of the AI-answer era.

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

## Pricing

from $20.00 / 1,000 result founds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## AI Overview Citation Tracker — Who Gets Cited by AI Answers?

When a buyer asks Perplexity or ChatGPT *"best project management software,"* the answer
links to a handful of sources — a review site, a vendor's own docs, maybe a competitor's
blog. Those citations are the new backlinks, and this Actor tells you which domains and
URLs get cited, query by query, model by model — out of the box, no API key and no
monthly seat.

Search is moving into AI answers, and GEO (Generative Engine Optimization) tools like
Ahrefs Brand Radar, Profound and Otterly charge hundreds a month to track this. This Actor
does the core job — per query, pay-as-you-go, no seat.

### What you get

- **Per-query, per-model citation data.** For every `query × model` pair: the domains
  cited, the full source URLs, and a snippet of the model's actual answer.
- **Works out of the box — no API key needed.** LLM access is built in and covered by
  the per-row price. Prefer your own [OpenRouter key](https://openrouter.ai/keys)? Pass
  it and the tokens bill to your account at cost instead, nothing marked up.
- **Three grounded engines.** `perplexity/sonar` (built-in web search), plus
  `openai/gpt-4o-mini:online` and `google/gemini-2.5-flash:online` (OpenRouter's web
  plugin).
- **Any language.** Set `lang` and the grounded model answers natively — this isn't a
  translation layer bolted on afterward.
- Runs on Apify: schedule it, monitor it, call it from the API or the MCP server, export
  to JSON, CSV or Excel, or push results straight into your own pipeline.

### How to run it

1. Click **Try for free** — no card needed on the free plan.
2. Paste your queries into **Queries** and, optionally, extra models into **Models**. No
   API key needed.
3. Press **Start**. Results appear in the dataset — one row per query × model — read them
   in the UI, pull them from the API, or have a webhook push them onward.

### Pricing

Pay-per-event: **$0.005 per run start + $0.02 per query × model row**, and the row price
**includes the LLM call** — grounded web-search queries are not cheap tokens, and
`perplexity/sonar` alone bills around $0.005 per searched answer, which this price
covers for you. Every model you add multiplies the bill, not just every query — **10
queries across 2 models is 20 billed rows, not 10**: 20 × $0.02 + $0.005 start ≈
**$0.41**. 100 rows cost about **$2.01**. Both fields are capped (20 queries, 5 models),
so the most a single run can charge is 100 rows, about **$2.01**, no matter how large
you set them.

Pass your own `openrouterApiKey` and the LLM tokens bill to your OpenRouter account
instead, at cost — the Actor's row price stays the same either way. Rows where the call
failed are still returned, with `found: false` and the reason, and are **not** charged
for.

### Input

| Field | Required | What it does |
|---|---|---|
| `queries` | yes | Prompts a real buyer would ask. Up to 20 per run. Each is run against every model in `models`. |
| `models` | no | OpenRouter model IDs to test — grounded options: `perplexity/sonar`, `openai/gpt-4o-mini:online`, `google/gemini-2.5-flash:online`. Up to 5 per run. Default `["perplexity/sonar"]`. |
| `lang` | no | Answer language, e.g. `en`, `ru`, `tr`. Default `en`. |
| `openrouterApiKey` | no | Optional. Leave empty to use the built-in LLM access (included in the row price). Pass your own [OpenRouter key](https://openrouter.ai/keys) to have tokens billed to your account instead. |
| `maxConcurrency` | no | Parallel LLM calls, 1–10 (default 3), kept low to respect rate limits. |

```json
{
    "queries": ["best project management software", "what is the capital of France"],
    "models": ["perplexity/sonar"]
}
```

### Output

One row per `query × model` pair. This is a real row from a real run — nothing invented:

```json
{
    "query": "best crm for small business",
    "model": "perplexity/sonar",
    "lang": "en",
    "found": true,
    "citedDomains": ["pcmag.com", "zapier.com", "techradar.com", "fitsmallbusiness.com", "fayedigital.com"],
    "citedUrls": ["https://www.pcmag.com/picks/the-best-small-business-crm-software", "https://zapier.com/blog/best-crms-for-small-business/", "https://www.techradar.com/best/best-crm-for-small-business", "https://fitsmallbusiness.com/best-crm-for-small-business/", "https://fayedigital.com/blog/best-crm-for-small-business/"],
    "answerSnippet": "The **best CRM for a small business depends on your priorities**, but the most consistently recommended options in 2026 are **Bigin by Zoho CRM** for overall value and simplicity, and **HubSpot CRM** for teams that want a strong free/startup-friendly option...",
    "promptTokens": 33,
    "completionTokens": 398,
    "summary": "perplexity/sonar on \"best crm for small business\": cites 5 sources: pcmag.com, zapier.com, techradar.com, fitsmallbusiness.com, fayedigital.com.",
    "checkedAt": "2026-07-28T15:50:06.215Z"
}
```

| Field | What it means |
|---|---|
| `query` / `model` / `lang` | Echo of the input for this row |
| `found` | Whether the call succeeded |
| `citedDomains` | The domains the model's answer is grounded in |
| `citedUrls` | The full source URLs behind those domains |
| `answerSnippet` | First 280 characters of the model's answer |
| `promptTokens` / `completionTokens` | Token usage reported by OpenRouter for this call, for reconciling your own bill |
| `summary` | Human-readable one-line summary of the domains cited for this query × model |
| `found: false` | Same shape, `citedDomains`/`citedUrls` empty, `answerSnippet: null`, and an `error` — not billed |

#### Need the rest of the picture?

These run on the same account, take the same shape of input and bill the same way, so they slot into an existing pipeline without new plumbing.

| Actor | What it does |
|---|---|
| [AI Crawler Access Checker](https://apify.com/zinin/ai-crawler-access-checker) | Check which AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Google-Extended & more) can access your website |
| [Domain Health Checker](https://apify.com/zinin/domain-health-checker) | Bulk-audit domains: DNS records, SSL certificate expiry, SPF & DMARC email authentication |
| [LLM Brand Visibility Tracker](https://apify.com/zinin/llm-brand-visibility) | For each query that matters, check whether AI assistants recommend YOUR brand — and which competitors they… |
| [Social Preview Checker](https://apify.com/zinin/social-preview-checker) | See exactly how your links look when shared on Telegram, WhatsApp, X, LinkedIn, Slack, Facebook & Discord |
| [B2B Lead Enricher](https://apify.com/zinin/b2b-lead-enricher) | Turn a list of company websites into sales-qualified lead cards: detected tech stack, a rough revenue… |

### FAQ

**Do I need an API key?** No — it works out of the box, LLM access is built in and
covered by the row price. Passing your own OpenRouter key is optional: do it if you want
the tokens billed to your account at OpenRouter's own price, with your own rate limits.

**Which languages work?** Any — set `lang` (e.g. `ru`, `tr`). Grounded models answer
natively.

**Can an agent call it?** Yes — a standard Apify Actor, callable from the Apify API, the
SDK, or the Apify MCP server.

**What this is NOT.** It does not trust whatever an LLM says without grounding — it is
built for web-searching models; an ungrounded model will simply produce a thinner
`citedUrls` list scraped from its own text.

Found a wrong result, or need a model we don't list? Open an issue on this Actor's page.

***

Built by [zinin](https://apify.com/zinin). Questions? Telegram [@timzinin](https://t.me/timzinin).

# Actor input Schema

## `queries` (type: `array`):

The prompts a real user would ask (e.g. `best project management software`, `how to choose a CRM`). Each query is run against EVERY model in `models` below, and you are charged per query × model pair, not per query — e.g. 10 queries × 2 models = 20 billed rows. With the limits on both fields, the maximum possible is 20 queries × 5 models = 100 rows.

## `models` (type: `array`):

OpenRouter model IDs to test. Grounded options: `perplexity/sonar`, `openai/gpt-4o-mini:online`, `google/gemini-2.0-flash-001:online`. Every model you add here multiplies the number of billed rows: rows = number of queries × number of models (see `queries`).

## `lang` (type: `string`):

Answer language (e.g. en, ru, tr).

## `openrouterApiKey` (type: `string`):

Your OpenRouter API key (https://openrouter.ai/keys). LLM token cost is billed to YOUR account; this Actor only orchestrates and scores. Optional to start the Actor: without it the run finishes cleanly and explains setup, and nothing is charged beyond the Actor start.

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

Parallel LLM calls (kept low to respect rate limits).

## Actor input object example

```json
{
  "queries": [
    "best project management software",
    "what is the capital of France"
  ],
  "models": [
    "perplexity/sonar"
  ],
  "lang": "en",
  "maxConcurrency": 3
}
```

# 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 = {
    "queries": [
        "best project management software",
        "what is the capital of France"
    ],
    "models": [
        "perplexity/sonar"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/ai-overview-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 = {
    "queries": [
        "best project management software",
        "what is the capital of France",
    ],
    "models": ["perplexity/sonar"],
}

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

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

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

```

## CLI example

```bash
echo '{
  "queries": [
    "best project management software",
    "what is the capital of France"
  ],
  "models": [
    "perplexity/sonar"
  ]
}' |
apify call zinin/ai-overview-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=zinin/ai-overview-tracker",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "AI Overview Citation Tracker",
        "description": "For each query that matters, see which sources and domains AI assistants cite in their answer — grounded via Perplexity Sonar, GPT or Gemini, no API key needed. GEO citation tracking: the backlink profile of the AI-answer era.",
        "version": "0.1",
        "x-build-id": "iPAsAP6lH8jpbo70N"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/zinin~ai-overview-tracker/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-zinin-ai-overview-tracker",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/zinin~ai-overview-tracker/runs": {
            "post": {
                "operationId": "runs-sync-zinin-ai-overview-tracker",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/zinin~ai-overview-tracker/run-sync": {
            "post": {
                "operationId": "run-sync-zinin-ai-overview-tracker",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "queries"
                ],
                "properties": {
                    "queries": {
                        "title": "Queries",
                        "maxItems": 20,
                        "type": "array",
                        "description": "The prompts a real user would ask (e.g. `best project management software`, `how to choose a CRM`). Each query is run against EVERY model in `models` below, and you are charged per query × model pair, not per query — e.g. 10 queries × 2 models = 20 billed rows. With the limits on both fields, the maximum possible is 20 queries × 5 models = 100 rows.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "models": {
                        "title": "Models",
                        "maxItems": 5,
                        "type": "array",
                        "description": "OpenRouter model IDs to test. Grounded options: `perplexity/sonar`, `openai/gpt-4o-mini:online`, `google/gemini-2.0-flash-001:online`. Every model you add here multiplies the number of billed rows: rows = number of queries × number of models (see `queries`).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "lang": {
                        "title": "Language",
                        "type": "string",
                        "description": "Answer language (e.g. en, ru, tr).",
                        "default": "en"
                    },
                    "openrouterApiKey": {
                        "title": "OpenRouter API key",
                        "type": "string",
                        "description": "Your OpenRouter API key (https://openrouter.ai/keys). LLM token cost is billed to YOUR account; this Actor only orchestrates and scores. Optional to start the Actor: without it the run finishes cleanly and explains setup, and nothing is charged beyond the Actor start."
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Parallel LLM calls (kept low to respect rate limits).",
                        "default": 3
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
