# Website Technical Audit — SEO, Accessibility & Broken Links (`kikou/audit-technique-site`) Actor

Crawls a site you own or manage and reports technical SEO issues, accessibility problems, broken links and performance warnings. Every check is validated against test sites whose defects are known in advance. Respects robots.txt. Report in English or French.

- **URL**: https://apify.com/kikou/audit-technique-site.md
- **Developed by:** [Christophe De Caroppo](https://apify.com/kikou) (community)
- **Categories:** Developer tools, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.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?

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

## Website Technical Audit — SEO, Accessibility & Broken Links

**Crawl a website you own or manage, and get a prioritised list of what is technically wrong with it.**

Point it at a URL. In a few minutes you get a per-page report and a summary that tells you, in order, what to fix first — broken links, missing titles, pages blocked from search engines, images without alt text, slow responses, duplicate metadata.

No account on a third-party SEO suite. No monthly subscription. You pay for the pages you actually audit.

***

### Who this is for

- **Web agencies** running a technical check before handing a site to a client, or as part of a monthly retainer.
- **SEO consultants** who need a fast, repeatable audit across many client sites.
- **Site owners and developers** who want to know what broke after a redesign or a migration.
- **Accessibility reviewers** looking for missing alt text, unlabelled form fields, undeclared page language and broken heading structure.

***

### What it checks

**Indexing and crawlability**

- Pages returning 4xx or 5xx errors
- Broken internal links (and external ones, optionally)
- `noindex` / `nofollow` directives — in both the meta tag and the `X-Robots-Tag` header
- Missing, mismatched or malformed canonical tags
- Redirect chains

**On-page SEO**

- Missing, too short or too long `<title>`
- Missing, too short or too long meta description
- Duplicate titles and descriptions **across the whole site**
- Missing or duplicated H1
- Broken heading hierarchy (h1 → h3, or a page that starts at h3)
- Thin content

**Accessibility**

- Images without an `alt` attribute (`alt=""` is correctly treated as intentional, not as a fault)
- Missing `lang` attribute on `<html>`
- Links with no accessible name
- Form fields with no associated label

**Mobile, performance and security**

- Missing or malformed viewport meta tag
- Slow server response times
- Heavy pages
- Pages served over HTTP instead of HTTPS
- Mixed content — HTTP resources loaded on an HTTPS page

**Rich results**

- Missing JSON-LD structured data
- JSON-LD blocks that fail to parse

***

### What you get

**A summary** (`SUMMARY` in the key-value store) built to be read in ten seconds:

```json
{
  "auditedSite": "https://example.com/",
  "overallScore": 74,
  "pagesAnalyzed": 248,
  "pagesWithErrors": 6,
  "brokenLinksFound": 14,
  "criticalIssues": 6,
  "majorIssues": 91,
  "minorIssues": 203,
  "whereToStart": [
    { "code": "broken_link", "label": "Broken links", "severity": "critical", "affectedPages": 14 },
    { "code": "missing_meta_description", "label": "Missing meta description", "severity": "major", "affectedPages": 68 }
  ],
  "pagesToFixFirst": [
    { "url": "https://example.com/old-page", "score": 20, "issueCount": 9 }
  ]
}
```

The list of broken links is stored alongside it, under `BROKEN_LINKS`.

**A dataset**, one row per page: URL, HTTP status, score out of 100, title, meta description, H1 count, images without alt, response time, crawl depth, and the full list of issues found with severity and explanation.

```json
{
  "url": "https://example.com/pricing",
  "statusCode": 200,
  "score": 74,
  "title": "Pricing | Example",
  "metaDescription": null,
  "h1Count": 1,
  "imagesWithoutAlt": 0,
  "issues": [
    {
      "code": "missing_meta_description",
      "severity": "major",
      "message": "No meta description: the search engine then picks a snippet at random."
    }
  ]
}
```

Every issue carries a stable `code` you can filter on, a `severity`, and a `message` written for a human. Export to Excel, CSV or JSON, or pull it from the API to feed your own report template.

**Report language.** Field names and issue codes are always English, so your integrations stay stable. The `message` and `label` texts follow the **Report language** setting — English by default, French available.

***

### How it was verified

The audit was tested against **150 generated sites whose defects were known in advance** — around 1 000 pages and 8 600 injected issues across three independent draws. Every injected defect was found, and no non-existent defect was reported:

| | |
|---|---|
| **Recall** (real defects actually found) | **100 %** |
| **Precision** (reported defects that are real) | **100 %** |

Plus 84 automated tests covering each rule, the crawl boundaries, and robots.txt compliance.

That test bench caught a real bug before release: pages returning **403** were silently skipped by the crawler's block-detection and never appeared in the report. A site with a protected section would have produced an incomplete audit without saying so.

***

### Scoring

Each page starts at 100 and loses points per issue: **25 for a critical**, **8 for a major**, **2.5 for a minor**. The overall score is the average across pages.

It is deliberately simple and documented, so you can explain it to your own client instead of pointing at a black box.

***

### Settings

| Setting | Default | What it does |
|---|---|---|
| **Website URL** | — | The site to audit. Required. |
| **Maximum pages** | 100 | How many pages to crawl. This is what you pay for. |
| **Maximum crawl depth** | 5 | How many clicks from the start page. `0` audits only that page. |
| **Include subdomains** | off | Also audit `blog.example.com`, `shop.example.com`. |
| **Check external links** | off | Also verify outbound links still resolve. Slower. |
| **Parallel requests** | 5 | Lower it if the server is small or rate-limited. |

**Tip:** run it first with **Maximum pages = 20** to see the shape of the results and estimate what a full audit will cost.

***

### How it behaves

- **robots.txt is always respected.** There is no setting to override it, by design. Pages excluded by robots.txt are counted and reported so you know what wasn't seen.
- **No anti-bot circumvention.** No CAPTCHA solving, no proxy rotation to defeat rate limits, no spoofing. If a site blocks automated access, this Actor reports the failure rather than working around it.
- **Rate limited by default** — 5 parallel requests, 20 maximum. It won't hammer a small server.
- **No personal data is collected.** No email addresses, no phone numbers, no author names, no comments. Only technical characteristics of the documents. `mailto:` links are ignored entirely.
- **No browser** — pages are fetched and parsed as HTML, which is roughly twenty times cheaper in compute than driving a full browser. That saving is passed on in the price.

**Response time is measured end to end**, network latency included. A first connection to a distant server can cross the slow-response threshold without the server being at fault — the report says so rather than letting you blame the wrong thing. Re-run the audit before acting on that specific finding.

One consequence worth knowing: because there is no browser, content injected purely by client-side JavaScript is not seen. For most sites this doesn't matter — search engines index the served HTML too — but if your site is a single-page application that renders everything client-side, this tool will report thin content for pages that look full in a browser.

***

### Intended use

This Actor is for auditing websites **you own, manage, or are authorised to analyse**. That is what it is built and priced for.

***

### Pricing

Pay per event: a small fixed charge when the audit starts, then a charge per page audited. You pay for what you crawl — no subscription, no minimum.

Set **Maximum pages** to cap your spend exactly. If your run hits your account's spending limit mid-audit, the Actor stops cleanly and still gives you the report for the pages it completed, with a note saying so.

***

### Support

Found a false positive, or a check you'd expect that isn't here? Open an issue on the Actor's issues tab with the URL and what you expected — that's the fastest way to get it fixed.

# Actor input Schema

## `startUrl` (type: `string`):

The website to audit. Use a site you own or are authorised to analyse. The prefilled address is a public sandbox built for crawling — replace it with yours.

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

How many pages to crawl at most. This is what you pay for — start small to estimate the cost of a full audit.

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

How many clicks away from the starting page the crawler may go. 0 audits only the starting page.

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

Also audit subdomains (blog.example.com, shop.example.com). Off by default so the audit stays within the scope you expect.

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

Also verify that outbound links to other websites still work. Slower, and sends requests to third-party servers.

## `concurrency` (type: `integer`):

How many pages are fetched at the same time. Lower this if your server is small or rate-limited.

## `outputLanguage` (type: `string`):

Language of the issue descriptions in the report. Field names and issue codes stay in English when 'English' is selected.

## Actor input object example

```json
{
  "startUrl": "https://books.toscrape.com",
  "maxPages": 20,
  "maxDepth": 2,
  "includeSubdomains": false,
  "checkExternalLinks": false,
  "concurrency": 5,
  "outputLanguage": "en"
}
```

# Actor output Schema

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

One row per page: HTTP status, score out of 100, and every issue found with its severity and explanation.

## `summary` (type: `string`):

The ten-second read: overall score, issue counts by severity, what to fix first, and the pages to fix first.

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

Every URL that answered with an error, and the page it was found on.

# 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 = {
    "startUrl": "https://books.toscrape.com",
    "maxPages": 20,
    "maxDepth": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("kikou/audit-technique-site").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 = {
    "startUrl": "https://books.toscrape.com",
    "maxPages": 20,
    "maxDepth": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("kikou/audit-technique-site").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 '{
  "startUrl": "https://books.toscrape.com",
  "maxPages": 20,
  "maxDepth": 2
}' |
apify call kikou/audit-technique-site --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kikou/audit-technique-site"
        }
    }
}

```

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/Kxi6bOc4TnKE99aod/builds/KMZfDCfVZhQ0gsbVY/openapi.json
