# Lighthouse PageSpeed Checker - Core Web Vitals in Bulk (`martin10291/lighthouse-pagespeed-audit`) Actor

Real Google Lighthouse (headless Chromium) on a list of URLs, mobile and/or desktop. One row per URL and strategy: performance, accessibility, best-practices and SEO scores, LCP, FCP, CLS, TBT, Speed Index, TTI, page weight, requests, top 5 opportunities and failing SEO/accessibility audits. No Goog

- **URL**: https://apify.com/martin10291/lighthouse-pagespeed-audit.md
- **Developed by:** [Martin Petrov](https://apify.com/martin10291) (community)
- **Categories:** SEO tools, Automation, Integrations
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Lighthouse PageSpeed Audit - Core Web Vitals, Bulk, MCP

You need Lighthouse scores and Core Web Vitals for many URLs, but the PageSpeed Insights API wants a Google key and hits quota limits.
This actor runs the real Google Lighthouse (headless Chromium) on every URL you give it: no API key, no quota, one clean row per page.

### Run it from the API

```bash
curl -X POST "https://api.apify.com/v2/acts/martin10291~lighthouse-pagespeed-audit/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://example.com", "https://www.python.org"], "strategy": "both"}'
```

### Use it from an AI agent (MCP)

Add this server URL to Claude, Cursor or any MCP client:

```
https://mcp.apify.com/?actors=martin10291/lighthouse-pagespeed-audit
```

Then ask: "Audit https://mysite.com on mobile and tell me the three biggest speed problems."

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `urls` | list of strings | `["https://example.com"]` | Pages to audit. A link without scheme gets `https://`. |
| `strategy` | `mobile` / `desktop` / `both` | `mobile` | `both` gives two rows per URL. |
| `categories` | list | all four | Subset of `performance`, `accessibility`, `best-practices`, `seo`. Fewer is a little faster; skipped ones are `null`. |
| `maxUrls` | integer | 50 | Cap on URLs audited per run (max 1000). |
| `concurrency` | integer | 2 | Parallel audits. Each runs its own Chrome (about 0.5-1 GB). |
| `monitorId` | string | empty | Turns on monitoring (score history and alerts). |
| `alertDrop` | integer | 5 | Alert when any category score falls by this many points. |
| `onlyAlerts` | boolean | false | Output only rows with `alert=true`. |
| `includeErrorRows` | boolean | false | Also add a (billed) row with `error` for pages that cannot be audited. Off by default: failed pages are free and listed in RUN_SUMMARY. |

### Output

One row per URL and strategy:

```json
{
  "url": "https://example.com",
  "finalUrl": "https://example.com/",
  "strategy": "mobile",
  "fetchedAt": "2026-11-04T14:34:28.763Z",
  "performance": 97,
  "accessibility": 96,
  "bestPractices": 100,
  "seo": 80,
  "lcpMs": 1245,
  "fcpMs": 1147,
  "cls": 0,
  "tbtMs": 204,
  "speedIndexMs": 1147,
  "ttiMs": 1494,
  "totalByteWeight": 2146,
  "requests": 2,
  "opportunities": [],
  "failingAudits": [
    {"id": "meta-description", "title": "Document does not have a meta description", "category": "seo"}
  ],
  "lighthouseVersion": "13.6.0",
  "durationSec": 21.2,
  "error": null
}
```

Scores are integers 0-100. `opportunities` are the 5 biggest savings (milliseconds and/or bytes). `failingAudits` lists failed SEO and accessibility checks.
If a page cannot be loaded, the row has `error` set and all scores `null`; the run still finishes and `RUN_SUMMARY` has `lastError`.

### Monitoring and alerts

Set a `monitorId` (for example `my-shop`). The actor remembers the last scores of every URL and strategy in a named key-value store.
On the next run with the same ID each row gets:

- `previousPerformance` and `performanceDelta` (points since the last run)
- `alert: true` and `alertReasons` (for example `performance 95 -> 73 (-22)`) when any audited category fell by `alertDrop` points or more
- `previousCheckedAt`

Schedule the actor daily or weekly in Apify, set `onlyAlerts: true`, and you only get rows (and only pay) when something got worse. Connect the dataset to a webhook, Slack or email.

### Pricing

$10.00 per 1,000 results ($0.01 per audit), about 3x cheaper than other real-Lighthouse actors ($0.03 per audit). One row is one audit; failed pages are free. No Google API key, no PageSpeed quota.

### Limits and honest notes

- It is real Lighthouse 13 with its default mobile and desktop emulation and its own user agent. No proxies, no user-agent spoofing: pages that block datacenter traffic can return an error.
- Lab data, not field data: this is not the Chrome UX Report (CrUX) real-user data.
- Lighthouse scores vary a little between runs (typically a few points). Lower concurrency gives steadier numbers. Raise `alertDrop` if you get false alerts.
- Typical audit takes 20-60 seconds. Heavy pages need about 1 GB each; default memory is 4 GB (1 CPU core) for stable scores; for concurrency above 2 give the run more memory.
- Pages behind a login, or that need clicks, are not covered.
- Failed audits are free and not written as rows by default; set `includeErrorRows` to true to get them as rows with `error`.

### Use it as an integration (chain it after another actor)

This actor can run automatically after any actor whose results contain a URL.

1. Open the source actor in Apify Console and go to the **Integrations** tab.
2. Click **Add integration** -> **Actor**, pick this actor and set **Dataset** to `{{resource.defaultDatasetId}}` (leave `urls` empty). Set your other options and save.
3. When the source run finishes, this actor reads its dataset and processes every row. The field is detected automatically; set **Dataset field** if your column has another name.

You can also start it by hand with `datasetId` (pick a dataset or paste its ID) to process an existing dataset.

Good sources to chain from:

- compass/crawler-google-places (Google Maps Scraper)
- martin10291/local-business-leads-osm
- apify/website-content-crawler
- martin10291/website-tech-stack-detector

# Actor input Schema

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

Pages to audit with Google Lighthouse. One result row is produced per URL and strategy. Use full http(s) links; a link without a scheme gets https:// added.

## `strategy` (type: `string`):

mobile = Lighthouse default mobile emulation (slow 4G, mid-range phone). desktop = desktop preset. both = two audits per URL (two result rows).

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

Lighthouse categories to run. Fewer categories make each audit a little faster. Categories not run come back as null. Leave empty for all four (performance, accessibility, best-practices, seo).

## `maxUrls` (type: `integer`):

Audit at most this many URLs from the list (counted before strategies are applied). Caps the cost of big lists.

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

How many audits run at the same time. Each one starts its own Chrome (about 500-800 MB). Keep 2 on the default 2 GB memory; raise it only together with the run memory. Very high values make timings less accurate. With the default 4 GB memory (1 CPU core) 2 is the best speed/stability balance; use 1 for the most stable scores.

## `monitorId` (type: `string`):

Turns on monitoring. Scores of every URL and strategy are remembered under this ID, and the next run with the same ID adds previousPerformance, performanceDelta and alert to each row. Use a different ID per site or customer. Leave empty for a one-off audit.

## `alertDrop` (type: `integer`):

Monitoring only. A row gets alert=true when any audited category score fell by at least this many points (0-100 scale) compared with the previous run with the same Monitor ID.

## `onlyAlerts` (type: `boolean`):

Monitoring only. Push only rows where alert is true (a score drop), so you pay and get notified only when something got worse. Scores are still remembered for the next run.

## `includeErrorRows` (type: `boolean`):

Also write a row (billed) for URLs that could not be audited. Off by default: failed URLs are free and listed in RUN_SUMMARY.

## `datasetId` (type: `string`):

Optional. Pick a dataset (or paste its ID) to read the input from, for example the result of Google Maps Scraper. When this actor runs as an integration, the dataset of the triggering run is used automatically (payload.resource.defaultDatasetId), so you can leave this empty. If set, the values found in the dataset replace the main input list.

## `datasetField` (type: `string`):

Optional. The item field that holds the value, for example website, url or videoUrl (dot paths like author.url work). Empty = detected automatically.

## `datasetMaxItems` (type: `integer`):

Upper limit of unique values taken from the dataset, to keep the cost under control.

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "strategy": "mobile",
  "maxUrls": 50,
  "concurrency": 2,
  "alertDrop": 5,
  "onlyAlerts": false,
  "includeErrorRows": false,
  "datasetMaxItems": 1000
}
```

# Actor output Schema

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

One row per URL and strategy: scores (performance, accessibility, bestPractices, seo), Core Web Vitals metrics, top opportunities, failing audits, and in monitoring mode previousPerformance, performanceDelta and alert.

# 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://example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("martin10291/lighthouse-pagespeed-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://example.com"] }

# Run the Actor and wait for it to finish
run = client.actor("martin10291/lighthouse-pagespeed-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://example.com"
  ]
}' |
apify call martin10291/lighthouse-pagespeed-audit --silent --output-dataset

```

## MCP server setup

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