# SERP + AI Answer Monitor (`exepal/serp-ai-monitor`) Actor

For each keyword: your Google rank, whether an AI Overview appeared and cited you, and whether ChatGPT, Claude, Gemini or Perplexity name your domain. Diff against your last snapshot. Pay per keyword.

- **URL**: https://apify.com/exepal/serp-ai-monitor.md
- **Developed by:** [Laxman Kafle](https://apify.com/exepal) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $40.00 / 1,000 keyword checkeds

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

## SERP + AI Answer Monitor

**One keyword list, two answers: where you rank on Google, and whether Google's AI Overview, ChatGPT, Claude, Gemini and Perplexity name you.**

Rank trackers tell you position 1–100. They don't tell you that an AI Overview now sits above position 1 citing three competitors, or that Perplexity recommends someone else when a buyer asks the same question. This Actor checks both for every keyword and scores them separately, so an SEO report can show "search visibility" and "AI visibility" side by side — and what changed since last time.

### What you get

For one domain and up to 200 keywords, per keyword:

| Field | What it tells you |
|---|---|
| `rank` | Google organic position of your domain (1–100) or `null` |
| `rankedUrl` | The page that ranks |
| `topUrls[]` | Top 10 organic URLs for the keyword |
| `aiOverview.present` | Google showed an AI Overview for this query |
| `aiOverview.cited` | Your domain is one of the overview's sources |
| `aiEngines[]` | Per engine: named or not, rank among the domains it mentioned, cited as a source, snippet |
| `searchVisibility` | 0–100: rank curve, adjusted for being cited / not cited in an AI Overview |
| `aiVisibility` | 0–100: presence and position across the AI assistants |
| `diff` | vs. your previous snapshot: rank `up` / `down` / `new` / `lost`, citations `gained` / `lost` per engine |

Plus overall `searchVisibility`, `aiVisibility`, a `summary` (top 3, top 10, AI Overviews seen/cited, AI mentions), a `changes` block listing improved / declined / newly cited / lost keywords, and a compact `snapshot` to feed into the next run.

Example (one keyword, trimmed):

```json
{
  "keyword": "best note taking app",
  "rank": 2,
  "rankedUrl": "https://www.notion.so/product",
  "topUrls": ["https://zapier.com/blog/best-note-taking-apps/", "https://www.notion.so/product", "..."],
  "aiOverview": { "present": true, "cited": true, "citedUrls": ["https://zapier.com/...", "https://www.notion.so/help/..."] },
  "aiEngines": [
    { "engine": "openai", "mentioned": true, "rank": 2, "domainsMentioned": ["obsidian.md", "notion.so", "evernote.com"], "cited": false },
    { "engine": "perplexity", "mentioned": true, "rank": 1, "domainsMentioned": ["notion.so", "obsidian.md"], "cited": true }
  ],
  "searchVisibility": 97,
  "aiVisibility": 93,
  "diff": { "previousRank": 5, "rankChange": 3, "rankDirection": "up", "aiOverviewCitation": "gained", "aiEngines": [{ "engine": "openai", "change": "unchanged" }, { "engine": "perplexity", "change": "gained" }] }
}
```

The dataset has one flat row per keyword (ready for Google Sheets / Looker). The full report, summary and snapshot are in the run's key-value store as `REPORT`, `REPORT_SUMMARY` and `SNAPSHOT`.

### Who uses this

- **SEO agencies** adding an "AI answers" column to monthly rank reports without a second tool.
- **SEO platforms and dashboards** that want an AI Overview + assistant feed per keyword via API.
- **In-house SEO / content teams** watching which queries lost clicks to AI Overviews and whether they are cited in them.
- **AI agents** that need a structured "how visible is this site for these queries" answer.

### Pricing

Pay per event. No subscription.

- **$0.04 per keyword checked** (Google rank, top 10, AI Overview status)
- **$0.03 per AI check** (one engine × one keyword)

50 keywords on Google plus ChatGPT and Perplexity: **50 × $0.04 + 100 × $0.03 = $5.00**. Google-only for 100 keywords: $4.00.

Google results are cached for 6 hours and AI answers for 24 hours, so re-running the same list the same day (for example after fixing an input) costs nothing extra upstream.

**Bring your own keys:** the Google lookups use [SerpAPI](https://serpapi.com). Add your own SerpAPI key — and optionally OpenAI / Anthropic / Google AI / Perplexity keys — in the input to run on your quota. Per-event prices stay the same; upstream usage is then on your accounts.

### Input

| Field | Required | Notes |
|---|---|---|
| `domain` | yes | `notion.so` — subdomains count |
| `keywords` | yes | 1–200 queries |
| `brand` | | `Notion` — how assistants name you; defaults to the domain label |
| `country` | | Google `gl`, default `us` |
| `language` | | Google `hl`, default `en` |
| `engines` | | subset of `openai`, `anthropic`, `google`, `perplexity`; empty = all configured |
| `previousSnapshot` | | the `SNAPSHOT` object from a previous run, enables `diff` and `changes` |
| `serpApiKey` | | bring your own SerpAPI key |
| `openaiApiKey`, `anthropicApiKey`, `googleApiKey`, `perplexityApiKey` | | bring your own AI keys |

### Use from code or an AI agent

**Apify API (Node), with week-over-week diff:**

```js
import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const previousSnapshot = await fs.readFile("snapshot.json", "utf8").then(JSON.parse, () => undefined);
const run = await client.actor("exepal/serp-ai-monitor").call({
  domain: "notion.so", brand: "Notion",
  keywords: ["best note taking app", "notion alternatives"],
  country: "us", engines: ["openai", "perplexity"], previousSnapshot,
});
const kv = client.keyValueStore(run.defaultKeyValueStoreId);
const { value: report } = await kv.getRecord("REPORT");
await fs.writeFile("snapshot.json", JSON.stringify(report.snapshot));
console.log(report.searchVisibility, report.aiVisibility, report.changes);
```

**Scheduled monitoring:** create an Apify Schedule for the Actor and pass the last run's `SNAPSHOT` as `previousSnapshot` (an Apify webhook or a 10-line integration task does this). Each run then reports what moved.

**MCP (Claude, ChatGPT, Cursor):** add `exepal/serp-ai-monitor` to the Apify MCP server at `https://mcp.apify.com` and ask: *"Check where notion.so ranks for 'best note taking app' and 'notion alternatives' in the US, and whether ChatGPT and Perplexity mention it."* The agent fills the input and pays per keyword.

**Direct HTTP with USDC (x402):** the same tool is available at `https://api.exepal.com/v1/serp-ai-monitor` for agents that pay per request in stablecoins. See [exepal.com](https://exepal.com).

### How it works

1. For each keyword, fetches the Google results page for your country and language through SerpAPI: organic results, and the `ai_overview` block when Google rendered one (including its source links).
2. Asks each configured AI engine a neutral question — *"Answer the query: \<keyword>. Name specific websites or companies."* — with no hint of your brand, so this measures unprompted recall.
3. Parses every answer for domain names and your brand name, ranks your position among the domains named, and checks the engine's citations (Gemini grounding, Perplexity sources) for your domain.
4. Scores: `searchVisibility` follows a click-curve (position 1 = 100, position 10 ≈ 30, page 2 = 15) and is lifted when an AI Overview cites you, lowered when one appears and doesn't. `aiVisibility` averages presence across engines (first-named = 100, each later position −15).
5. If you passed a previous snapshot, diffs rank and citations per keyword and lists what improved, declined, was newly cited or lost.

### Limits and notes

- Ranks come from a single fetch per keyword; Google personalises and rotates results, so treat ±2 positions as noise and track trends.
- AI Overviews are shown for a subset of queries and vary by country; `present: false` means none was rendered for that fetch.
- Domain detection in AI answers is regex-based plus brand-name matching. Common-word brands (e.g. "Monday") can over-match; set `brand` to the exact form assistants use.
- Keyword lists above 200 are truncated; split into several runs.

### About Exepal

[Exepal](https://exepal.com) builds paid, agent-ready tools: upstream APIs in, computed answers out. Questions or custom runs: contact@laxmankafle.com

# Actor input Schema

## `domain` (type: `string`):

The website to track, e.g. notion.com. Subdomains count as the same site.

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

How AI assistants refer to the site, e.g. Notion. Defaults to the first label of the domain.

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

Search queries to check (1–200). One Google lookup and one query per AI engine each.

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

Google country code (gl), e.g. us, gb, in, de

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

Google interface language (hl), e.g. en, de, hi

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

Which assistants to query for each keyword. Leave empty for all configured; pass an empty list and remove all AI keys for Google-only runs.

## `previousSnapshot` (type: `object`):

The SNAPSHOT object from an earlier run of this Actor. When supplied, every keyword carries a diff: rank up/down/new/lost and AI citations gained/lost.

## `serpApiKey` (type: `string`):

Use your own SerpAPI quota for the Google lookups.

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

Optional. Use your own OpenAI key so upstream usage is billed to your account. Leave empty to use Exepal's managed key.

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

Optional. Use your own Anthropic key so upstream usage is billed to your account. Leave empty to use Exepal's managed key.

## `googleApiKey` (type: `string`):

Optional. Use your own Google AI key so upstream usage is billed to your account. Leave empty to use Exepal's managed key.

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

Optional. Use your own Perplexity key so upstream usage is billed to your account. Leave empty to use Exepal's managed key.

## Actor input object example

```json
{
  "domain": "notion.com",
  "brand": "Notion",
  "keywords": [
    "best note taking app",
    "notion alternatives",
    "project management software for teams"
  ],
  "country": "us",
  "language": "en"
}
```

# Actor output Schema

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

No description

# 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 = {
    "domain": "notion.com",
    "brand": "Notion",
    "keywords": [
        "best note taking app",
        "notion alternatives",
        "project management software for teams"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("exepal/serp-ai-monitor").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 = {
    "domain": "notion.com",
    "brand": "Notion",
    "keywords": [
        "best note taking app",
        "notion alternatives",
        "project management software for teams",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("exepal/serp-ai-monitor").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 '{
  "domain": "notion.com",
  "brand": "Notion",
  "keywords": [
    "best note taking app",
    "notion alternatives",
    "project management software for teams"
  ]
}' |
apify call exepal/serp-ai-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,exepal/serp-ai-monitor"
        }
    }
}
```

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/nGJCl3MpYqcSPVlqT/builds/YVc8REtbbCcZnGwks/openapi.json
