# Complete SEO Audit Tool - Technical Website Audit (`khadinakbar/complete-seo-audit`) Actor

Audit one public website for crawlability, indexation, metadata, headings, links, images, structured data, hreflang, security, response-time and optional AI-crawler signals. Returns a prioritized, source-linked report. It does not query AI answers or claim rankings.

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

## Pricing

from $100.00 / 1,000 complete seo audits

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Complete SEO Audit Tool - Technical Website Audit

Audit one public website across a bounded sample of same-origin HTML pages and return one validated technical report. It covers crawlability, indexation, metadata, heading structure, canonical integrity, internal-link graph coverage, sampled link health, images, structured data, hreflang, security, response-time signals, and optional AI-crawler signals. The report includes source-to-destination internal links with anchor text and rel directives, inbound/outbound coverage, redirect/broken-link counts, and bounded-sample orphan candidates so a team can prioritize real linking fixes rather than only seeing page-level totals.

### Best fit and connected workflows

### Use when

Use this Actor when the starting point is one public website and the goal is a focused technical audit across a bounded page sample. It fits workflows such as:

- Baseline checks before a launch or migration
- Evidence-linked repair queues for content, SEO, and engineering teams
- Review of robots.txt, sitemap discovery, HTTPS, canonical and noindex signals
- Mapping sampled internal links with source URL, destination, anchor text, rel directives, inbound/outbound coverage, and orphan candidates
- Sampling metadata, headings, image alt text, structured data, and link health
- Comparing a later audit against `previousSnapshot.overallScore`

### Avoid when

Use a dedicated crawler for a whole-domain inventory beyond 50 pages, redirect-chain tracing, JavaScript-rendered field extraction, or authenticated Search Console inspections. This Actor does not claim rankings, index coverage, Core Web Vitals, or a site-wide orphan-page verdict; every internal-link coverage finding is limited to the sampled public HTML graph.

### Practical scenario

Maya, an SEO lead, starts with `https://example.com` and wants a bounded audit before a release. She sends the homepage plus a page limit of 10 and keeps link checks enabled. The returned record shows the site score, category scores, page count, issue counts, and prioritized findings with evidence URLs. Maya uses the issue list to assign metadata updates to content owners and image alt text fixes to design support, then runs the Actor again after deployment and compares the score change.

### Input fields

| Field | Type | Description |
| --- | --- | --- |
| `siteUrl` | string | Public website origin or homepage to audit. Required. Same-origin links and sitemap URLs are followed from this starting point. |
| `maxPages` | integer | Maximum same-origin HTML pages to sample, including the homepage. Defaults to 10, range 1 to 50. |
| `checkLinks` | boolean | Samples discovered links and classifies them as healthy, redirect, unavailable, access-restricted, timeout, or request-issue. |
| `maxLinksPerPage` | integer | Maximum unique links sampled from each analyzed page when link checks are enabled. Defaults to 10, range 1 to 50. |
| `maxInternalLinksPerPage` | integer | Maximum extracted internal-link details retained per analyzed page. Defaults to 25, range 1 to 100. It limits report size, not page discovery. |
| `includeExternalLinks` | boolean | Includes off-domain links in the bounded link-health sample. |
| `checkAiReadiness` | boolean | Checks AI crawler directives, llms.txt, and structured-data availability alongside conventional SEO signals. |
| `respectRobotsTxt` | boolean | Skips discovered same-origin pages disallowed for the default user-agent group. |
| `requestTimeoutMs` | integer | Maximum time allowed for each public HTTP request. Defaults to 15000, range 3000 to 30000. |
| `previousSnapshot` | object | Optional prior report summary used to calculate overall score change. |
| `demoMode` | boolean | Validates the execution contract without fetching a site. |

#### Focused input example

```json
{
  "siteUrl": "https://example.com",
  "maxPages": 10,
  "checkLinks": true,
  "maxLinksPerPage": 10,
  "maxInternalLinksPerPage": 25,
  "includeExternalLinks": false,
  "checkAiReadiness": true,
  "respectRobotsTxt": true,
  "requestTimeoutMs": 15000,
  "previousSnapshot": {
    "overallScore": 76
  },
  "demoMode": false
}
```

