# SEO Audit & Performance Checker — Full Site Lighthouse Scan (`ntriqpro/lighthouse-website-audit`) Actor

Enter one website address and get a full-site audit: Google Lighthouse runs on every page it finds via sitemap, and the performance, SEO, accessibility and best-practices findings come back as flat, exportable rows — plus site-wide score summaries.

- **URL**: https://apify.com/ntriqpro/lighthouse-website-audit.md
- **Developed by:** [daehwan kim](https://apify.com/ntriqpro) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$30.00 / 1,000 audit result rows

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

## SEO Audit & Performance Checker — Full Site Lighthouse Scan

**Give it one website address. Get a full-site SEO, performance, accessibility and best-practices audit — every page, every finding, as clean table rows.** This Actor runs **Google Lighthouse**, the same engine behind Chrome DevTools and PageSpeed Insights, against every page it can find on your site, then flattens the reports into rows you can sort, filter and export.

No Chrome extension, no per-page copy-pasting, no API key. Point it at a domain and it reads the sitemap, crawls internal links when there is no sitemap, audits each page, and returns both the raw findings and site-wide summaries.

Built for **SEO audits, site migrations, client reporting, Core Web Vitals tracking, and pre-launch QA**. Runs on the Apify platform, so you can schedule it, call it from the API, or wire it into your own pipeline.

> **Unofficial.** This Actor runs the open-source [Lighthouse](https://github.com/GoogleChrome/lighthouse) project (Apache-2.0) and is **not affiliated with, endorsed by, or sponsored by** Google. It audits **publicly reachable pages only**, respects `robots.txt`, and identifies itself honestly. You are responsible for complying with the target site's Terms of Service and with the laws that apply to you.

***

### Why use this Actor?

- **One input, hundreds of rows** — a single domain typically yields **~50 rows per page**. An 8-page site returns roughly **400 rows** in one run.
- **Finds the pages for you** — reads `sitemap.xml` first, falls back to internal-link discovery. You do not supply a URL list.
- **Four audit categories in one pass** — performance, SEO, accessibility, best practices. Turn off what you do not need.
- **Site-wide summaries** — average score per category and the most frequent issues across the whole site, as their own rows. No spreadsheet work on your side.
- **Compare several sites in one run** — put your client and their competitors in together and get a ranked league table per category. See [Compare a client against competitors](#compare-a-client-against-competitors).
- **Mobile and desktop side by side** — audit one device or both. Both means two full sets of scores, tagged by `formFactor`, so you can see exactly where mobile falls behind.
- **Never charged for failures** — pages that time out, refuse the connection, or are blocked by `robots.txt` cost you nothing.
- **Structured output** — one flat row per finding, ready for CSV, Excel, Google Sheets, or a database.

***

### How to use it

1. Put one or more website addresses in **Websites to audit** (`https://example.com`).
2. Set **Pages to audit per website** — how deep to go. Start at 3–10, raise it once you see the shape of the output.
3. (Optional) Trim **Audit categories** to just the ones you care about — fewer categories, faster runs, fewer rows.
4. Choose **Devices**: `mobile` (Google's default for ranking), `desktop`, or both. Both doubles the audit time and the number of rows.
5. Start the run and export from the Output tab as JSON, CSV, Excel, or HTML.

***

### Compare a client against competitors

This is what the Actor is best at. Put the site you work on **and the sites you are measured against** into `startUrls` in the same run. Every site is audited identically, and the run adds `comparison` rows: one per category per site, with the rank, the leader, and how many points behind you are.

```json
{
    "startUrls": [
        "https://your-client.com",
        "https://competitor-one.com",
        "https://competitor-two.com",
        "https://competitor-three.com"
    ],
    "maxUrlsPerDomain": 5,
    "categories": ["performance", "seo"],
    "formFactors": ["mobile"],
    "maxRunSecs": 1800,
    "maxResults": 800,
    "disclaimerAck": true
}
```

A `comparison` row looks like this:

```json
{
    "rowType": "comparison",
    "domain": "your-client.com",
    "category": "performance",
    "formFactor": "mobile",
    "auditTitle": "performance ranking on mobile: #3 of 4",
    "score": 61,
    "displayValue": "#3 of 4 — 61/100, 27 point(s) behind competitor-one.com (88)",
    "rank": 3,
    "comparedDomains": 4,
    "bestDomain": "competitor-one.com",
    "bestScore": 88,
    "gapToBest": 27
}
```

Filter the dataset to `rowType = comparison` and you have the slide: who leads each category, and by how much. Up to **10 sites per run**. Comparison rows appear only when at least two sites returned results — a single-site run produces none.

**Want the mobile-versus-desktop gap too?** Set `"formFactors": ["mobile", "desktop"]`. Every score row, summary row and comparison row is tagged with `formFactor`, and rankings are produced per device, so mobile and desktop are never averaged together.

***

### Input

| Field | Type | Description | Default |
|---|---|---|---|
| `startUrls` | array | **Websites to audit.** A domain or a specific page. Two or more sites also produce a ranked comparison (max 10) | `https://example.com` |
| `maxUrlsPerDomain` | integer | Pages to audit per website (max 200) | `3` |
| `categories` | array | `performance`, `seo`, `accessibility`, `best-practices` | all four |
| `formFactors` | array | Devices to audit on: `mobile`, `desktop`, or both | `["mobile"]` |
| `includePassedAudits` | boolean | Also return audits the page already passes | `false` |
| `pageTimeoutSecs` | integer | Per-page timeout, seconds (max 180) | `60` |
| `maxRunSecs` | integer | Total run time budget, seconds | `900` |
| `maxResults` | integer | Hard cap on result rows (max 5000) | `500` |

**Example input:**

```json
{
    "startUrls": ["https://example.com"],
    "maxUrlsPerDomain": 10,
    "categories": ["performance", "seo"],
    "formFactors": ["mobile"]
}
```

> The earlier single-device field `"formFactor": "mobile"` still works, so saved tasks and API calls written against the first release keep running unchanged.

***

### Output

Every row is one finding. Five row types come back in the same dataset, tagged by `rowType`.

**A page score** — one per page per category:

```json
{
    "rowType": "page-score",
    "domain": "example.com",
    "url": "https://example.com/",
    "category": "performance",
    "auditTitle": "Performance",
    "score": 100,
    "scoreDisplayMode": "score-0-100",
    "formFactor": "mobile",
    "lighthouseVersion": "12.8.2",
    "collectedAt": "2026-08-14T02:10:14.504Z"
}
```

**An individual finding** — what to actually fix, with the size of the win:

```json
{
    "rowType": "audit",
    "domain": "example.com",
    "url": "https://example.com/",
    "category": "performance",
    "auditId": "render-blocking-resources",
    "auditTitle": "Eliminate render-blocking resources",
    "auditDescription": "Resources are blocking the first paint of your page.",
    "score": 0.42,
    "displayValue": "Potential savings of 320 ms",
    "savingsMs": 320,
    "savingsBytes": null
}
```

**Site-wide rows** — `domain-category-score` (average per category across the site, per device) and `domain-top-issue` (the findings that recur on the most pages, per device).

**Comparison rows** — `comparison`, produced only when two or more sites returned results. One per category per device per site, carrying `rank`, `bestDomain` and `gapToBest`. See [Compare a client against competitors](#compare-a-client-against-competitors).

You can download the dataset as JSON, CSV, Excel, or HTML.

***

### Data fields

| Field | Format | Description |
|---|---|---|
| `rowType` | text | `page-score` / `audit` / `domain-category-score` / `domain-top-issue` / `comparison` |
| `domain` | text | Website the row belongs to |
| `url` | link | Page audited (empty on site-wide rows) |
| `category` | text | `performance`, `seo`, `accessibility`, `best-practices` |
| `auditId` | text | Lighthouse audit identifier, e.g. `render-blocking-resources` |
| `auditTitle` | text | Human-readable name of the score or finding |
| `auditDescription` | text | What it means and why it matters |
| `score` | number | 0–100 for page scores, 0–1 for individual audits |
| `displayValue` | text | Lighthouse's own summary, e.g. "Potential savings of 320 ms" |
| `savingsMs` | number | Estimated time saved by fixing it |
| `savingsBytes` | number | Estimated bytes saved by fixing it |
| `formFactor` | text | `mobile` or `desktop` — the device this row was measured on |
| `rank` | number | Comparison rows: this site's position for that category and device |
| `comparedDomains` | number | Comparison rows: how many sites were ranked |
| `bestDomain` | text | Comparison rows: the site that leads that category |
| `bestScore` | number | Comparison rows: the leader's score |
| `gapToBest` | number | Comparison rows: points behind the leader (`0` for the leader) |
| `affectedUrls` | number | Summary rows: pages the score or issue covers |
| `lighthouseVersion` | text | Engine version used for the run |
| `collectedAt` | date | Timestamp |

***

### Pricing / Cost estimation

**$0.03 per result row.** No subscription, no monthly fee.

**What is charged:** every delivered result row — `page-score`, `audit`, and the `domain-category-score`, `domain-top-issue` and `comparison` rows. The summary and comparison rows are charged because they are results in their own right: they are the cross-page and cross-site maths you would otherwise do by hand in a spreadsheet, delivered ready to paste into a report.

**What is never charged:** pages that time out or refuse the connection, URLs blocked by `robots.txt`, sites that produce no results, and every status or notice row. If a run stops early on its limit, you are only charged for what you actually received.

Measured on real runs:

| What you audit | Rows returned | Cost |
|---|---|---|
| 1 page, four categories, mobile | ~50–70 | **~$1.50–2.10** |
| The same page on mobile **and** desktop | ~2× the rows | ~2× the cost |
| Small site (8 pages), mobile | ~400 | **~$12.00** |
| Trimmed to 2 categories | roughly half the rows | roughly half the cost |
| 4 sites compared, 2 categories, mobile | comparison rows add 8 (2 categories × 4 sites) | **~$0.24** on top of the audits |

Two ways to control spend: lower **Pages to audit per website**, or set **Max result rows** — the run stops cleanly at that number and tells you it stopped. You can also set a maximum cost per run in the Actor's **Run options**; the run then finishes successfully with everything collected up to that point rather than failing.

**Free-plan users** get a sample of up to **25 rows per run** (auditing up to 3 pages per site), then the run ends successfully. The sample is not simply the first 25 rows produced: the run finishes auditing every site first, then delivers the highest-value rows — **site-vs-site comparison rows first, then site summary scores, top recurring issues, page scores, and finally a taste of the individual audit findings**. A closing message states exactly what the full dataset contained (for example, how many individual findings were left out). Upgrade your Apify plan to receive everything.

***

### Tips

- **Fewer categories, more pages.** If you only care about search, run `["seo"]` and raise `maxUrlsPerDomain` — you get broader coverage for the same spend.
- **Mobile is the number that matters** for Google ranking. Audit `desktop` separately when you are chasing a specific complaint.
- **Scores move between runs.** Lighthouse measures a live page over a real network, so performance scores vary a few points run to run. Compare trends, not single numbers.
- **One device for routine monitoring, both when something breaks.** Weekly tracking on `mobile` keeps the cost and run time down; switch both on when a client reports a problem you cannot reproduce.

***

### Set up a weekly automatic audit

A single audit tells you where a site stands today. A **scheduled** audit tells you when it slips — a deploy that adds 400 KB of JavaScript, an image nobody compressed, an `alt` attribute dropped in a redesign. You find out on Monday morning instead of when the rankings move.

Scheduling is built into Apify and needs nothing from you but a few clicks:

1. Run the Actor once with the input you want to repeat, so you know the run time and the row count.
2. On the run page, click **Create task** (or open the Actor → **Tasks** → **Create new task**). A task stores that exact input under a name like `client-weekly-seo`.
3. Open **Schedules** in the left sidebar → **Create new schedule**.
4. Add your task to it, set the cadence — `Weekly`, or a cron expression such as `0 6 * * 1` for every Monday at 06:00 — pick your timezone, and enable it.

Every run writes its own dataset, so the history builds up on its own. A few ways teams use it:

- **Regression alarm** — the same 5–10 pages every Monday. Filter each dataset to `rowType = domain-category-score` and chart the score over time.
- **Competitor tracking** — the multi-site input from above, run monthly. The `comparison` rows become a standing scoreboard of you against the field.
- **Client reporting** — one schedule per client, each with its own task, exported to Google Sheets through Apify's integrations or the API.

Budget it before you enable it: a schedule bills every time it fires. Multiply the row count of your test run by **$0.03**, then by how often it runs. Set **Max result rows** on the task as a hard ceiling so a site that suddenly grows a thousand sitemap entries cannot surprise you.

***

### Limitations

- Audits **publicly reachable pages only** — no login, no cookie injection, no bypassing of protections.
- Pages behind heavy bot protection may refuse the audit. Those rows come back marked as failed and are not charged.
- Page discovery uses `sitemap.xml` when present and internal links otherwise; pages reachable only through search boxes or JavaScript-only navigation may be missed.
- `robots.txt` is respected. Disallowed URLs are skipped and not charged.

***

### FAQ and support

**Is this the same as PageSpeed Insights?** It runs the same Lighthouse engine, but across your whole site in one go and returns the results as data instead of one report per page.

**Why do my scores differ from PageSpeed Insights?** PSI blends lab data with real-user field data from the Chrome UX Report. This Actor returns lab data only, measured at run time.

**Something is wrong or missing.** Open an issue on the Actor's Issues tab — it is read and answered.

⭐ If this audit saved you time, a sentence about what you used it for helps the next person decide whether it fits their case.

# Actor input Schema

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

One or more domains or page URLs. Each one is expanded into a list of pages via sitemap.xml (or internal links) and every page is audited. Enter two or more sites (your client plus their competitors) and the run also returns a ranked comparison per category. Max 10 per run. Example: example.com

## `maxUrlsPerDomain` (type: `integer`):

How many pages to discover and audit for each website. Each page takes roughly 10-30 seconds, so raise this only when you have the run time budget. 1-200.

## `categories` (type: `array`):

Which Lighthouse categories to run. Fewer categories means faster runs and fewer result rows.

## `formFactors` (type: `array`):

Which devices to audit each page on. Pick both to get the mobile and desktop numbers side by side — that doubles both the audit time and the number of result rows, so raise the run time budget when you do.

## `includePassedAudits` (type: `boolean`):

Off by default: only failing and actionable audits are returned, which is what you fix. Turn on to receive every audit Lighthouse ran, including the ones you already pass. This multiplies the number of billable rows.

## `pageTimeoutSecs` (type: `integer`):

How long Lighthouse may wait for a single page to load before giving up on it. 15-180.

## `maxRunSecs` (type: `integer`):

Stop auditing new pages after this many seconds and write the site summary with whatever was collected. Protects long runs from timing out with nothing to show. 60-21600.

## `maxResults` (type: `integer`):

Upper bound on billable result rows for this run — your cost ceiling. Free-plan runs return at most 25 rows regardless of this value.

## `disclaimerAck` (type: `boolean`):

Required. By checking this you confirm that (1) you audit only websites you own or are authorized to test; (2) you will respect each target site's Terms of Service; (3) this Actor reads publicly accessible pages only, honours robots.txt, and stores no personal data.

## Actor input object example

```json
{
  "startUrls": [
    "https://example.com"
  ],
  "maxUrlsPerDomain": 3,
  "categories": [
    "performance",
    "seo",
    "accessibility",
    "best-practices"
  ],
  "formFactors": [
    "mobile"
  ],
  "pageTimeoutSecs": 60,
  "maxRunSecs": 900,
  "maxResults": 500,
  "disclaimerAck": true
}
```

# Actor output Schema

## `dataset` (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"
    ],
    "maxUrlsPerDomain": 3,
    "categories": [
        "performance",
        "seo",
        "accessibility",
        "best-practices"
    ],
    "formFactors": [
        "mobile"
    ],
    "includePassedAudits": false,
    "pageTimeoutSecs": 60,
    "maxRunSecs": 900,
    "maxResults": 500,
    "disclaimerAck": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("ntriqpro/lighthouse-website-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"],
    "maxUrlsPerDomain": 3,
    "categories": [
        "performance",
        "seo",
        "accessibility",
        "best-practices",
    ],
    "formFactors": ["mobile"],
    "includePassedAudits": False,
    "pageTimeoutSecs": 60,
    "maxRunSecs": 900,
    "maxResults": 500,
    "disclaimerAck": True,
}

# Run the Actor and wait for it to finish
run = client.actor("ntriqpro/lighthouse-website-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"
  ],
  "maxUrlsPerDomain": 3,
  "categories": [
    "performance",
    "seo",
    "accessibility",
    "best-practices"
  ],
  "formFactors": [
    "mobile"
  ],
  "includePassedAudits": false,
  "pageTimeoutSecs": 60,
  "maxRunSecs": 900,
  "maxResults": 500,
  "disclaimerAck": true
}' |
apify call ntriqpro/lighthouse-website-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ntriqpro/lighthouse-website-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/hoaRaU6UaIIMg3Zha/builds/W5POuOR2trpws5nZQ/openapi.json
