# Website SEO Audit: Broken Links & On-Page SEO Checker (`vncntlabs/website-seo-audit`) Actor

Crawl any website and get an SEO audit: broken links and 404s, missing titles, meta descriptions and H1s, duplicate content, slow pages, redirects, sitemap and SSL checks, with a plain-English fix for every issue. $3 per 1,000 pages. No API key needed.

- **URL**: https://apify.com/vncntlabs/website-seo-audit.md
- **Developed by:** [VNCNT Labs](https://apify.com/vncntlabs) (community)
- **Categories:** SEO tools, Developer tools, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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: Broken Links & On-Page SEO Checker

Crawl a website and get a **full SEO audit at $3 per 1,000 pages**. Every page gets a row with its **status code, title, meta description, H1, word count, canonical, load time, internal links and an on-page score (0-100)**, plus a list of the **issues found on that page and how to fix each one**. Each website also gets **one report row**: issues ranked by severity and number of pages affected, example URLs, **broken links and 404s**, redirects, duplicate titles and content, and **sitemap, robots.txt, SSL and HTTPS redirect checks**.

No Semrush or Ahrefs subscription, no API key and no software to install. The crawl runs on DataForSEO's OnPage crawler, respects robots.txt, and you only pay for pages that were actually audited.

Built for:

- **SEO freelancers and agencies**: quick technical audits for prospects and clients, scheduled re-checks after a site launch or migration.
- **Shopify, WooCommerce and Etsy Pattern store owners**: find broken product links, missing descriptions and thin pages before they cost you traffic.
- **Bloggers, KDP authors and print-on-demand sellers with their own site**: catch 404s, duplicate titles and slow pages on your author or brand site.
- **Developers and AI agents**: one call returns structured, filterable JSON for a whole site.

### What you get

| Row (`type`) | What's in it | Charged |
|---|---|---|
| `page` | `url`, `statusCode`, `resourceType` (html, redirect, broken), `onpageScore`, `title`, `titleLength`, `metaDescription`, `descriptionLength`, `h1`, `h1Count`, `canonical`, `wordCount`, `clickDepth`, `internalLinks`, `externalLinks`, `inboundInternalLinks`, `imagesCount`, `loadTimeMs`, `pageSizeBytes`, `redirectTo`, `errors`, `warnings`, `issues` (plain English), `issueIds` | `page-audited` |
| `site` | `onpageScore`, `pagesCrawled`, `crawlStopReason`, `brokenPages`, `brokenLinks`, `redirects`, `duplicateTitles`, `duplicateDescriptions`, `duplicateContent`, `topIssues`, `issues` (each with `severity`, `pagesAffected`, `exampleUrls`, `howToFix`), `hasSitemap`, `hasRobotsTxt`, `ssl`, `sslExpires`, `httpsRedirect`, `cms`, `server` | free |
| `broken-link` | `linkFrom` (the page with the bad link), `linkTo`, `anchorText`, `targetStatusCode`, `direction`, `dofollow` | free |

Issues checked include: 4xx and 5xx pages, broken links and broken images or scripts, missing or duplicate titles, titles that are too long or too short, missing or duplicate meta descriptions, missing H1, duplicate content, thin pages, slow load and slow server response, large pages, images without alt text, missing canonical, canonicals pointing to redirects or broken pages, redirect chains, meta refresh redirects, plain HTTP pages and HTTPS pages linking to HTTP, orphan pages, render-blocking CSS and scripts, non-friendly URLs, placeholder lorem ipsum text, plus site-wide checks for the XML sitemap, robots.txt, SSL certificate, HTTP to HTTPS redirect and real 404 handling.

### Input examples

Audit up to 100 pages of a site:

```json
{ "websites": ["example.com"], "maxPagesPerSite": 100 }
```

Audit three client sites, sitemap pages only, no broken-link rows:

```json
{ "websites": ["client-one.com", "client-two.com", "client-three.com"], "maxPagesPerSite": 500,
  "crawlSitemapOnly": true, "includeBrokenLinks": false }
```

Check specific pages without crawling (product pages, landing pages):

```json
{ "pageUrls": ["https://example.com/products/blue-mug", "https://example.com/about"] }
```

**Tips**

- A domain starts the crawl at the home page. A full URL like `https://example.com/blog/` starts there instead (same domain only; turn on **Include subdomains** for blog.example.com and the like).
- **Max pages per website** is also your cost cap: 100 pages = $0.30, 1,000 pages = $3.00, plus the $0.005 run start.
- Sites bigger than 100 pages get a quick 100-page pass first and then the full crawl, so small sites finish fast.
- JavaScript is not rendered. Sites that build their pages in the browser (some single-page apps) may show fewer links and less text than visitors see.
- Crawling takes about 2 to 3 seconds per page plus a minute or two of queue time, so 100 pages usually finish in 4 to 6 minutes and 1,000 pages in 40 to 50 minutes. The default run timeout is 2 hours; if a crawl hits the timeout you still get the pages crawled so far.
- Schedule the Actor weekly and compare `onpageScore` and `brokenLinks` over time to catch problems after updates.

### Output examples

```json
{
  "type": "page", "site": "books.toscrape.com",
  "url": "https://books.toscrape.com/catalogue/category/books/classics_6/index.html",
  "resourceType": "html", "statusCode": 200, "onpageScore": 92.4,
  "title": "Classics | Books to Scrape - Sandbox", "titleLength": 42,
  "metaDescription": null, "h1": "Classics", "h1Count": 1, "wordCount": 163, "clickDepth": 1,
  "internalLinks": 71, "loadTimeMs": 616, "errors": 0, "warnings": 4,
  "issues": ["Missing meta description", "Low text-to-HTML ratio", "Very little text on the page",
             "Content nearly identical to another page", "No charset meta tag",
             "Render-blocking CSS or scripts", "URL isn't SEO friendly"]
}
```

```json
{
  "type": "site", "site": "books.toscrape.com", "status": "ok", "onpageScore": 92.09,
  "pagesCrawled": 20, "brokenPages": 0, "brokenLinks": 0, "duplicateTitles": 2, "duplicateContent": 19,
  "topIssues": ["No XML sitemap found", "HTTP doesn't redirect to HTTPS", "Missing meta description"],
  "issues": [
    { "id": "missing_meta_description", "severity": "warning", "issue": "Missing meta description",
      "pagesAffected": 20, "exampleUrls": ["https://books.toscrape.com/"],
      "howToFix": "Write a 120 to 160 character description that matches the page." }
  ],
  "hasSitemap": false, "hasRobotsTxt": false, "ssl": true, "httpsRedirect": false
}
```

The dataset has four views: **Overview**, **Pages**, **Site reports** and **Broken links**. Export to CSV, Excel or JSON, or send results to Google Sheets, Slack or email with Apify integrations.

### Pricing (pay per event)

| Event | Price | When it is charged |
|---|---|---|
| Actor start | $0.005 | once per run |
| `page-audited` | $0.003 | one URL crawled and checked (an HTML page, a redirect or a broken URL), delivered as its own `page` row |

So 100 pages cost $0.305 and 1,000 pages cost $3.005. Site reports and broken-link rows are free.

You are not charged for:

- sites that can't be crawled (down, blocked by robots.txt, or no pages returned) and page URLs that fail to load;
- skipped inputs, and anything beyond your run's maximum charge. The run lowers the page limit to fit your maximum charge and says so in the log.

**Apify free plan:** 1 website x 25 pages and 10 page URLs per run. Any paid Apify plan unlocks 20 websites x 2,000 pages and 500 page URLs per run.

### Use from AI agents (MCP)

AI assistants such as Claude, ChatGPT and Cursor can run this Actor through [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp) (`https://mcp.apify.com`). The agent can look up the Actor, read its input schema, run it and read the results. Runs use your own Apify account and are charged at the prices on this page.

- **Actor name:** `vncntlabs/website-seo-audit`
- **Server URL with only this tool:** `https://mcp.apify.com?tools=vncntlabs/website-seo-audit`. The default `https://mcp.apify.com` also works; the agent can then search Apify Store and call the Actor by name.
- **Claude** (desktop app or claude.ai): Settings > Connectors > Add custom connector, paste the server URL, then sign in to Apify.
- **ChatGPT:** turn on Developer mode, then Settings > Apps & Connectors > Create, paste the server URL and choose OAuth.
- **Cursor:** run `/add-plugin apify` in Cursor chat and connect the Apify MCP server under Cursor Settings > Tools & MCPs, or add the server to `mcp.json`:

```json
{ "mcpServers": { "apify": { "url": "https://mcp.apify.com?tools=vncntlabs/website-seo-audit" } } }
```

Example prompt: *"Use the Apify Actor vncntlabs/website-seo-audit to audit 50 pages of example.com and list the top issues with how to fix them."*

To cap the cost of an agent's run, it can pass `maxTotalChargeUsd` in the run options.

### FAQ

**Who crawls the site?** DataForSEO's OnPage crawler (user agent `RSiteAuditor`), at about one request every two seconds. It follows robots.txt, so pages you block from crawlers are skipped.

**Is the on-page score Google's?** No. It is DataForSEO's 0-100 score based on the checks above. Use it to compare pages and track changes, not as a ranking prediction.

**Why do I see a 404 for /cdn-cgi/l/email-protection?** That's Cloudflare's email obfuscation. Crawlers get a 404 there but visitors don't, so those rows carry a note and are usually safe to ignore.

**Can it audit sites that need a login?** No. It only sees public pages.

**Related tools:** [Backlink Checker](https://apify.com/vncntlabs/backlink-checker) for who links to the site, [Website Traffic Checker](https://apify.com/vncntlabs/domain-seo-data) for traffic and ranked keywords, and [Google Rank Tracker](https://apify.com/vncntlabs/google-rank-tracker) for keyword positions.

Questions or a check you'd like added? Email hello@vncntlabs.com.

# Actor input Schema

## `websites` (type: `array`):

Up to 20 per run. A domain like <code>example.com</code> crawls the whole site from the home page. A full URL like <code>https://example.com/blog/</code> starts the crawl there (same domain).

## `maxPagesPerSite` (type: `integer`):

The crawl stops here. You pay per page audited, so this is also your cost cap per site (100 pages = $0.30).

## `pageUrls` (type: `array`):

Optional. Check up to 500 specific pages (product pages, landing pages, blog posts) without crawling the rest of the site. Each one returns the same page row.

## `includeBrokenLinks` (type: `boolean`):

Add one free row per broken link found (up to 200 per site): the page it's on, where it points and the anchor text.

## `crawlSitemapOnly` (type: `boolean`):

Audit just the URLs listed in the site's XML sitemap instead of following links.

## `maxCrawlDepth` (type: `integer`):

Optional. 1 = home page plus the pages it links to, 2 = one more level, and so on. Empty or 0 = no limit.

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

Also crawl subdomains like blog.example.com or shop.example.com.

## Actor input object example

```json
{
  "websites": [
    "books.toscrape.com"
  ],
  "maxPagesPerSite": 10,
  "pageUrls": [
    "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
  ],
  "includeBrokenLinks": true,
  "crawlSitemapOnly": false,
  "includeSubdomains": false
}
```

# Actor output Schema

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

No description

## `sites` (type: `string`):

No description

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

No description

## `brokenLinks` (type: `string`):

No description

## `all` (type: `string`):

No description

## `summary` (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 = {
    "websites": [
        "books.toscrape.com"
    ],
    "maxPagesPerSite": 10,
    "pageUrls": [
        "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vncntlabs/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 = {
    "websites": ["books.toscrape.com"],
    "maxPagesPerSite": 10,
    "pageUrls": ["https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"],
}

# Run the Actor and wait for it to finish
run = client.actor("vncntlabs/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 '{
  "websites": [
    "books.toscrape.com"
  ],
  "maxPagesPerSite": 10,
  "pageUrls": [
    "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
  ]
}' |
apify call vncntlabs/website-seo-audit --silent --output-dataset

```

## MCP server setup

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