### Output fields

This Actor writes a validated audit record to the default dataset and stores terminal run details in the default key-value store.

| Field | Type | Description |
| --- | --- | --- |
| `siteUrl` | string | Normalized public origin audited by the Actor. |
| `auditedAt` | string | UTC timestamp when the report was created. |
| `pagesRequested` | integer | Maximum HTML page sample requested by the input. |
| `pagesAudited` | integer | Number of usable same-origin HTML pages inspected. |
| `crawlStatus` | string | Whether discovery completed fully or retained useful partial results. |
| `overallScore` | integer | Bounded triage score derived from observed checks. |
| `categoryScores` | object | Scores for crawlability, indexation, on-page, links, structured data, performance, security, and optional AI readiness. |
| `robotsStatus` | string | Whether robots.txt was present and reachable. |
| `sitemapStatus` | string | Whether a reachable sitemap with same-origin URLs was found. |
| `sitemapUrlCount` | integer | Number of same-origin URLs extracted from the sitemap used for bounded discovery. |
| `llmsStatus` | string | AI-readiness check result for the optional llms.txt file. |
| `https` | boolean | Whether the normalized audited origin uses HTTPS. |
| `issueCounts` | object | Counts of critical, warning, and informational findings. |
| `pages` | array | Page-level metadata, indexation, heading, image, link, structured-data, and response observations. |
| `internalLinkSummary` | object | Sampled internal-link totals, destination coverage, nofollow/empty-anchor counts, link-health classifications, and bounded-sample orphan candidates. |
| `internalLinks` | array | Bounded source-to-destination internal-link details with anchor text, rel directives, and destination-audited status. |
| `linkChecks` | array | Sampled link responses with source URL, anchor text, rel directives, link type, and classification. |
| `issues` | array | Prioritized findings with severity, category, evidence URL, and recommendation. |
| `scoreChangeFromPreviousSnapshot` | integer or null | Signed overall-score change when a previous snapshot was supplied. |
| `warnings` | array | Non-fatal discovery or transport warnings. |

#### Illustrative output record

```json
{
  "siteUrl": "https://example.com",
  "auditedAt": "2026-08-09T04:45:00.000Z",
  "pagesRequested": 10,
  "pagesAudited": 10,
  "crawlStatus": "complete",
  "overallScore": 78,
  "categoryScores": {
    "crawlability": 100,
    "onPage": 72
  },
  "robotsStatus": "present",
  "sitemapStatus": "present",
  "llmsStatus": "missing",
  "https": true,
  "issueCounts": {
    "critical": 1,
    "warning": 4,
    "info": 7
  },
  "pages": [
    {
      "url": "https://example.com/",
      "status": 200,
      "titleLength": 42,
      "imagesMissingAlt": 0
    }
  ],
  "internalLinkSummary": {
    "totalInternalLinks": 84,
    "uniqueInternalDestinations": 17,
    "brokenInternalLinks": 1,
    "orphanCandidatePages": ["https://example.com/pricing"]
  },
  "internalLinks": [
    {
      "sourceUrl": "https://example.com/",
      "url": "https://example.com/about",
      "anchorText": "About us",
      "rel": [],
      "isNofollow": false,
      "destinationAudited": true
    }
  ],
  "linkChecks": [
    {
      "url": "https://example.com/about",
      "classification": "ok",
      "status": 200
    }
  ],
  "issues": [
    {
      "severity": "warning",
      "code": "images-missing-alt",
      "evidenceUrl": "https://example.com/about"
    }
  ],
  "scoreChangeFromPreviousSnapshot": 6,
  "warnings": []
}
```

### How it works

The Actor starts from the supplied public homepage or origin, follows same-origin links and sitemap URLs, and samples up to the requested number of HTML pages. It retains a bounded internal-link graph for the sampled pages, including anchor text, rel directives, inbound/outbound coverage, and whether a linked destination was audited. It can separately check a bounded sample of discovered links, include or exclude external links in that network sample, and optionally evaluate AI-crawler signals such as named directives, `llms.txt`, and structured-data availability. When `respectRobotsTxt` is enabled, discovered pages disallowed for the default user-agent group stay outside the sample, while robots.txt itself is still recorded as an audit signal.

