# SEO Score API: SEO, AI Readiness and Accessibility Audit (`seoscoreapi/seo-score-api`) Actor

Audit a list of URLs with your own SEO Score API key. One row per URL: SEO score, grade, category and AI readiness scores, and a prioritized fix list. A free key audits 2 URLs per day.

- **URL**: https://apify.com/seoscoreapi/seo-score-api.md
- **Developed by:** [SEO Score API](https://apify.com/seoscoreapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## SEO Score API: SEO, AI Readiness and Accessibility Audit

Give this Actor a list of URLs and your own [SEO Score API](https://seoscoreapi.com/?utm_source=apify\&utm_medium=directory) key. It audits each page and writes one dataset row per URL: an overall SEO score (0 to 100), a letter grade, a score per category (meta, technical, social, performance, accessibility, AI readability), and a prioritized fix list where every fix has a severity (`high`, `medium` or `low`) and a plain instruction. Audits usually return in seconds.

The Actor is free. It calls the SEO Score API with your key, so your SEO Score API plan decides how many URLs you can audit. **A free key audits 2 URLs per day** (2 requests per minute, no credit card). Paid plans start at $5/month for 200 audits.

### What it checks

- **SEO audit** (every plan): 80+ checks per URL on paid plans, covering meta tags, technical SEO, social tags, performance, on-page accessibility, structured data, AI readability and, on paid plans, SXO, AEO and AIO scores. A free key is scored on 50+ checks, and its response details 2 checks per category and the top 2 fixes.
- **Accessibility audit, WCAG 2.1 AA** (paid plans, optional): score, grade, lawsuit risk level, violations with the affected elements and a fix for each. Runs on the axe-core engine.
- **GEO audit** (Basic plan and up, optional): how visible the page is to AI search and LLM answer engines, with its own score and fix list.

The Actor does not crawl. It audits exactly the URLs you list, one API call per URL per audit type.

### Input

| Field | Required | What it does |
|---|---|---|
| `urls` | yes | Pages to audit, one per line. |
| `apiKey` | no | Your SEO Score API key. Stored as a secret input. Without it the Actor runs one demo audit of the first URL (2 checks per category, top 2 fixes; the row has `demo: true`). |
| `audits` | no | Any of `seo`, `accessibility`, `geo`. Default `["seo"]`. |
| `includeCoreWebVitals` | no | Also measure Core Web Vitals (LCP, INP, CLS, FCP, TTFB) for each URL. Default off: it adds about 10 seconds per URL not measured in the last 24 hours. Uses no extra audits. |
| `maxAudits` | no | Stop after this many API calls in the run. |
| `maxConcurrency` | no | Audits in parallel (default 3). Requests are also paced to your plan's per-minute limit. |
| `includeRawAudit` | no | Include the full API response on each row (default on). |
| `requestTimeoutSecs` | no | Timeout per audit (default 120; at least 60 for SEO audits when Core Web Vitals are on). |

```json
{
  "urls": ["https://example-shop.com", "https://example-shop.com/pricing"],
  "apiKey": "ssa_your_key_here",
  "audits": ["seo"]
}
```

#### Getting a key

1. Go to [seoscoreapi.com](https://seoscoreapi.com/?utm_source=apify\&utm_medium=directory) and enter your email (or `POST /signup` with `{"email": "you@example.com"}`).
2. You get a 6-digit code by email. Confirm it (`POST /verify` with the email and code) and the key is returned.

No credit card is needed for the free key.

### Output

One row per URL. This is a real row from a run on a paid key, trimmed:

```json
{
  "url": "https://45squared.com",
  "status": "ok",
  "score": 96.894,
  "grade": "A+",
  "category_scores": {
    "meta": 98.625,
    "technical": 95.0,
    "social": 100.0,
    "performance": 92.5,
    "accessibility": 100.0,
    "ai_readability": 91,
    "sxo": 94,
    "aeo": 91,
    "aio": 87
  },
  "priorities": [
    {
      "severity": "low",
      "category": "technical",
      "issue": "Schema missing recommended fields",
      "fix": "Add recommended schema.org properties to unlock additional rich-result enhancements",
      "plain_english": "The page's machine-readable labels could include more detail to unlock extra search features.",
      "who_fixes_it": "developer"
    }
  ],
  "priorities_note": null,
  "accessibility": {
    "score": 100,
    "grade": "A+",
    "standard": "WCAG 2.1 AA",
    "lawsuit_risk": "minimal",
    "violations": 0,
    "best_practice_issues": 0,
    "needs_review": 1,
    "priorities": []
  },
  "geo": null,
  "errors": [],
  "plan": "ultra",
  "audited_at": "2026-10-07T18:01:08+00:00",
  "audit": { "...": "the full GET /audit response: every check with its status and detail" },
  "accessibility_audit": { "...": "the full GET /audit/accessibility response" }
}
```

| Field | Meaning |
|---|---|
| `status` | `ok` (every requested audit returned), `partial` (some did), `failed` (the page could not be audited), `skipped` (no call was made: quota used up, plan does not include it, or `maxAudits` reached). |
| `score`, `grade` | Overall SEO score, 0 to 100, and letter grade. |
| `category_scores` | One score per category. `sxo`, `aeo` and `aio` appear on paid plans. |
| `priorities` | Fixes in priority order: `severity`, `category`, `issue`, `fix`, `plain_english`, `who_fixes_it` (`developer`, `content` or `marketing`). |
| `priorities_note` | Set on free keys, which see the top 2 fixes. |
| `core_web_vitals` | With `includeCoreWebVitals` on: `status` (`ok`, or `unavailable` with a `reason`; `pending: true` means Google was still measuring, so the next run has it), `source` (`field` for real-user data, else `lab`), `lcp_ms`, `inp_ms`, `cls`, `fcp_ms`, `ttfb_ms`. Otherwise `null`. |
| `accessibility`, `geo` | Summaries of those audits when requested, otherwise `null`. |
| `errors` | One entry per audit that returned no result, with `code`, `http_status`, `reason` and `message`. |
| `audit`, `accessibility_audit`, `geo_audit` | The unmodified API responses (when `includeRawAudit` is on). |

A run summary (plan, API calls made, rows by status, and why any audit type stopped) is saved to the key-value store as `SUMMARY`.

### Limits and pricing

The Actor itself has no charge beyond normal Apify platform usage, which is small because it only makes HTTP calls. What you can audit is set by your SEO Score API plan:

| Plan | Price | Audits | Requests per minute | Accessibility audits | GEO audits |
|---|---|---|---|---|---|
| Free | $0, no card | 2 per day | 2 | not included | not included |
| Starter | $5/month | 200 per month | 10 | 5 per month | not included |
| Basic | $15/month | 1,000 per month | 30 | 20 per month | 1 per month |
| Pro | $39/month | 5,000 per month | 60 | 100 per month | 5 per month |
| Ultra | $99/month | 25,000 per month | 120 | 500 per month | 10 per month |

How the Actor handles those limits:

- It reads your plan and remaining allowance first (`GET /usage`, which is not counted as an audit) and never sends more audits than you have left. URLs beyond the allowance are written as `skipped` rows with the reason, so you can see exactly what was not audited.
- It spaces requests to stay under your plan's per-minute limit. On a free key that means about 30 seconds between the two audits.
- If the API still answers 429 for the per-minute limit, it waits (using `Retry-After` when given) and retries up to 3 times. If the 429 or 402 says the allowance is used up, it stops calling that audit type.
- A page that cannot be loaded (blocked the crawler, DNS failure, timeout) becomes a `failed` row with the API's `reason`, and the run continues. The API does not count those against your quota.
- A timeout or a 502/503/504 is retried once.
- With `includeCoreWebVitals` on, SEO audits run at most 3 at a time whatever `maxConcurrency` says, because each one also waits on a Google PageSpeed Insights measurement. A measurement that is not ready in time does not fail the row: the score is still there and `core_web_vitals.status` says `unavailable`.
- If no URL could be audited at all, the run is marked failed with the reason in the status message.

### FAQ

**Is this Actor free?**
Yes. You bring your own SEO Score API key. A free key audits 2 URLs per day. For more, paid plans start at $5/month for 200 audits.

**Do I need a credit card for the free key?**
No.

**How long does an audit take?**
Usually a few seconds per URL. Accessibility audits load the page in a real browser and can take longer.

**Can it audit a whole site?**
Not by itself. It audits the URLs you list. To cover a site, feed it URLs from a sitemap or from a crawler Actor.

**Why did some rows come back `skipped`?**
Your plan's allowance ran out during the run, the audit type is not in your plan, or `maxAudits` was reached. The row's `errors` field says which.

**Why are there only 2 fixes on my rows?**
Free keys see the top 2 fixes and 2 checks per category. Paid plans return the full list.

**Does a higher score mean higher rankings?**
No tool can promise that. The score measures how many known on-page and technical problems a page has. Fixing them removes obstacles; it does not guarantee a position.

**Is my API key safe?**
The key is a secret input, is only sent to `https://seoscoreapi.com/?utm_source=apify&utm_medium=directory` in the `X-API-Key` header, and is never written to the dataset or the log.

**Can I call the API directly instead?**
Yes: `curl -H "X-API-Key: YOUR_KEY" "https://seoscoreapi.com/audit?url=https://example-shop.com"`. Docs are at [seoscoreapi.com/docs](https://seoscoreapi.com/docs?utm_source=apify\&utm_medium=directory). There are also Python and Node clients, an n8n node, a GitHub Action and an MCP server.

### Alternatives, and when they fit better

- **An Actor with no outside key.** Several Apify Actors run their own on-page checks and bill per result through Apify. If you want one bill and do not want a second account, pick one of those. This Actor fits better when you want the same scores your team already gets from SEO Score API in CI, n8n or code, or when you need the accessibility and AI readiness audits in the same row.
- **Google PageSpeed Insights or Lighthouse.** Better when you only need lab performance metrics and Core Web Vitals, and they are free. They do not score AI readiness and their SEO category is a short list.
- **axe or Pa11y run directly.** Better when you need to script accessibility tests against pages behind a login or in a local build. The accessibility audit here uses the same axe-core engine against public URLs and adds a score and risk level.
- **Keyword and backlink suites (Ahrefs, Semrush, DataForSEO).** This Actor audits pages. It does not provide keyword volumes, rank tracking or a backlink index. Use those tools for that.

### Support

Questions or a wrong result: info@seoscoreapi.com, or open an issue on this Actor's Issues tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/seoscoreapi/seo-score-api/changelog.md

# Actor input Schema

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

One page per line. Each URL uses one audit from your SEO Score API plan. A free key covers 2 URLs per day. Without a key, only the first URL is audited, as a demo.

## `apiKey` (type: `string`):

Your own key, sent in the X-API-Key header. Free keys need no credit card: get one at https://seoscoreapi.com/?utm_source=apify\&utm_medium=directory (sign up with your email, then confirm the 6-digit code). Leave it empty to try the Actor: it then runs one demo audit of the first URL, with 2 checks per category and the top 2 fixes.

## `audits` (type: `array`):

SEO audit works on every plan. The accessibility audit (WCAG 2.1 AA) needs a paid plan and the GEO audit needs Basic or higher; each has its own monthly allowance. An audit your plan does not include is reported on the row, not treated as a failed run.

## `includeCoreWebVitals` (type: `boolean`):

Also measure LCP, INP, CLS, FCP and TTFB with Google PageSpeed Insights and add them to each row as `core_web_vitals`. Off by default because it is slower: about 10 seconds more per URL that was not measured in the last 24 hours. It uses no extra audits and does not change the score. With it on, at most 3 SEO audits run at once.

## `maxAudits` (type: `integer`):

Optional safety cap on calls made in this run, across all audit types. Leave empty to use whatever your plan has left.

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

How many audits run at once. The Actor also paces requests to your plan's per-minute limit, so a higher number never breaks the limit.

## `includeRawAudit` (type: `boolean`):

Adds the unmodified API response for each audit under `audit`, `accessibility_audit` and `geo_audit` (every check, with details). Turn off for a smaller dataset.

## `requestTimeoutSecs` (type: `integer`):

Audits usually return in seconds. Heavy pages can take longer. With Core Web Vitals on, an SEO audit is always given at least 60 seconds.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com"
  ],
  "audits": [
    "seo"
  ],
  "includeCoreWebVitals": false,
  "maxConcurrency": 3,
  "includeRawAudit": true,
  "requestTimeoutSecs": 120
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "urls": [
        "https://apify.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("seoscoreapi/seo-score-api").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://apify.com"] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,seoscoreapi/seo-score-api"
        }
    }
}
```

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/Tt9Vtt8Qr5bWdX6R0/builds/lNkuP8sAD1gicag7f/openapi.json
