# SEO Audit Tool - Technical On-Page SEO Checker & Score (`tenfoldfleet/seo-audit-tool`) Actor

Check the SEO of a website or page: technical and on-page audit of titles, meta descriptions, canonicals, robots, hreflang, headings, alt text, structured data, broken links, robots.txt and sitemap, with a 0-100 score and issue list per page. Site crawl. $20 per 1,000 pages; failed pages are free.

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

## Pricing

from $20.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

### What does SEO Audit Tool do?

**SEO Audit Tool** runs a **technical and on-page SEO audit** of any website and returns **one row per page** with a **0-100 SEO score**, a prioritized **issue list (error / warning / notice)** and every on-page signal search engines read: **title and meta description length, canonical URL, robots meta and X-Robots-Tag, hreflang, H1-H3 headings, word count, image alt text, internal and external links, broken links, mixed content, Open Graph and Twitter Card tags, JSON-LD structured data, robots.txt and XML sitemap**.

Audit a list of URLs, or switch on **crawl mode** to audit a whole site: it starts from your URL and follows internal links and the **sitemap.xml**, breadth-first, up to the page limit you set. Plain HTTP requests, no browser, so it's fast: about 100 pages per minute. Use it as an **SEO audit API**, a bulk **website SEO checker**, or a lightweight **Screaming Frog alternative** in the cloud.

### Why use an SEO audit tool?

- 🔎 **Technical SEO audits** for clients: get structured, sortable findings instead of a PDF, then export to Google Sheets or Excel.
- 🏷️ **Find missing or duplicate titles and meta descriptions** across a whole site (see the `SUMMARY` record).
- 🔗 **Find broken links** (404, 410, 5xx, dead domains, bad SSL) on every page.
- 🚦 **Check indexability**: noindex tags, X-Robots-Tag headers, robots.txt blocks and canonicals pointing elsewhere.
- 🛠️ **Monitor SEO in CI or on a schedule**: run after each deploy and alert when the score drops.
- 🤖 **Feed AI agents and SEO dashboards** with a factual, scored snapshot of any page via API or MCP.

Runs on the Apify platform, so you get an **API**, scheduling, webhooks and integrations with Make, Zapier, n8n, Google Sheets and Slack.

### What data can it extract?

| Field | What you get |
|---|---|
| `score`, `issues[]`, `errorCount`, `warningCount`, `noticeCount` | 0-100 SEO score and issues with code, severity and a plain-English message |
| `statusCode`, `redirectChain[]`, `responseTimeMs`, `pageSizeBytes` | HTTP status, every redirect hop with its status, server response time, HTML size |
| `isHttps`, `mixedContent[]` | HTTPS check and HTTP resources loaded on HTTPS pages |
| `title`, `titleLength`, `metaDescription`, `metaDescriptionLength` | Title and description with character counts |
| `canonicalUrl`, `canonicalIsSelf`, `metaRobots`, `xRobotsTag`, `isIndexable`, `blockedByRobotsTxt` | Indexability signals |
| `hreflang[]`, `lang`, `viewport`, `charset` | International and mobile signals |
| `h1`, `h2`, `h3` (+ counts), `wordCount` | Heading texts and visible word count |
| `imagesCount`, `imagesMissingAlt`, `imagesMissingAltSample[]` | Image alt-text coverage |
| `internalLinks`, `externalLinks`, `nofollowLinks`, `brokenLinks[]` | Link counts and broken links (optional check) |
| `openGraph`, `twitterCard` | All `og:` and `twitter:` tags |
| `schemaTypes[]` | Structured data types from JSON-LD and microdata (Organization, Product, Article...) |
| `robotsTxt`, `sitemaps[]` | Site-level robots.txt and XML sitemap presence |

### How to run an SEO audit of a website

1. Click **Try for free**.
2. Paste one or more URLs into **URLs to audit**.
3. To audit a whole site, switch on **Crawl each site** and set **Max pages per site**.
4. Optionally switch on **Check for broken links**.
5. Click **Start**, then sort the table by **Score** to see the weakest pages first. Download as **JSON, CSV, Excel or HTML**, or fetch results through the API.

### How much does it cost?

You pay **$0.02 per page successfully audited ($20 per 1,000 pages)**, Apify platform usage included. Pages that fail are **free**: unreachable sites, timeouts, HTTP 4xx/5xx responses and bot-protection pages are returned as error rows and never charged. Set a **maximum cost per run** in the run options and the audit stops when it is reached. Apify's free plan includes monthly credit, enough to audit hundreds of pages at no cost.

### How is the SEO score calculated?

Every page starts at **100**. Each issue found subtracts a fixed number of points (minimum score 0):

