# SEO Audit Tool: Website SEO Checker, Crawler & Score (`best_apis/seo-audit-tool`) Actor

Crawl a website and get a 0-100 SEO score and a prioritised issue list for every page: titles, meta descriptions, headings, canonicals, noindex, broken internal links, duplicates, images alt, structured data, Open Graph, sitemap and orphan pages. $2 per 1,000 pages.

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

## Pricing

Pay per event

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 Tool: website SEO checker with a 0-100 score per page

Crawl any website and get a technical and on-page **SEO audit** of every page: a **0-100 SEO score**, every issue ranked as error, warning or notice, and a concrete **fix hint** for each. Titles, meta descriptions, headings, canonicals, noindex, broken internal links, redirects, duplicate titles and descriptions, image alt text, structured data, Open Graph, mobile viewport, HTTPS and mixed content, XML sitemap coverage and orphan pages. Plus a site-wide report with the overall score and issue totals.

**$2 per 1,000 pages audited.** A 500-page site costs $1. No login, no API keys, no proxies.

### What it checks (45 checks)

| Area | Checks |
|---|---|
| **Status & indexability** | 4xx / 5xx / unreachable pages, redirects (full chain), noindex in meta robots or `X-Robots-Tag`, canonical missing / multiple / pointing elsewhere, `indexable` flag with reason |
| **Titles & descriptions** | Missing, too long (>60 / >160 chars), too short (<30 / <70), multiple titles, **duplicates across the site** (with the other URLs) |
| **Headings & content** | Missing or multiple H1, H1 equal to title, skipped heading levels, word count, thin content (<250 words), text-to-HTML ratio |
| **Links** | **Broken internal links** (with anchor text), links to redirecting URLs, internal / external / nofollow link counts, inlinks and anchors pointing to each page, click depth |
| **Sitemap & crawlability** | robots.txt rules honoured, XML sitemaps (incl. sitemap indexes and .gz), indexable pages missing from the sitemap, sitemap URLs that don't return 200, **orphan pages** |
| **Mobile, security, performance** | Viewport tag, `lang`, charset, HTTPS, mixed content, server response time, HTML size |
| **Rich results & social** | JSON-LD and microdata types (Organization, Product, Article, BreadcrumbList...), invalid JSON-LD, Open Graph, Twitter/X card, favicon, hreflang |
| **URLs** | Length, uppercase, underscores, query parameters |

Every page gets `score`, `errors`, `warnings`, `notices` and an `issues` list like:

```json
{ "code": "title_too_long", "severity": "warning", "message": "Title longer than 60 characters", "fix": "Shorten the title so it is not truncated in search results." }
```

The **SUMMARY** record in the key-value store has the site score, status code totals, indexable pages, average response time and word count, robots.txt and sitemap details, and every issue type with the number of affected pages and example URLs, sorted by priority. Rows in the dataset are sorted worst page first.

### How to use

1. Enter your **website URL** (homepage or any section such as `https://example.com/blog/`).
2. Set **Max pages** (default 50, up to 10,000).
3. Click **Start**. Download the results as JSON, CSV, Excel or HTML, or open the **Issues per page** view.

**Bulk on-page SEO checker**: turn **Crawl the site** off and paste a list of URLs (any domains) to audit exactly those pages.

Example input:

```json
{ "startUrls": ["https://docs.apify.com"], "maxPages": 20 }
```

Use `includePatterns` / `excludePatterns` (`*/blog/*`, `*/tag/*`) to focus the crawl.

### Output example (shortened)

```json
{
  "url": "https://example.com/pricing",
  "score": 72,
  "errors": 1, "warnings": 3, "notices": 2,
  "statusCode": 200, "indexable": true, "redirectChain": [], "responseTimeMs": 212, "htmlSizeKb": 84.2,
  "title": "Pricing", "titleLength": 7,
  "metaDescription": null, "metaDescriptionLength": 0,
  "canonical": "https://example.com/pricing", "metaRobots": null,
  "h1": ["Simple pricing"], "h1Count": 1, "h2Count": 4, "wordCount": 412,
  "lang": "en", "hasViewport": true, "structuredDataTypes": ["Organization", "Product"],
  "openGraph": { "title": "Pricing", "image": "https://example.com/og.png" }, "twitterCard": "summary_large_image",
  "imageCount": 6, "imagesMissingAlt": 2, "internalLinks": 38, "externalLinks": 4,
  "brokenLinks": [{ "url": "https://example.com/old-plans", "statusCode": 404, "anchorText": "compare plans" }],
  "duplicateTitleUrls": [], "inSitemap": true, "depth": 1, "inlinks": 27,
  "issues": [
    { "code": "broken_links", "severity": "error", "message": "Links to internal pages that return errors", "fix": "Fix or remove the links listed in brokenLinks." },
    { "code": "title_too_short", "severity": "warning", "message": "Title shorter than 30 characters", "fix": "Expand the title with the main keyword and a benefit." }
  ]
}
```