### Pricing

Complete SEO Audit Tool - Technical Website Audit uses Pay per event plus Apify platform usage. The primary `seo-audit-completed` event is **$0.10 per persisted audit report**, while Apify platform usage is billed separately. Open the live Pricing tab for the current event details and platform billing view.

A bounded 10-page audit that writes one report costs **$0.10 + Apify platform usage**. The same is true of a 50-page audit because the primary event is charged once per persisted report, although higher `maxPages`, `maxLinksPerPage`, and `maxInternalLinksPerPage` can increase platform usage and report size. Keep the settings aligned with the decision you need to make.

Last verified against the live Apify contract on 2026-08-09. The report is derived from the public HTTP pages fetched during that run; it is a current bounded-sample audit, not a search-engine index or ranking measurement.

### Use with AI agents (MCP)

This Actor is available as an Apify Actor usable through Apify MCP. The tool runs a public-site technical SEO audit and returns a dataset report plus terminal records for the run summary and output.

Actor identity: `khadinakbar/complete-seo-audit`

> Audit `https://example.com` with a 10-page sample. Return the overall score, category scores, issue counts, top prioritized issues with evidence URLs, and any warnings. Keep the audit scoped to the supplied public site and summarize the results from the dataset output.

When you read the results through MCP or the Apify API, the dataset item is the source-linked report. `issues` contains prioritized findings, `pages` contains page-level observations, and `linkChecks` contains the bounded link sample. `warnings` helps you see whether discovery or transport produced partial coverage while still preserving useful results. `scoreChangeFromPreviousSnapshot` is present when `previousSnapshot.overallScore` was supplied. Pagination is bounded by `maxPages`, and link sampling is bounded by `maxLinksPerPage`, so an agent should treat the output as a sampled technical audit rather than a full site-wide inventory. Cost-wise, the audit event is charged per completed report, with Apify platform usage billed separately.

### Apify API example

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({
  token: process.env.APIFY_TOKEN,
});

const input = {
  siteUrl: 'https://example.com',
  maxPages: 10,
  checkLinks: true,
  checkAiReadiness: true,
  respectRobotsTxt: true,
};

const run = await client.actor('khadinakbar/complete-seo-audit').call(input);

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log('Dataset items:', items);

const outputRecord = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');
const runSummaryRecord = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('RUN_SUMMARY');

