# SEO Audit + GEO AI-Visibility Check Included (`eilitine/seo-geo-site-auditor`) Actor

Full technical SEO audit with the GEO / AI-visibility check included at no extra cost: what Googlebot, GPTBot, ClaudeBot and PerplexityBot actually see, llms.txt, AI bot rules, plus hreflang and multilingual checks. 0-100 score per page and a ranked fix list.

- **URL**: https://apify.com/eilitine/seo-geo-site-auditor.md
- **Developed by:** [mark muzyka](https://apify.com/eilitine) (community)
- **Categories:** SEO tools, AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$25.00 / 1,000 page audited (seo + geo)s

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

## SEO Audit + GEO AI-Visibility Check Included

A full technical SEO audit of any website, **with the GEO / AI-visibility check included at no extra cost**. One price per page covers both.

- **SEO:** a 0-100 score for every page, indexing, meta, headings, content, structured data, links, images and a **prioritized fix list** ranked by impact, reach and effort.
- **GEO (included):** can ChatGPT, Claude, Perplexity and Google AI features actually read your site? The audit fetches your pages as GPTBot, OAI-SearchBot, ClaudeBot, PerplexityBot and Googlebot and compares what each one gets, checks robots.txt rules for 15 AI and search bots (including Google-Extended, used for Gemini), and validates `llms.txt` and `llms-full.txt`.
- **Multilingual (included):** hreflang reciprocity, x-default, `<html lang>` vs URL, and the real language of the text on every locale page. Most SEO audit tools skip this.

**What bots actually see.** The audit reads the raw HTML exactly as crawlers fetch it, without running JavaScript. Most search and AI crawlers index that raw HTML, so if your content only appears after JavaScript runs, this audit shows it as missing, which is exactly what you need to fix.

### Who it is for

- **SEO agencies and freelancers:** a client-ready audit with a fix list you can paste into a proposal or a ticket tracker.
- **Site owners and marketers:** find out why pages do not rank or never show up in AI answers.
- **Developers:** a repeatable technical check before and after a release (schedule it on Apify and compare runs).
- **Multilingual and international sites:** hreflang reciprocity, x-default, wrong-language text on a locale page, thin translations.

### What it checks

| Area | Checks |
|---|---|
| Crawl and indexing | robots.txt (RFC 9309 longest-match), every sitemap and sitemap index, status codes, redirect chains, canonical (present, self, target returns 200), meta robots and `X-Robots-Tag`, noindex pages listed in the sitemap, soft 404, http to https, www, HSTS, compression |
| Content without JavaScript | visible text in the raw HTML (main content vs navigation and footer), text that exists only in `<noscript>`, single H1, heading tree, title and description length and duplicates, Open Graph, viewport |
| Multilingual | languages detected from `<html lang>`, hreflang and URL prefixes; hreflang reciprocity, x-default, self-reference, targets that redirect or 404; `<html lang>` vs URL language; the actual script of the text (catches Russian text on an `/en/` page) |
| Structured data | parses every JSON-LD block (including `@graph`) and checks required properties for Organization, LocalBusiness, Article, BlogPosting, BreadcrumbList, FAQPage, Product, Offer, ItemList and more |
| GEO / AI readiness | robots.txt rules for 15 AI and search bots (GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, PerplexityBot, Google-Extended, CCBot and others); fetches sample pages as Googlebot, GPTBot, OAI-SearchBot, ClaudeBot and PerplexityBot and compares what each one gets (blocks, empty shells, different HTML); `llms.txt` and `llms-full.txt` (exists, links valid) |
| Links and images | samples internal and external links (broken, redirecting), images (status, weight, format, alt text, dimensions) |
| Speed (optional) | Core Web Vitals from the PageSpeed Insights API for one URL per template (bring your own free Google API key) |

Every score is explainable: the weights are listed in the report, and each issue links to example URLs.

### Output

**Dataset (Pages view)**, one row per audited page, worst score first, with the problems spelled out in plain words:

| score | url | lang | top_fix | issues_text |
|---|---|---|---|---|
| 39 | https://kinto.am/en/blog/prepare-before-ordering-website/ | en | Page is noindex (not in sitemap; check it is intended): Remove noindex if it should rank; otherwise avoid heavy internal linking to it | \[low] Page is noindex (not in sitemap; check it is intended) (noindex). Fix: Remove noindex if it should rank...<br>\[medium] Missing canonical. Fix: Add a self-referencing canonical.<br>\[low] No x-default. Fix: Add x-default. |
| 89 | https://kinto.am/primery/salon/ | ru | No hreflang: Add hreflang for all locales | \[medium] No hreflang. Fix: Add hreflang for all locales.<br>\[medium] No JSON-LD. Fix: Add schema for the page type.<br>\[low] Missing og:title / og:image. Fix: Add Open Graph tags. |

- `top_fix` is the single most important thing to fix on the page; `issues_text` has one line per issue: severity, what is wrong (with the detail found), and how to fix it. They follow *Report language* (`ru` gives Russian, `en` and `both` give English).
- Machine-readable fields stay in every row: `issues` (codes such as `NOINDEX`, `CANONICAL_MISSING`, `HREFLANG_NO_XDEFAULT` with details), `checks`, `category_scores`, `status`, `canonical`, `hreflang`, `main_text_chars`, `ttfb_ms` and more. The *Technical details* view shows the main ones.
- The page budget is split evenly across the site's languages, then across page templates inside each language, so even a 20-page run covers every locale and section.

**Site summary** (key-value store record `summary`, JSON): site score, GEO score with its components, category averages (indexability, meta, content, i18n, schema, links, images, performance), averages by template and by language, site-level issues and the ranked fix list:

```json
{
  "type": "site-summary",
  "url": "https://kinto.am",
  "languages": ["ru", "en", "hy"],
  "site_score": 99,
  "geo_score": 100,
  "geo_components": { "llms_txt": 1, "robots_ai_allowed": 1, "bot_parity": 1, "org_schema": 1, "raw_text_share": 1 },
  "category_averages": { "indexability": 94, "meta": 97, "i18n": 95, "schema": 93 },
  "by_lang": { "en": { "pages": 7, "avg": 90 }, "hy": { "pages": 6, "avg": 89 }, "ru": { "pages": 7, "avg": 89 } },
  "fixes": [
    { "id": "CANONICAL_MISSING", "severity": "medium", "pages": 3, "priority": 4.8,
      "en": "Missing canonical", "fix_en": "Add a self-referencing canonical",
      "examples": ["https://kinto.am/en/blog/prepare-before-ordering-website/"] },
    { "id": "NOINDEX", "severity": "low", "pages": 3, "priority": 3.2,
      "en": "Page is noindex (not in sitemap; check it is intended)",
      "fix_en": "Remove noindex if it should rank; otherwise avoid heavy internal linking to it",
      "examples": ["https://kinto.am/en/blog/prepare-before-ordering-website/"] }
  ]
}
```

(Real output from a 20-page run on kinto.am, shortened.) The run page shows live progress (pages fetched, current step) and a final status line with the scores.

**Key-value store:** `summary` (above), `report-md` (readable Markdown report), `pages-csv` and `fixes-csv` (open in Excel or Google Sheets). Set *Report language* to `ru` for a Russian report, or `both` to get `report-md` (Russian) plus `report-en-md` (English).

### How to use

1. Enter the site's home page, for example `https://example.com`.
2. Set *Max pages*. 50 is enough for most sites: the sitemap is sampled by template and language, so a small budget still covers every section.
3. Run. A 50-page audit usually takes 2-5 minutes at the default polite speed (2 requests per second).

Example input:

```json
{
  "startUrl": "https://example.com",
  "maxPages": 50,
  "langs": "auto",
  "reportLang": "en"
}
```

| Field | Default | Notes |
|---|---|---|
| Site URL | | Home page |
| Max pages | 50 | HTML pages to audit |
| Languages | auto | or a list with the default (unprefixed) language first: `en,de,fr` |
| Report language | en | `en`, `ru` or `both` |
| Concurrency / requests per second | 2 / 2 | polite by default |
| Hard request budget | 1500 | the run never sends more requests |
| Include / exclude regex | | limit the crawl to a section |
| PageSpeed templates + key | 0 | optional, needs your own PageSpeed Insights API key |

### Pricing

Pay per event, no subscription: **$0.025 per audited page** (one row in the dataset).

Included at no extra cost: site-level SEO checks (robots.txt, sitemaps, https, compression, soft 404), the GEO / AI-visibility check, hreflang and language checks, link and image sampling, the fix list and the Markdown and CSV reports. Platform usage is included too.

Examples: 10 pages = $0.25, 50 pages = $1.25, 200 pages = $5.00.

If you set a **maximum charge per run**, the actor lowers the number of pages to fit it before crawling. If the site cannot be reached (no page returns HTTP 200), nothing is charged. Charges are made only after the results are saved.

### FAQ

**Does it render JavaScript?**
No, on purpose: it shows what bots actually see. It measures the raw HTML that most search and AI crawlers index. If your content appears only after JavaScript runs, the audit shows it as missing text, which is exactly the problem to fix.

**What is a GEO score?**
GEO (generative engine optimization) is how ready a site is to be read and cited by AI assistants. The score combines: AI bots allowed in robots.txt, the same HTML served to AI bots as to browsers, an `llms.txt` file with working links, Organization schema, and the share of pages with real text in the raw HTML. It measures technical readiness; it does not track whether AI assistants actually mention your brand.

**Will it overload my site?**
No. Default speed is 2 requests per second with 2 parallel connections, it respects robots.txt and stops at the hard request budget.

**Can I audit a site I do not own?**
Yes, it only reads public pages, like a search engine bot. Please keep the default polite speed.

**Does it check backlinks, keyword rankings or traffic?**
No. It is an on-site technical and content audit. Use it together with Search Console or a backlink tool.

**Can I run it on a schedule?**
Yes. Create a task with your input and add an Apify schedule, for example weekly, then compare `site_score` and the fix list between runs.

### Limits

- No JavaScript rendering (see above).
- Pages behind login, or blocked for bots by a firewall, are reported with their status code and are not analyzed.
- Link and image checks use a sample to keep runs fast and cheap.

### Support

Found a false positive or need a check that is missing? Open an issue on the actor's Issues tab. Built by the team behind wse.am, a multilingual real estate site in Yerevan, Armenia, where this auditor is used in production.

# Actor input Schema

## `startUrl` (type: `string`):

Home page of the site, e.g. https://example.com

## `maxPages` (type: `integer`):

How many HTML pages to crawl. The sitemap is sampled by template and language so a small budget still covers every section.

## `langs` (type: `string`):

auto, or comma list with the default (unprefixed) language first: ru,hy,en,zh

## `reportLang` (type: `string`):

Language of the human-readable report.

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

Parallel requests. Keep low to be polite.

## `rps` (type: `number`):

Global requests per second across all threads.

## `maxRequests` (type: `integer`):

Hard request budget; the run never exceeds it.

## `userAgent` (type: `string`):

Custom User-Agent (optional).

## `include` (type: `string`):

Only crawl URLs matching this regex (optional).

## `exclude` (type: `string`):

Skip URLs matching this regex (optional).

## `pagespeedTemplates` (type: `integer`):

Run PageSpeed Insights (mobile) for this many template URLs. 0 = off.

## `psiKey` (type: `string`):

Google PageSpeed Insights API key (needed if PageSpeed templates > 0).

## Actor input object example

```json
{
  "startUrl": "https://kinto.am",
  "maxPages": 20,
  "langs": "auto",
  "reportLang": "en",
  "maxConcurrency": 2,
  "rps": 2,
  "maxRequests": 1500,
  "pagespeedTemplates": 0
}
```

# Actor output Schema

## `pages` (type: `string`):

No description

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

No description

## `report` (type: `string`):

No description

## `fixes` (type: `string`):

No description

## `pagesCsv` (type: `string`):

No description

## `details` (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 = {
    "startUrl": "https://kinto.am",
    "maxPages": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("eilitine/seo-geo-site-auditor").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 = {
    "startUrl": "https://kinto.am",
    "maxPages": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("eilitine/seo-geo-site-auditor").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 '{
  "startUrl": "https://kinto.am",
  "maxPages": 20
}' |
apify call eilitine/seo-geo-site-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eilitine/seo-geo-site-auditor"
        }
    }
}
```

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/LmGXhF3dqzCwTcmtA/builds/5HeBrKeTQRpymAsi6/openapi.json
