# Website SEO Audit Crawler: Broken Links, Redirects, hreflang (`northpine-studio/seo-audit`) Actor

SEO audit tool and website crawler for your own site: one row per page with status, redirect chain, title/meta/H1, canonical, hreflang, Open Graph, images without alt and broken links, plus a site summary. Try it with maxPages=10. Obeys robots.txt.

- **URL**: https://apify.com/northpine-studio/seo-audit.md
- **Developed by:** [Northpine Studio](https://apify.com/northpine-studio) (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

$2.00 / 1,000 audited pages

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

## Technical SEO Audit: links, redirects, canonicals, hreflang

Need a quick site audit for broken links, hreflang and meta tags? Give it URLs, get one audit row per page.

Crawl **your own site** (the start URLs you supply) and get one row per page plus a site summary. Obeys robots.txt, honours
Crawl-delay, rate-limits (default 500 ms per host), stays on the start URLs' host, and identifies itself as `NorthpineSEOAudit/1.0`.
Audit only sites you own or have permission to crawl.

**Pay per result: about $8 per 1,000 audited pages ($0.008/page).** Apify free credit covers small sites. No logins, no API keys.

### What it checks

Per page: HTTP status, redirect chain, title and meta description (presence and length), H1 count, canonical (missing or pointing
elsewhere), robots meta and X-Robots-Tag noindex, hreflang validity / self-reference / x-default, Open Graph and Twitter card,
`lang`, viewport, images without alt, word count, internal/external link counts, an issue list with severity and a 0-100 score.

Site summary (key-value store, key `SUMMARY`): pages audited, average score, errors/warnings, redirect chains, duplicate titles and
descriptions, broken internal and external links (with the pages that link to them), robots.txt, sitemap URLs and `llms.txt` presence.
External links are checked with one HEAD request each and skipped if the other site's robots.txt disallows it. 401/403/429 results
are reported as `blocked-or-restricted`, not broken.

### Example input

```json
{"startUrls":["https://example.com/"],"maxPages":50,"maxDepth":3,"checkExternalLinks":true,"delayMs":500}
```

### Limits (honest)

Static HTML only: pages that need JavaScript to render their content or links are analysed as served. Not a Core Web Vitals or
backlink tool. Scores are a rule-of-thumb summary, not a ranking guarantee. Not affiliated with any search engine.

Feedback and feature requests are welcome in the Actor's Issues tab. Built by Northpine Studio.

### Dev

`npm install && npm test`; `node test/run-local.cjs <url> [maxPages]` for a local report; `npx apify-cli push` to deploy.

### Caveat: project sites (e.g. user.github.io/project/)

robots.txt, sitemap and llms.txt are checked at the domain root, as crawlers do. A site served from a sub-path cannot publish files there, so "robots.txt not found" is expected and not a defect for those sites.

### Example result

Real run on a small static site (8 pages, after fixing short titles/descriptions): average score 95, 0 errors, 1 warning, no broken links or duplicate titles/descriptions.

### Billing and result rules

One row per distinct audited HTML page. Duplicate start URLs, redirect aliases of an already-audited page, non-HTML files and unreachable or error pages (404, 5xx, DNS failures) are **not** rows: they are listed in `SUMMARY` (`unreachablePages`, `duplicateRedirects`, `skippedNonHtml`, `robotsBlockedUrls`, `invalidStartUrls`). 429/5xx/network errors are retried with backoff. If the start URL redirects to another host (apex to www), that host is crawled too. Speed: expect roughly 1-8 s per page on cloud runs (politeness delay plus fetch time); for 1,000+ pages set a run timeout of several hours.

# Actor input Schema

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

Pages to start from. Only pages on the same host as a start URL are crawled. Audit sites you own or have permission to crawl.

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

Maximum number of pages to audit (one result row each).

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

How many clicks from a start URL to follow.

## `checkExternalLinks` (type: `boolean`):

Check outbound links with one HEAD request each (skipped when the other site's robots.txt disallows it).

## `maxExternalLinks` (type: `integer`):

Cap on outbound links checked per run.

## `delayMs` (type: `integer`):

Per-host politeness delay. Crawl-delay in robots.txt is honoured if larger.

## Actor input object example

```json
{
  "startUrls": [
    "https://example.com/"
  ],
  "maxPages": 50,
  "maxDepth": 3,
  "checkExternalLinks": true,
  "maxExternalLinks": 100,
  "delayMs": 500
}
```

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

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

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

```

## MCP server setup

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