| Issue code | Severity | Points |
|---|---|---|
| `title-missing` | error | -15 |
| `not-https` | error | -15 |
| `noindex` | error | -15 |
| `blocked-by-robots-txt` | error | -15 |
| `mixed-content` | error | -10 |
| `viewport-missing` | error | -10 |
| `broken-links` | error | -10 |
| `meta-description-missing` | warning | -8 |
| `h1-missing` | warning | -8 |
| `redirect-chain` (2+ redirects) | warning | -5 |
| `slow-response` (over 2,000 ms) | warning | -5 |
| `images-missing-alt` | warning | -5 |
| `title-too-long` (over 60 characters) | warning | -4 |
| `page-too-large` (HTML over 1 MB) | warning | -4 |
| `structured-data-invalid` (JSON-LD that doesn't parse) | warning | -4 |
| `canonical-missing` | notice | -3 |
| `lang-missing` | notice | -3 |
| `thin-content` (under 200 words) | notice | -3 |
| `title-too-short` (under 30 characters) | notice | -2 |
| `meta-description-too-long` (over 160 characters) | notice | -2 |
| `meta-description-too-short` (under 70 characters) | notice | -2 |
| `multiple-h1` | notice | -2 |
| `canonical-points-elsewhere` | notice | -2 |
| `open-graph-missing` (no og:title or og:image) | notice | -2 |
| `structured-data-missing` | notice | -2 |
| `robots-txt-missing` | notice | -2 |
| `sitemap-missing` | notice | -2 |

`noindex` counts robots meta tags (`robots`, `googlebot`) and `X-Robots-Tag` headers that apply to Google. `broken-links` is only checked when **Check for broken links** is on.

### Input

```json
{
    "urls": ["https://www.example.com"],
    "crawl": true,
    "maxPagesPerSite": 50,
    "checkBrokenLinks": true,
    "maxLinksToCheck": 50
}
```

With `crawl` off (default), only the listed URLs are audited, which is ideal for checking a set of landing pages.

### Output

One row per page. Example (shortened):

```json
{
    "url": "http://bbc.co.uk/",
    "finalUrl": "https://www.bbc.co.uk/",
    "statusCode": 200,
    "score": 93,
    "errorCount": 0,
    "warningCount": 1,
    "noticeCount": 1,
    "issues": [
        { "code": "redirect-chain", "severity": "warning", "message": "URL goes through 2 redirects before the final page." },
        { "code": "title-too-short", "severity": "notice", "message": "Title is 10 characters; aim for 30-60." }
    ],
    "redirectChain": [{ "url": "http://bbc.co.uk/", "statusCode": 301 }, { "url": "https://bbc.co.uk/", "statusCode": 301 }],
    "responseTimeMs": 606,
    "title": "BBC - Home",
    "titleLength": 10,
    "metaDescriptionLength": 144,
    "canonicalUrl": "https://www.bbc.co.uk/",
    "canonicalIsSelf": true,
    "isIndexable": true,
    "hreflang": [{ "lang": "en-gb", "url": "https://www.bbc.co.uk/" }],
    "h1Count": 1,
    "h1": ["BBC Homepage"],
    "wordCount": 1405,
    "imagesCount": 87,
    "imagesMissingAlt": 0,
    "internalLinks": 121,
    "externalLinks": 16,
    "schemaTypes": ["CollectionPage", "NewsMediaOrganization", "ItemList"],
    "robotsTxt": true,
    "sitemaps": ["https://www.bbc.co.uk/sitemap.xml"],
    "error": null
}
```

The run also saves a **`SUMMARY`** record in the key-value store with, per site: pages audited, **average score**, the **most common issues**, and **duplicate titles and meta descriptions** with the URLs that share them.

### Tips

- Bare domains work: `example.com` is fetched as `https://example.com`, with an `http://` fallback.
- Crawl mode skips files (PDF, images, ZIP), pages disallowed by robots.txt, and links that redirect to another domain.
- Broken-link results are cached, so links in the site header and footer are checked only once per run.
- If a site blocks datacenter traffic, enable **Apify Proxy** in the input.

### FAQ

#### Does it render JavaScript?

No. It reads the HTML the server returns, the same first view Google gets before rendering. That keeps it fast and cheap. Pages built entirely in the browser (empty HTML shells) will show low word counts and missing headings, which is itself a useful SEO signal.

#### Does it measure Core Web Vitals?

No. It reports server response time and HTML size. For lab Core Web Vitals use Google PageSpeed Insights.

#### Why is a link I know works reported as broken?

Some servers reject automated requests. To avoid false alarms, only definite failures count as broken: HTTP 404, 410 and 5xx (except 503), dead domains, refused connections and invalid SSL certificates. Bot-blocking responses (400, 401, 403, 429, 999...) and timeouts are not reported. Failed `HEAD` requests are retried with `GET`.

#### Can I audit thousands of pages?

Yes. Add as many URLs as you like, or set **Max pages per site** up to 5,000 in crawl mode. At about 100 pages per minute, 5,000 pages take close to an hour, so raise the run **Timeout** for very large crawls (the `SUMMARY` record is saved as the run goes). Use the run's maximum-cost setting to cap spend.

### Disclaimer

This tool reads publicly available web pages only, the same way a search engine crawler does. Only audit sites you own or have permission to test, and respect each site's terms of service.

### More tools from Tenfold Fleet

| Actor | Price |
|---|---|
| [ATS Jobs Scraper - Greenhouse, Lever, Ashby & 5 More](https://apify.com/tenfoldfleet/ats-jobs-scraper) | $2 per 1,000 (job posting) |
| [Website Contact Scraper - Emails, Phones & Socials](https://apify.com/tenfoldfleet/company-contact-finder) | $8 per 1,000 (website with contacts) |
| [Google Ads Transparency Center Scraper - Competitor Ads by Site](https://apify.com/tenfoldfleet/google-ads-transparency-scraper) | $1 per 1,000 (ad scraped) |
| [Google News Scraper - Articles, Real URLs & Full Text](https://apify.com/tenfoldfleet/google-news-scraper) | $2 per 1,000 (article) |
| [Keyword Search Volume, CPC & Difficulty Checker (Bulk)](https://apify.com/tenfoldfleet/keyword-search-volume) | $5 per 1,000 (keyword with data) |
| [Remote Jobs Aggregator - RemoteOK, WWR, Himalayas & 4 more](https://apify.com/tenfoldfleet/remote-jobs-aggregator) | $1.2 per 1,000 (unique remote job) |
| [Shopify Products Scraper - Prices, Variants & Stock](https://apify.com/tenfoldfleet/shopify-products-scraper) | $0.8 per 1,000 (product) |
| [Shopify App & Theme Detector - Store Analyzer & Contacts](https://apify.com/tenfoldfleet/shopify-store-analyzer) | $8 per 1,000 (shopify store analyzed) |
| [Sitemap URL Extractor - All URLs from sitemap.xml & robots.txt](https://apify.com/tenfoldfleet/sitemap-url-extractor) | $0.4 per 1,000 (url extracted) |
| [Technology Detector - Wappalyzer & BuiltWith Alternative](https://apify.com/tenfoldfleet/tech-stack-detector) | $10 per 1,000 (website analyzed) |
| [URL to Markdown - Web Page to LLM-Ready Text for AI Agents](https://apify.com/tenfoldfleet/url-to-markdown) | $1 per 1,000 (page converted) |
| [Workday Jobs Scraper - myworkdayjobs.com API with Salary](https://apify.com/tenfoldfleet/workday-jobs-scraper) | $1.5 per 1,000 (job posting) |
| [YouTube Comments Scraper - Replies, Likes & Sort by Newest](https://apify.com/tenfoldfleet/youtube-comments-scraper) | $0.6 per 1,000 (comment scraped) |
| [YouTube Transcript Scraper - Captions & Subtitles API](https://apify.com/tenfoldfleet/youtube-transcript-scraper) | $3 per 1,000 (transcript extracted) |

# Actor input Schema

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

Pages to audit, one per line. Full URLs (https://example.com/pricing) or bare domains (example.com). With 'Crawl each site' on, each URL is the start page of a site crawl.

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

Off: audit only the URLs you list. On: start from each URL and audit pages of the same site found through links and the XML sitemap (breadth-first), up to 'Max pages per site'. Pages disallowed by robots.txt are skipped.

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

Crawl mode only: the maximum number of pages audited per start URL. You are charged only for pages successfully audited.

## `checkBrokenLinks` (type: `boolean`):

Request every link on each page (up to 'Max links to check per page') and report broken ones: HTTP 404, 410, 5xx, dead domains and invalid SSL certificates. Slower; results are cached across pages.

## `maxLinksToCheck` (type: `integer`):

Broken-link check only: how many links per page to test. Internal links are checked first, then external ones.

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

How many pages to fetch in parallel. Lower it for small or slow sites.

## `proxyConfiguration` (type: `object`):

Optional. Most sites work without a proxy. Use Apify Proxy if sites block you.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://www.python.org",
    "https://developer.mozilla.org/en-US/"
  ],
  "crawl": false,
  "maxPagesPerSite": 20,
  "checkBrokenLinks": false,
  "maxLinksToCheck": 50,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "urls": [
        "https://apify.com",
        "https://www.python.org",
        "https://developer.mozilla.org/en-US/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tenfoldfleet/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 = { "urls": [
        "https://apify.com",
        "https://www.python.org",
        "https://developer.mozilla.org/en-US/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tenfoldfleet/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 '{
  "urls": [
    "https://apify.com",
    "https://www.python.org",
    "https://developer.mozilla.org/en-US/"
  ]
}' |
apify call tenfoldfleet/seo-audit-tool --silent --output-dataset

```

## MCP server setup

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