# On-Page SEO Audit – Bulk Meta Tags, Headings & Schema Checker (`pinkish_armada/seo-page-audit`) Actor

Audit any list of URLs for on-page SEO: titles, meta descriptions, H1s, canonicals, robots/noindex, hreflang, JSON-LD schema, Open Graph, image alt text, links, redirects and speed basics. Score plus prioritised issues.

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

## Pricing

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

## On-Page SEO Audit – Bulk Meta Tags, Headings & Schema Checker

Audit **hundreds or thousands of URLs** for on-page SEO in one run. For every page you get a **score from 0 to 100**, a **prioritised list of issues** (errors → warnings → notices) and all the raw SEO facts, ready to export to CSV, Google Sheets or your dashboard.

**What it checks on each page:**

- **Title tag:** missing, too short or too long, multiple titles. **Meta description:** missing, length.
- **Headings:** H1 present or multiple, H1 vs title, skipped heading levels, H1–H6 counts.
- **Indexability:** meta robots / googlebot, **X-Robots-Tag header**, noindex/nofollow, **canonical** (missing, multiple, pointing elsewhere), HTTP status, **redirect chains**.
- **International:** `<html lang>`, **hreflang** codes and self-reference.
- **Structured data:** JSON-LD blocks and **@type list** (Article, Product, FAQPage, BreadcrumbList...), invalid JSON-LD, microdata types.
- **Social previews:** Open Graph (og:title, og:image...) and Twitter Card tags.
- **Content:** visible word count, thin content, text-to-HTML ratio.
- **Images and links:** images without alt text (with a sample list), lazy-loading, internal/external/nofollow links, links without anchor text.
- **Tech basics:** HTTPS, mixed content, HSTS, compression, HTML size, server response time, viewport, charset, favicon.
- **Run summary:** average score, **duplicate titles** and **duplicate meta descriptions** across all audited pages.

### Why this Actor

- 💸 **$2 per 1,000 pages.** Popular SEO audit Actors charge $10–$40 per 1,000 pages.
- ⚡ **Fast and light.** Plain HTTP with no headless browser, so a 1,000-page audit takes minutes.
- 🧾 **Actionable output.** Every issue has a code, a severity and a human-readable message. The *Issues* view gives one row per issue, perfect for sorting and filtering.
- 🤝 **Polite.** Respects robots.txt by default, fetches each listed URL once (no crawling), identifies itself, and uses timeouts.
- 🤖 **Agent-friendly.** Structured JSON that AI agents and automations (Make, Zapier, n8n, MCP) can act on.

### Input

```json
{
  "urls": ["https://wordpress.org/news/", "https://www.gov.uk/", "apify.com"],
  "includeNotices": true
}
```

| Field | Default | Description |
|---|---|---|
| `urls` | – | Page URLs to audit (required). Up to 20,000. Bare domains get `https://`. |
| `includeNotices` | true | Include low-priority suggestions |
| `respectRobotsTxt` | true | Skip disallowed pages (not charged) |
| `maxConcurrency` | 5 | Parallel requests |
| `timeoutSecs` | 30 | Per page |

