# SEO Audit Tool – 0-100 Score, Meta Tags and Schema (`martinvarelaa/seo-page-audit`) Actor

Technical SEO audit at $4 per 1,000 pages: 0-100 score, status and redirects, meta tags, canonical, schema, indexability and AI-crawler rules, with a fix for every issue.

- **URL**: https://apify.com/martinvarelaa/seo-page-audit.md
- **Developed by:** [Martin Varela](https://apify.com/martinvarelaa) (community)
- **Categories:** SEO tools, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 page auditeds

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

## SEO Page Audit

Technical SEO audit for any list of pages, or for the URLs in a sitemap, at $4 per 1,000 pages. Each page gets a 0–100 score and a one-line fix for every issue. One row per page, plus one free summary for the run.

### Who it is for

- **SEO consultants and agencies** who audit client sites every month and want a sortable list of what to fix.
- **Developers** who check a release for broken redirects, missing canonicals or pages that became non-indexable.
- **AI agents** that need a structured audit with stable issue codes instead of a PDF.

### What you get

- Status, redirect chain, title, meta description, canonical, headings, schema, images and indexability.
- A stable issue code, a severity and a one-line fix. The score starts at 100 and subtracts 25 / 10 / 5 / 2 for critical / high / medium / low. Two or more critical issues cap the score at 39.
- Sitemap URLs that a homepage crawl never reaches, up to Maximum pages.
- Which of GPTBot, ClaudeBot, PerplexityBot, Google-Extended and CCBot `robots.txt` blocks, and whether `/llms.txt` exists.

### Sample output

A real row from a run on crawlee.dev, trimmed:

```json
{
  "type": "page",
  "url": "https://crawlee.dev/blog",
  "statusCode": 200,
  "score": 85,
  "indexable": true,
  "issueCount": 3,
  "issues": [
    {
      "code": "TITLE_TOO_LONG",
      "severity": "medium",
      "message": "The title is longer than 60 characters.",
      "fix": "Shorten the title to 60 characters or fewer."
    },
    {
      "code": "H1_MISSING",
      "severity": "medium",
      "message": "The page has no H1.",
      "fix": "Add one H1 that states the page topic."
    }
  ]
}
```

The run also writes one `site-summary` row (average score, duplicate titles, top issues). That row is free. A page that never responds is an `error` row and is free too.

### How to use

1. Paste page URLs, or a domain under sitemap domains.
2. Leave Maximum pages at 2 for a preview. Raise it for a full audit. Turn on internal links only if you want them.
3. Run and export JSON or CSV. Sort by `score` to see the worst pages first.

```json
{
  "urls": ["https://apify.com", "https://crawlee.dev"],
  "maxPages": 2
}
```

### Input

| Field | Default | What it does |
|---|---|---|
| `urls` | two example sites | Absolute page URLs. |
| `sitemapDomains` | empty | Hosts whose sitemap URLs are added until `maxPages`. |
| `maxPages` | 100 (prefill 2) | Charged pages. The summary is not counted. |
| `crawlInternalLinks` | false | Follow same-site HTML links after the sitemap. |
| `checkLinks` | false | HEAD up to 50 internal links per page. |
| `respectRobotsTxt` | true | Disallowed URLs are skipped and not charged. |

### Pricing

You pay for audited pages. The summary, network errors and robots skips are free.

| You audit | You pay |
|---|---|
| 1 page | $0.004 |
| 100 pages | $0.40 |
| 1,000 pages | $4.00 |

Plan discounts: Bronze 10% off, Silver 20% off, Gold, Platinum and Diamond 30% off. A 512 MB run is the maximum, so the price stays predictable.

### Use with AI agents (MCP)

The dataset is one JSON object per page with stable `code` values. Call the actor from the Apify MCP server with `urls` and a small `maxPages`.

### Use via API

```bash
curl -X POST "https://api.apify.com/v2/acts/martinvarelaa~seo-page-audit/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://apify.com"],"maxPages":1}'
```

### FAQ

#### Does it render JavaScript?

No. The audit reads the HTML the server sends, and it does not pretend to be Googlebot. Titles and headings are returned; the page body is not, only a word count.

#### How long does a page take?

Each page has 8 seconds and responses are cut at 512 KB. Image checks are HEAD requests, at most 10 unique images per page. 200 pages from 20 sites took 54 seconds in our acceptance run.

#### What am I charged for a page that fails?

Nothing. A page that never responds becomes a free `error` row, and URLs blocked by `robots.txt` are skipped for free.

#### The price list shows a PageSpeed event. Can I use it?

Not yet. The PageSpeed option is switched off on this actor, so that event is never charged.

### Other actors

- [Sitemap URL Extractor](https://apify.com/martinvarelaa/sitemap-url-extractor) lists every URL in a sitemap.xml file.
- [Wayback Machine Scraper](https://apify.com/martinvarelaa/wayback-machine-snapshots) lists Wayback Machine snapshots and archived pages.
- [Clutch.co Scraper](https://apify.com/martinvarelaa/clutch-agency-scraper) builds agency lead lists with rates, team size and published contacts.

### Changelog

- 2026-09-25: a run that asks for PageSpeed now finishes without it instead of failing. The option is hidden until the actor has a PageSpeed key.
- 0.1: on-page audit with a 0–100 score, a fix for every issue, sitemap URLs and an optional internal-link crawl.

# Changelog

This Actor's version history is a separate document: https://apify.com/martinvarelaa/seo-page-audit/changelog.md

# Actor input Schema

## `urls` (type: `array`):

Pages to audit, for example https://example.com/pricing. Absolute http(s) URLs.

## `sitemapDomains` (type: `array`):

Domains such as example.com. Sitemap URLs are added until Maximum pages is reached.

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

Stop after this many audited pages. You pay per page, not per summary.

## `crawlInternalLinks` (type: `boolean`):

After the URLs you listed and their sitemaps, follow same-site HTML links until Maximum pages.

## `checkLinks` (type: `boolean`):

HEAD up to 50 internal links per page and report the ones that return an error.

## `respectRobotsTxt` (type: `boolean`):

Skip URLs disallowed for Googlebot or for every crawler. Skipped URLs are not charged.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://crawlee.dev"
  ],
  "sitemapDomains": [],
  "maxPages": 2,
  "crawlInternalLinks": false,
  "checkLinks": false,
  "respectRobotsTxt": true
}
```

# Actor output Schema

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

One row per audited page, plus one uncharged site summary.

## `runStats` (type: `string`):

Estimated platform cost, revenue and Diamond margin.

# 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 = {
    "urls": [
        "https://apify.com",
        "https://crawlee.dev"
    ],
    "maxPages": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("martinvarelaa/seo-page-audit").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 = {
    "urls": [
        "https://apify.com",
        "https://crawlee.dev",
    ],
    "maxPages": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("martinvarelaa/seo-page-audit").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 '{
  "urls": [
    "https://apify.com",
    "https://crawlee.dev"
  ],
  "maxPages": 2
}' |
apify call martinvarelaa/seo-page-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,martinvarelaa/seo-page-audit"
        }
    }
}
```

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/V58IdWvN96gpatuVk/builds/ghBcoJ17EtpHs0ZWv/openapi.json
