# SEO Audit Crawler & Broken Link Checker – Website Health (`forevertools/website-seo-audit`) Actor

Technical SEO audit crawler & SEO analysis tool (website audit / SEO checker): check every page for 25+ on-page issues — titles, meta tags & descriptions, H1s, canonical tags, noindex, broken links, duplicate content, Open Graph, JSON-LD, image alt text, mixed content, speed.

- **URL**: https://apify.com/forevertools/website-seo-audit.md
- **Developed by:** [Forever Tools](https://apify.com/forevertools) (community)
- **Categories:** SEO tools, Developer tools
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 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.

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

## Website SEO Audit Crawler

Crawl a whole website and get a page-by-page technical SEO audit plus a site-wide summary: **duplicate titles, broken internal links, missing meta descriptions, noindex pages, canonical problems** and 20+ other checks. It uses plain HTTP requests (no browser), respects robots.txt, and is priced per audited page, so small sites cost cents.

### Free-form bulk SEO audit of a whole website

Give the actor your homepage (or any page) and it follows links on the same host, auditing each page it reaches. Every page becomes one dataset row with the raw measurements (title, meta description, H1s, canonical, word count, link counts and so on) and an `issues` array of codes you can filter on. A `SUMMARY` record in the key-value store rolls the whole crawl up into issue counts, duplicates and broken links.

### What it checks on every page

| Area | Checks |
|---|---|
| Indexing | HTTP status, redirects, `meta robots` / `X-Robots-Tag` noindex, canonical missing / pointing elsewhere / invalid |
| Titles & meta | missing, too long (>60), too short (<20); meta description missing / >160 / <50; duplicates across the site |
| Content | H1 missing / multiple, thin content (<200 words), `html lang`, viewport meta |
| Links | internal, external and nofollow counts; broken internal links with the pages that link to them |
| Media | images missing `alt` |
| Social & schema | Open Graph tags, JSON-LD types (and invalid JSON-LD), hreflang alternates |
| Security & speed | mixed content on HTTPS, slow server response, large HTML |

### Find duplicate titles and broken internal links

The `SUMMARY` key-value record lists issue counts sorted by frequency, duplicate titles, duplicate meta descriptions, broken internal links (each with up to 20 referring pages) and average response time. That makes it a quick way to find broken links and duplicate metadata without opening every row.

### Use cases

- **Pre-launch or post-migration check:** confirm redirects, canonicals and noindex tags are what you intended.
- **Agency and freelancer audits:** export one row per page to CSV or Excel and hand over a fix list.
- **Scheduled monitoring:** run weekly with an Apify schedule and compare issue counts over time.
- **AI agents:** flat input and an `issues` array per page suit LLM tools calling the actor through the Apify MCP server.

### Input

```json
{
  "startUrls": [{ "url": "https://example.com" }],
  "maxPages": 200,
  "maxDepth": 10,
  "includeSubdomains": false,
  "maxConcurrency": 10
}
```

- **Start URLs** (required): links on the same host are followed.
- **Max pages** (default 100): hard cap on pages audited, in total. With several sites in one run the budget is split evenly between them (e.g. 5 sites, 100 pages → 20 each), and pages a small site doesn't use are re-dealt to the larger ones.
- **Max link depth** (default 10): clicks away from the start URL.
- **Include subdomains** (default off): also crawl e.g. blog.example.com. `example.com` and `www.example.com` always count as the same site, so a start URL that redirects between them is crawled normally.
- **Max concurrency** (default 10, max 50): lower it for small servers.

### Output

One dataset row per page. Example (abridged to a few real fields):

```json
{
  "url": "https://example.com/pricing",
  "statusCode": 200,
  "responseTimeMs": 184,
  "title": "Pricing | Example",
  "titleLength": 17,
  "metaDescriptionLength": 0,
  "h1": ["Simple pricing"],
  "canonical": "https://example.com/pricing",
  "wordCount": 412,
  "imagesMissingAlt": 3,
  "jsonLdTypes": ["Organization"],
  "depth": 1,
  "issues": ["title-too-short", "missing-meta-description", "images-missing-alt", "missing-open-graph"]
}
```

Other fields available per row: `finalUrl`, `htmlBytes`, `metaDescription`, `metaRobots`, `xRobotsTag`, `lang`, `hasViewport`, `images`, `internalLinks`, `externalLinks`, `nofollowLinks`, `openGraph`, `hreflang`, `mixedContentResources`, `error`. Issue codes include `missing-title`, `title-too-long`, `missing-h1`, `multiple-h1`, `noindex`, `redirected`, `invalid-canonical`, `canonicalized-elsewhere`, `thin-content`, `slow-response`, `mixed-content` and `fetch-failed`.

### Pricing

Pay per event: **$0.005 per audited page** ($5 per 1,000 pages), no subscription.

- 50-page site: about $0.25
- 200-page site: about $1.00
- 2,000-page site: about $10.00

Set **Max pages** (or a max cost per run) to cap spend; the actor stops when the charge limit is reached. Platform usage is billed by Apify according to your plan.

### Limitations

- JavaScript is not executed: the HTML as served is audited, so client-rendered content and links may be missed.
- It reports on-page and technical signals; it does not measure rankings, backlinks or Core Web Vitals.
- Response time is measured from the crawler's location and is a rough indicator only.
- Audit only sites you own or are permitted to crawl.

### FAQ

#### How do I find broken links on my website?

Run the actor from your homepage and open the `SUMMARY` record: broken internal links are listed with the pages that link to them.

#### How do I find duplicate title tags across a site?

The `SUMMARY` record includes duplicate titles and duplicate meta descriptions; each page row also has `title` and `titleLength`.

#### Can I audit a site that uses noindex or canonical tags?

Yes. Pages are still fetched and flagged with `noindex`, `missing-canonical`, `invalid-canonical` or `canonicalized-elsewhere` as appropriate.

#### Does it respect robots.txt?

Yes, the crawler honours robots.txt.

#### How much does a full website SEO audit cost?

$0.005 per page, so roughly $1 for 200 pages.

#### Can I crawl subdomains too?

Yes, switch on **Include subdomains**; by default only the start host is crawled.

Built and maintained with AI assistance. Issues and feature requests: use the Issues tab.

### Related tools

Other actors by the same developer (same flat pay-per-result pricing, no subscription):

- [App Store Reviews Scraper – Apple iOS, Multi-Country](https://apify.com/forevertools/apple-app-store-reviews)
- [Article Scraper & Text Extractor – Clean Markdown for LLM/RAG](https://apify.com/forevertools/article-extractor)
- [Job Postings & Career Page Scraper – Workday, Greenhouse, Lever](https://apify.com/forevertools/ats-company-jobs)
- [Bluesky Posts Scraper – Profiles & Threads, No Login](https://apify.com/forevertools/bluesky-posts)
- [Company Enrichment from Domain (Logo, Socials, Tech)](https://apify.com/forevertools/company-website-enrichment)
- [DNS Lookup & WHOIS Domain Checker — SPF/DMARC, SSL Expiry](https://apify.com/forevertools/domain-whois-dns-ssl)
- [Email Validator & MX Record Checker – Bulk, Disposable, Role](https://apify.com/forevertools/email-syntax-mx-checker)
- [Bulk PageSpeed Insights, Lighthouse & Core Web Vitals](https://apify.com/forevertools/pagespeed-core-web-vitals)
- [PDF Extractor & Parser – Bulk PDF to Text with Metadata](https://apify.com/forevertools/pdf-to-text-extractor)
- [Sitemap Extractor & Bulk URL Status Checker](https://apify.com/forevertools/sitemap-url-status-checker)
- [Steam Reviews Scraper – Game Reviews & App Details](https://apify.com/forevertools/steam-reviews)
- [Website Technology Detector – Tech Stack, CMS & Analytics](https://apify.com/forevertools/website-tech-stack-detector)
- [Website Screenshot API – Bulk Full Page PNG, JPEG & PDF](https://apify.com/forevertools/website-screenshot)

### Integrations

Run it from the Apify API, a schedule, or no-code tools: the Apify apps for **Zapier**, **Make** and **n8n** can start any public actor ("Run Actor") and read its dataset. AI agents can call it through the **Apify MCP server**.

### Ready-made examples

One-click tasks you can run or copy and adapt:

- [Technical SEO audit of a small website (30 pages)](https://apify.com/forevertools/website-seo-audit/examples/technical-seo-audit-small-site)
- [SEO checker for a blog: meta tags, H1 and broken links](https://apify.com/forevertools/website-seo-audit/examples/seo-checker-blog)
- [Find missing meta descriptions & title tags on a website](https://apify.com/forevertools/website-seo-audit/examples/missing-meta-descriptions-titles)
- [SEO audit of a documentation site: canonicals, noindex, H1](https://apify.com/forevertools/website-seo-audit/examples/docs-site-seo-audit)
- [SEO audit of a SaaS marketing site (titles, meta, headings)](https://apify.com/forevertools/website-seo-audit/examples/saas-website-seo-audit)
- [Find images missing alt text across a website](https://apify.com/forevertools/website-seo-audit/examples/image-alt-text-checker)
- [Check Open Graph tags and JSON-LD across a whole website](https://apify.com/forevertools/website-seo-audit/examples/open-graph-tags-checker)

# Actor input Schema

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

Homepage (or any page) of the site(s) to audit. Links on the same host are followed.

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

Stop after auditing this many pages in total. With several sites as start URLs the budget is split evenly between them, and pages a small site does not use go to the larger ones. You are charged per audited page.

## `maxDepth` (type: `integer`):

How many clicks away from the start URL to follow.

## `includeSubdomains` (type: `boolean`):

Also crawl subdomains (e.g. blog.example.com when starting at example.com).

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

Parallel requests. Lower it to be gentle on small servers.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://crawlee.dev"
    }
  ],
  "maxPages": 100,
  "maxDepth": 10,
  "includeSubdomains": false,
  "maxConcurrency": 10
}
```

# 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 = {
    "startUrls": [
        {
            "url": "https://crawlee.dev"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("forevertools/website-seo-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 = { "startUrls": [{ "url": "https://crawlee.dev" }] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,forevertools/website-seo-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/cHxB3MGO3uj2xfvhl/builds/RdpmQNhDmA5YggqKk/openapi.json
