# GEO Checker: Brand Visibility in ChatGPT, Gemini & Perplexity (`ruesandora/ai-brand-visibility`) Actor

Two modes. Visibility: does ChatGPT, Claude, Gemini or Perplexity mention your brand, where, with which sources, also for category questions. Fact check: do AI answers state your phone, address, hours, prices and founding year correctly. English and Turkish. Your own API keys.

- **URL**: https://apify.com/ruesandora/ai-brand-visibility.md
- **Developed by:** [Rues Forum](https://apify.com/ruesandora) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

$50.00 / 1,000 question checked on one ai models

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 Brand Visibility + Fact Check: ChatGPT, Claude, Gemini, Perplexity

Do AI assistants mention your brand, and do they get your business facts right? This Actor asks AI models the questions **you** choose, with web search switched on, using **your own API keys**. English and Turkish.

### Two modes

**Visibility** (`mode: visibility`, default). For every question and model you learn whether your brand, your domain and your competitors appear, in which position, with which sources and with what tone. Add a `category` (for example "ceramic mugs" or "seramik kupa") to also ask discovery questions that do not contain your brand name: does AI recommend you unprompted?

**Fact check** (`mode: fact-check`). You enter the true facts (phone, address, opening hours, price range, founding year, main product). The Actor asks the models about them and your facts are compared with the answers. Result per answer: `matches` (the answer states the fact as you gave it), `differs` (it states it differently) or `not-stated` (the answer does not give it). The summary adds `unclear` when answers disagree, and flags a fact when repeated answers state the same wrong value. Your fact values are not written to the results.

### Try it without a key

If you enter no API key, the Actor does not fail. It writes a **preview** row: the questions it would ask and the number of checks (events) a real run would use. No model is called and nothing is charged.

### Input

| Field | Description |
|---|---|
| `mode` | `visibility` or `fact-check` |
| `brand`, `domain` | Your brand name and website domain (required) |
| `language` | `en`, `tr` or `auto` (Turkish when brand, category or questions contain Turkish letters) |
| `competitors`, `questions`, `category` | Visibility: up to 5 competitors, up to 50 questions (empty = 10 template questions), optional category |
| `phone`, `address`, `hours`, `priceMin`, `priceMax`, `currency`, `foundedYear`, `mainProduct`, `repeats`, `includeAnswerExcerpt` | Fact check: the true facts and options |
| `models` | Subset of `openai`, `anthropic`, `gemini`, `perplexity` (empty = every model you entered a key for) |
| `openaiApiKey`, `anthropicApiKey`, `geminiApiKey`, `perplexityApiKey` | Your own keys, stored as secrets, sent only to the matching provider |

```json
{ "mode": "visibility", "brand": "Acme", "domain": "acme.com", "category": "ceramic mugs", "language": "en", "openaiApiKey": "..." }
```

### Output

Visibility rows (one per question and model): `brandMentioned`, `mentionCount`, `domainCited`, `domainMentionedInText`, `position`, `competitors`, `sentiment`, `citedUrls`, `citedDomains`, `answerExcerpt`, `kind` (brand, category or custom). Fact-check rows: `field`, `question`, `model`, `result`, a non-readable `deviationId`. A final `summary` row (also saved as `SUMMARY`): mention rate overall, per model and per question type, competitor share and most cited domains (visibility), or flagged facts per model (fact check).

`sentiment` and fact comparison are simple rule-based checks, not an AI judgement. They can be wrong. The Actor reports what the models answered, not what is true about your business.

### Not included

Google's AI Overviews are not read by this Actor. Gemini with Google Search grounding is the closest option that works with your own key.

### Pricing and your costs

Pay per event: one event per question asked to one model (see the Pricing tab). Failed calls and preview runs are not charged. The AI providers bill you directly for their calls. Hard limit: 300 checks per run. You can also set a maximum cost per run.

### Privacy and safety

API keys are used only in request headers. They never appear in logs, results or errors. Answer text is not stored in fact-check mode unless you turn on `includeAnswerExcerpt`, and e-mail addresses are removed from excerpts.

Full report: https://ruesandora.com

# Actor input Schema

## `mode` (type: `string`):

Visibility: is your brand mentioned in AI answers. Fact check: do AI answers state your business facts correctly.

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

Brand as people write it, e.g. "Acme".

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

Your website domain, e.g. acme.com.

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

Language of the questions asked to the AI and of the tone words. Auto picks Turkish when your brand, category or questions contain Turkish letters.

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

Up to 5 competitor brand names to compare against.

## `questions` (type: `array`):

Questions your customers might ask an AI assistant. Leave empty to use 10 template questions built from your brand and language (no extra model call).

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

Optional. Your product category, e.g. "ceramic mugs" or "seramik kupa". Adds 3 discovery questions that do not contain your brand name, to see whether AI recommends you unprompted.

## `phone` (type: `string`):

Optional. Any common writing style works (with or without country code). Not written to the results.

## `address` (type: `string`):

Optional. Street, number and district. Abbreviations such as Cad. or St. are understood. Not written to the results.

## `hours` (type: `string`):

Optional. A range such as 09:00-18:00.

## `priceMin` (type: `number`):

Optional. Set together with the highest price.

## `priceMax` (type: `number`):

Optional. A small rounding margin is allowed.

## `currency` (type: `string`):

Currency of the price range.

## `foundedYear` (type: `integer`):

Optional.

## `mainProduct` (type: `string`):

Optional. A few words, e.g. "ceramic mugs".

## `repeats` (type: `integer`):

How many times each question is asked per model. More samples make flags more reliable and cost more events.

## `includeAnswerExcerpt` (type: `boolean`):

Off by default. When on, each row holds the first 300 characters of the AI answer (e-mail addresses removed). The excerpt can contain numbers the AI made up.

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

Leave empty to use every model whose key you entered.

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

Optional. Your own key; the provider bills you for the calls.

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

Optional. Your own key.

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

Optional. Your own key (search grounding needs a billing-enabled project).

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

Optional. Your own key.

## Actor input object example

```json
{
  "mode": "visibility",
  "brand": "Acme",
  "domain": "acme.com",
  "language": "en",
  "currency": "TRY",
  "repeats": 1,
  "includeAnswerExcerpt": false
}
```

# Actor output Schema

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

Audit rows pushed to the default dataset. Views: checks, summary.

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

Run summary JSON stored as the SUMMARY record in the default key-value store.

# 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": "Acme",
    "domain": "acme.com"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ruesandora/ai-brand-visibility").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": "Acme",
    "domain": "acme.com",
}

# Run the Actor and wait for it to finish
run = client.actor("ruesandora/ai-brand-visibility").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": "Acme",
  "domain": "acme.com"
}' |
apify call ruesandora/ai-brand-visibility --silent --output-dataset

```

## MCP server setup

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

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/W64ybSa2BB6UZY17w/builds/ugZOmWWSAVQUlMP6R/openapi.json