### Pricing compared

| Actor | Price per 1,000 pages |
|---|---|
| **This Actor** | **$2** |
| autofacts/metadata-scraper | $5 |
| logiover/website-seo-audit-crawler | $10 |
| smart-digital/complete-seo-audit-tool | $40 |

Prices from the Apify Store, October 2026 (free-plan tier). Plus $0.0005 per run start. Set a maximum cost per run and the Actor audits only as many pages as the limit allows, then stops cleanly.

### Use cases

- **Technical SEO audits** for clients or your own sites, scheduled weekly to catch regressions
- **Pre-launch and migration checks**: redirects, noindex left on, broken links, canonicals
- **Content audits**: thin pages, duplicate titles and descriptions, missing H1s
- **Agency lead generation**: audit prospects' homepages in bulk and pitch with real findings
- **AI agents and dashboards**: structured JSON for Looker Studio, Sheets or an LLM summary

### FAQ

**Is it polite to the website?** Yes. It honours robots.txt, sends at most 4 parallel requests per host, retries 429/503 with backoff and identifies itself with a clear user agent.

**Does it render JavaScript?** No. It audits the HTML your server returns, which is what search engines see first. That makes it fast and cheap (hundreds of pages per minute).

**How is the score calculated?** Each page starts at 100: minus 10 per error, 4 per warning, 1 per notice. Pages that return errors score 0. The site score is the average.

**Does it check external links?** It counts them. To check every internal and external link for 404s, use our [Broken Link Checker](https://apify.com/best_apis/broken-link-checker).

**Core Web Vitals?** This Actor reports server response time and HTML size. For a fast check of what technologies a site runs, see [Website Tech Stack Detector](https://apify.com/best_apis/website-tech-stack-detector).

### API

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

Python: `ApifyClient("TOKEN").actor("best_apis/seo-audit-tool").call(run_input={"startUrls": ["https://example.com"]})`. Works with Zapier, Make, n8n, Google Sheets, webhooks and the Apify MCP server for AI agents.

### Related Actors

- [Broken Link Checker](https://apify.com/best_apis/broken-link-checker): every internal and external link, 404s, redirect chains
- [Website Tech Stack Detector](https://apify.com/best_apis/website-tech-stack-detector): CMS, frameworks, analytics and hosting of any site
- [Wayback Machine Scraper](https://apify.com/best_apis/wayback-machine-scraper): page history and archived URLs of any domain
- [Domain WHOIS Lookup](https://apify.com/best_apis/domain-whois-lookup): registrar, creation and expiry dates

# Actor input Schema

## `startUrls` (type: `array`):

Homepage (or any page) of the site to audit, e.g. https://example.com. With crawling on, internal links are followed from here. With crawling off, exactly these URLs are audited (bulk on-page SEO check). Leave empty for a 10-page demo.

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

Stop after auditing this many pages (cost control). One page = one charged result.

## `crawl` (type: `boolean`):

Follow internal links (and sitemap URLs) from the start URLs. Turn off to audit only the URLs you listed.

## `useSitemap` (type: `boolean`):

Read robots.txt sitemaps (or /sitemap.xml) to flag pages missing from the sitemap, sitemap URLs that don't return 200, and orphan pages with no internal links. Default: on when crawling.

## `includePatterns` (type: `array`):

Optional. Only audit URLs matching one of these patterns (wildcards like */blog/* or regular expressions).

## `excludePatterns` (type: `array`):

Optional. Skip URLs matching any of these patterns, e.g. */tag/* or ?page=.

## `respectRobots` (type: `boolean`):

Skip pages disallowed for crawlers by robots.txt.

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

Global limit; at most 4 requests run in parallel per host, so your server isn't stressed.

## Actor input object example

```json
{
  "startUrls": [
    "https://crawlee.dev"
  ],
  "maxPages": 10,
  "crawl": true,
  "respectRobots": true,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `issues` (type: `string`):

No description

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

No description

## `full` (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 = {
    "startUrls": [
        "https://crawlee.dev"
    ],
    "maxPages": 10
};

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

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

```

## MCP server setup

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

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/f59zzOeVDCdLe5lCk/builds/qz6NLUfRLvDC6YCky/openapi.json
