# Website SEO Audit (Bulk, With Fixes) (`velveteen_driver/seo-audit`) Actor

Audit websites for on-page SEO in bulk: title, meta description, headings, mobile, HTTPS, speed, structured data, images, Open Graph, robots.txt and sitemap. Each page gets a 0-100 score and a plain-English list of fixes. Can crawl whole sites.

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

## Pricing

$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 (Bulk, With Fixes)

Paste in websites or pages and get an **SEO score from 0 to 100** and a **plain-English list of fixes** for each page, sorted high, medium and low priority.

### What it checks

- **Title** and **meta description**: present, and a sensible length
- **Headings**: one H1, H2 structure
- **Indexing**: noindex tags, canonical link, HTTP status, redirects
- **Mobile and HTTPS**: viewport tag and secure connection
- **Speed**: server response time and page weight
- **Content**: word count (thin pages)
- **Images**: missing alt text
- **Structured data**: schema.org types found (Organization, LocalBusiness, Product...)
- **Social previews**: Open Graph title and image
- **Site files**: robots.txt and XML sitemap
- **Links**: internal and external link counts

### Who it's for

- **Agencies**: audit client and prospect sites you have a legitimate reason to review.
- **Site owners**: check every page of your site in one run.
- **SEO teams**: monitor many client sites on a schedule.

### Crawling whole sites

Set **Pages per website** above 1 (up to 200) to crawl a site's own internal links. The page you give is always audited; every further page is only fetched if the site's robots.txt allows it.

- If robots.txt returns a server error or can't be reached, no further pages are crawled (only the page you gave is audited).
- The crawler honours `Crawl-delay` and otherwise waits at least 1 second between pages of the same site, one request at a time per site.
- If a page redirects to a different website, that website's robots.txt is checked before the redirect is followed.

### Output fields

`url`, `site`, `status`, `score` (0 to 100), `issues` (severity and plain-English fix), `issueCount`, `title`, `titleLength`, `metaDescription`, `metaDescriptionLength`, `h1`, `h2Count`, `canonical`, `robotsMeta`, `indexable`, `wordCount`, `images`, `imagesMissingAlt`, `internalLinks`, `externalLinks`, `structuredDataTypes`, `openGraph`, `responseSeconds`, `htmlBytes`, `redirects`, and on the first page of each site `robotsTxt` and `sitemaps`. Pages that fail to load have an `error` field.

Length checks: titles of 15 to 65 characters and meta descriptions of 70 to 165 characters pass.

### Pricing

Each page in the output is one charged event (`page-audited`), including pages that fail to load (they still appear in the dataset with an `error`). Pages skipped because robots.txt disallows them are not output and not charged. The one exception is the start page you gave us: if it redirects to another website that blocks us (robots.txt disallows it, can't be read, or asks for a crawl delay over 30 seconds), that start page appears once with an `error` and counts as one charged event, so you can see why it wasn't audited.

### Data source and licence

The actor only reads public web pages of the websites you supply, plus each site's own `/robots.txt` and `/sitemap.xml`. It doesn't use any third-party data source, log in, solve captchas or use proxies to get around blocks. The audit results are generated by the actor; the page content itself stays the property of each website owner and is not stored beyond the fields above.

### Responsible use

- Only audit sites you own, manage, or have a legitimate reason to check.
- The actor identifies itself honestly with the User-Agent `SEOAuditBot/1.0 (+https://apify.com/velveteen_driver/seo-audit)`, so site owners can recognise and block it in robots.txt (`User-agent: SEOAuditBot`).
- Keep **Websites at the same time** modest; pages of any one site are fetched one at a time with a delay.
- Don't use the results to send unsolicited bulk messages. Follow the laws that apply to you (for example UK GDPR and PECR) and Apify's terms.

# Actor input Schema

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

One per line.

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

1 audits just the page you give. More crawls the site's own links, following robots.txt and its Crawl-delay (at least 1 second between pages of the same site). Up to 200.

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

How many different websites to check in parallel. Pages of the same website are always fetched one at a time.

## Actor input object example

```json
{
  "urls": [
    "apify.com"
  ],
  "maxPagesPerSite": 1,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `results` (type: `string`):

All results in the default dataset, shown in the overview table.

# 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": [
        "apify.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("velveteen_driver/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 = { "urls": ["apify.com"] }

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

```

## MCP server setup

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