console.log('OUTPUT:', outputRecord?.value);
console.log('RUN_SUMMARY:', runSummaryRecord?.value);
```

### Best results and outcome guidance

Use the same site URL, sample size, and audit settings when comparing runs so score changes are easier to interpret. Keep the scope focused when you are triaging a release, and expand `maxPages` only when you need a broader sample. If link health is already tracked elsewhere, you can turn off `checkLinks` to keep the audit centered on metadata, crawling, and indexation. If the comparison value in `previousSnapshot` comes from an earlier run, the report can include the signed change in overall score.

### Design note

I found that the dataset schema always requires `pages`, `linkChecks`, `issues`, and `warnings`, which keeps the report structurally complete even when some arrays are empty.

### FAQ

#### When should I use this Actor instead of a general crawler?

Use this Actor when you want a technical SEO audit focused on one public website and a bounded same-origin sample, with prioritized SEO findings and evidence URLs.

#### Can I compare one audit to a previous run?

Yes. Supply `previousSnapshot.overallScore` to receive `scoreChangeFromPreviousSnapshot` in the output record.

#### Does this Actor inspect search ranking or AI answers?

The contract describes a technical audit based on public HTTP evidence. It does not query AI answers or claim rankings.

#### How broad is the crawl?

The crawl starts from the supplied public site and samples up to `maxPages` same-origin HTML pages, with link sampling limited by `maxLinksPerPage`.

#### Can I include outbound links in the check?

Yes. Set `includeExternalLinks` to true when outbound-link QA is part of the workflow.

#### What happens if I want a simpler audit?

Set `checkAiReadiness` to false for a conventional technical audit, and reduce `maxPages` or `checkLinks` to keep the scope tighter.

### Focused standalone workflow

Complete SEO Audit Tool - Technical Website Audit is designed as a focused standalone workflow.

### Responsible use

Audit only public websites you are authorized to evaluate. Respect applicable law, website terms, rate limits, intellectual property rights, and privacy obligations. Keep credentials, cookies, private URLs, and private-network addresses out of the input.

# Actor input Schema

## `siteUrl` (type: `string`):

The public website origin or homepage to audit, for example https://example.com. The Actor follows same-origin links and sitemap URLs from this starting point. Required and must not contain credentials or private-network addresses.

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

Maximum same-origin HTML pages to sample, including the homepage. Use 1 for a fast spot check and up to 50 for a broader bounded audit. Defaults to 10 and limits crawl scope, not platform usage. Not a search-engine index inspection.

## `checkLinks` (type: `boolean`):

Fetches a bounded sample of discovered links and classifies them as ok, redirect, broken, blocked, timeout, or error. Defaults to true. Use false when you already have a dedicated link inventory. Not a replacement for a full broken-link crawl.

## `maxLinksPerPage` (type: `integer`):

Maximum unique links sampled from each analyzed page when link checks are enabled. Defaults to 10 and accepts 1 through 50. Lower values reduce target requests and platform usage. Not a cap on links reported in page counts.

## `maxInternalLinksPerPage` (type: `integer`):

Maximum extracted internal-link details retained for each analyzed page. Defaults to 25 and accepts 1 through 100. It limits report size, not same-origin page discovery or link-health checks. Increase it when you need a denser internal-link graph for the sampled pages.

## `includeExternalLinks` (type: `boolean`):

Includes off-domain links in the bounded link-health sample. Defaults to false so the audit stays focused on the site you supplied. Enable when outbound-link QA is part of the job. It does not grant access to private destinations.

## `checkAiReadiness` (type: `boolean`):

Checks named AI crawler directives, llms.txt, and structured-data availability alongside conventional SEO signals. Defaults to true. Disable for a conventional technical audit only. It does not query ChatGPT, Gemini, Perplexity, or claim AI citations.

## `respectRobotsTxt` (type: `boolean`):

Skips discovered same-origin pages disallowed for the default user-agent group. Defaults to true. robots.txt is still fetched and reported as an audit signal. This setting does not bypass access controls or authenticate private pages.

## `requestTimeoutMs` (type: `integer`):

Maximum time allowed for each public HTTP request. Defaults to 15000 milliseconds and accepts 3000 through 30000. Increase only for slow but authorized public sites. It is not a total run-time guarantee.

## `previousSnapshot` (type: `object`):

Optional prior report summary used to calculate overall score change. Supply fields such as overallScore from an earlier run. Defaults to no comparison. Do not include credentials, cookies, analytics exports, or private URLs.

## `demoMode` (type: `boolean`):

Validates the run contract without fetching a site or charging the audit event. Defaults to false. Use for integration smoke tests only. It is not a real SEO report and returns no audited pages.

## Actor input object example

```json
{
  "siteUrl": "https://example.com",
  "maxPages": 10,
  "checkLinks": true,
  "maxLinksPerPage": 10,
  "maxInternalLinksPerPage": 25,
  "includeExternalLinks": false,
  "checkAiReadiness": true,
  "respectRobotsTxt": true,
  "requestTimeoutMs": 15000,
  "previousSnapshot": {
    "overallScore": 76
  },
  "demoMode": false
}
```

# Actor output Schema

## `auditReport` (type: `string`):

One validated complete SEO audit report for the supplied public site.

## `output` (type: `string`):

Terminal outcome and audit result for this run.

## `runSummary` (type: `string`):

Terminal diagnostics, issue counts, warnings, and event-charge accounting.

# 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 = {
    "siteUrl": "https://example.com"
};

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

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

```

## MCP server setup

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