**Tip:** to audit a whole site, first list its URLs with a sitemap extractor (e.g. [Sitemap URL Extractor](https://apify.com/pinkish_armada/sitemap-url-extractor)) and paste them here.

### Output (one row per page, shortened)

```json
{
  "url": "https://www.gov.uk/",
  "statusCode": 200,
  "score": 88,
  "issueCounts": { "error": 0, "warning": 1, "notice": 2 },
  "issues": [
    { "severity": "warning", "code": "TITLE_TOO_SHORT", "message": "Title is 15 characters (aim for 30–60)." },
    { "severity": "notice", "code": "META_DESCRIPTION_SHORT", "message": "Meta description is 64 characters (aim for 70–160)." }
  ],
  "title": "Welcome to GOV.UK",
  "metaDescription": "GOV.UK - The place to find government services and information",
  "h1": ["..."],
  "headings": { "h1": 1, "h2": 6, "h3": 12, "h4": 0, "h5": 0, "h6": 0 },
  "canonical": "https://www.gov.uk/",
  "robots": { "meta": null, "xRobotsTag": null, "indexable": true, "follow": true },
  "hreflang": [],
  "wordCount": 412,
  "images": { "total": 3, "withoutAlt": 0, "lazyLoaded": 0, "withoutAltSample": [] },
  "links": { "internal": 58, "external": 4, "nofollow": 0, "emptyAnchorText": 0 },
  "structuredData": { "jsonLdBlocks": 1, "jsonLdTypes": ["WebSite"], "invalidJsonLd": 0, "microdataTypes": [] },
  "openGraph": { "title": "...", "image": "..." },
  "redirects": [],
  "responseTimeMs": 61,
  "status": "ok"
}
```

**Issue codes include:**

- Errors: `HTTP_ERROR`, `NOT_HTTPS`, `TITLE_MISSING`, `H1_MISSING`, `NOINDEX`.
- Warnings: `TITLE_TOO_LONG`, `META_DESCRIPTION_MISSING`, `CANONICAL_MISSING`, `REDIRECT_CHAIN`, `IMAGES_WITHOUT_ALT`, `MIXED_CONTENT`, `SLOW_RESPONSE`, `INVALID_JSON_LD`, `HREFLANG_INVALID`, `VIEWPORT_MISSING`, `LANG_MISSING`.
- Notices: `NO_STRUCTURED_DATA`, `OPEN_GRAPH_INCOMPLETE`, `THIN_CONTENT`, `HSTS_MISSING`, `NO_COMPRESSION` and more.

**Score:** starts at 100 and loses 12 points per error, 5 per warning and 1 per notice.

### Pricing

Pay per event, plus a tiny Actor start fee ($0.00005 per GB of memory):

- **Audited page:** **$0.002** per page ($2 per 1,000 pages), compute included.
- Pages that return HTTP 4xx/5xx, time out, don't resolve, aren't HTML or are blocked by robots.txt are reported but **not charged**.
- Set a maximum cost per run to cap spend; the Actor stops cleanly when it's reached.

### Limitations (honest)

- **No JavaScript rendering.** The audit sees the HTML as served, which is what most search-engine first passes and all social previews see. Content injected only by client-side JavaScript isn't counted.
- **One page per URL, no crawling.** Combine with a sitemap extractor for full-site audits. Broken outbound links are not checked; use a broken-link checker for that.
- **Not a Lighthouse/Core Web Vitals test.** Response time is server time-to-HTML, not page-load metrics.
- **Heuristic thresholds** (e.g. title 30–60 characters) follow common SEO guidelines and are not search-engine rules.

### FAQ

**Can I audit a competitor's site?** It fetches public pages like a normal visitor and respects robots.txt by default. Use it responsibly and keep concurrency low for small sites.

**Can I schedule it?** Yes. Run it weekly on your key pages with Apify Schedules and compare scores over time.

# Actor input Schema

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

Pages to audit (each URL is fetched once; nothing is crawled). Tip: get all URLs of a site with a sitemap extractor first. Up to 20,000 per run.

## `includeNotices` (type: `boolean`):

Include low-priority suggestions (e.g. missing structured data, Open Graph, HSTS) in the issues list. Errors and warnings are always included.

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

Skip pages that robots.txt disallows for automated agents (not charged). Turn off only for sites you own or are allowed to audit.

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

Pages fetched at once. Keep low (≤5) for a single small site.

## `timeoutSecs` (type: `integer`):

Pages slower than this are reported as TIMEOUT (not charged).

## Actor input object example

```json
{
  "urls": [
    "https://wordpress.org/news/",
    "https://www.gov.uk/",
    "apify.com"
  ],
  "includeNotices": true,
  "respectRobotsTxt": true,
  "maxConcurrency": 5,
  "timeoutSecs": 30
}
```

# Actor output Schema

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

Score, issue counts and key SEO facts per page.

## `issues` (type: `string`):

One row per issue (severity, code, details) across all pages.

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

Pages audited, average score, duplicate titles and meta descriptions.

# 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://wordpress.org/news/",
        "https://www.gov.uk/",
        "apify.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pinkish_armada/seo-page-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": [
        "https://wordpress.org/news/",
        "https://www.gov.uk/",
        "apify.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pinkish_armada/seo-page-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": [
    "https://wordpress.org/news/",
    "https://www.gov.uk/",
    "apify.com"
  ]
}' |
apify call pinkish_armada/seo-page-audit --silent --output-dataset

```

## MCP server setup

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