# Core Web Vitals Checker: Bulk PageSpeed & Lighthouse Audit (`datacolada/lighthouse-core-web-vitals-auditor`) Actor

Core Web Vitals checker for many URLs at once. Run a bulk PageSpeed / Lighthouse audit on mobile and desktop and get a site speed report: scores, LCP, CLS, TBT with good/poor ratings, top fixes per page, optional real-user CrUX data (INP) and alerts when pages get slower.

- **URL**: https://apify.com/datacolada/lighthouse-core-web-vitals-auditor.md
- **Developed by:** [Cyd Dunscombe](https://apify.com/datacolada) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 page audits

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

## Bulk Lighthouse & Core Web Vitals Auditor

Run **Google Lighthouse on hundreds of URLs at once**, on **mobile and desktop**, and get one clean, spreadsheet-ready row per page: performance, accessibility, best-practices and SEO scores, **LCP, CLS, TBT, FCP, Speed Index and TTFB** with Google's good / needs-improvement / poor ratings, a Core Web Vitals pass/fail, and the **top 3 fixes** for each page, ranked by how much time they would save.

Add your own free Google API key to also get **real-user Core Web Vitals (CrUX field data: LCP, INP, CLS)** and to run audits on Google's PageSpeed Insights servers (**beta**, see below). Turn on **change tracking** and every run tells you which pages got slower or faster since the last one, so a daily schedule becomes a performance regression monitor.

> **Beta: Google API key mode.** The PageSpeed Insights engine and real-user (CrUX) field data both need your own Google API key. This mode is in **beta**: it is newer and less tested than the default Lighthouse engine, and Google's API quotas and responses can change. With **Engine** set to *Auto*, if Google refuses the key (invalid, or the API is not enabled) the run falls back to the built-in Lighthouse engine, charged as a normal Lighthouse audit. If field data cannot be fetched, those columns stay empty with a `fieldDataError` note. Failed pages are not charged. Please report any problem in the **Issues** tab.

### How to audit website speed in 3 steps

1. Paste your URLs into **URLs to audit** (or a `sitemap.xml` link to audit a whole site).
2. Pick **mobile**, **desktop** or both. Optional: turn on **Compare with the previous run**, set a **performance budget**, or add a Google API key for real-user data.
3. Click **Start**. Results appear in the **Output** tab in four views (Overview, Fixes, Real-user data, Changes). Export to CSV, Excel or JSON, or read them through the API.

### What you can use it for

- **SEO and Core Web Vitals audits** for a whole site or a client list, mobile and desktop, in one run.
- **Performance regression monitoring:** schedule it daily or after every deploy and get flagged when a page's score drops or LCP/CLS/TBT moves to a worse rating.
- **Agency reporting:** one row per page and device, with plain-English "fix this first" items and an optional full Lighthouse HTML report per page.
- **Competitor benchmarking:** compare your pages with competitors' on the same metrics.
- **Performance budgets in CI:** call the API after a deploy and fail the build if `budgetPassed` is `false`.

### Features

- **Bulk:** many URLs per run, or a `sitemap.xml` (sitemap index files are followed). Duplicates are removed.
- **Mobile and desktop** with the official Lighthouse settings (Moto G Power on slow 4G, and desktop).
- **Lab metrics with ratings:** LCP, FCP, TBT, CLS, Speed Index, TTFB, each with `good` / `needs-improvement` / `poor` against Google's thresholds, plus `labCoreWebVitalsPass`.
- **All Lighthouse categories:** performance, accessibility, best practices, SEO, and (optional) Lighthouse 13's new *agentic browsing* category.
- **Top fixes:** the highest-impact opportunities per page (for example "Reduce unused JavaScript (~0.8 s)") in flat `fix1..fix3` columns plus a one-line `topFixes` summary.
- **Real-user data (CrUX), optional and free (beta):** p75 LCP, INP, CLS, FCP and TTFB for the URL, or the whole site when the URL has too little traffic, with ratings and a field Core Web Vitals pass/fail.
- **Change tracking:** compares each page with the previous run of the same monitor and adds `performanceScoreChange`, `lcpChangeMs`, `clsChange`, `tbtChangeMs`, `regressed`, `improved` and a readable `changeNote`.
- **Performance budget:** `budgetPassed` true/false per row.
- **Accurate scores:** run each URL up to 5 times and keep the median run, like Google recommends. Cloud CPU is calibrated automatically.
- **Full HTML reports** (optional): the standard Lighthouse report for every page, with a link in each row.
- **Two engines:** Lighthouse inside the Actor (no key needed, the default), or Google PageSpeed Insights with your own key (**beta**) (scores identical to pagespeed.web.dev, no quota sharing with other users).
- **Flat, CSV-friendly output:** no nested objects to untangle.

### Input example

```json
{
  "startUrls": [{ "url": "https://example.com" }, { "url": "https://www.bbc.com/news" }],
  "devices": ["mobile", "desktop"],
  "categories": ["performance", "accessibility", "best-practices", "seo"],
  "runsPerUrl": 1,
  "maxOpportunities": 3,
  "performanceBudget": 90,
  "compareWithPrevious": true,
  "monitorName": "my-site",
  "saveHtmlReport": false
}
```

### Output

One row per URL and device. A real row (BBC News, mobile, trimmed):

```json
{
  "url": "https://www.bbc.com/news",
  "device": "mobile",
  "engine": "lighthouse",
  "performanceScore": 55,
  "accessibilityScore": 95,
  "bestPracticesScore": 77,
  "seoScore": 100,
  "lcpMs": 8027, "lcpRating": "poor",
  "cls": 0.015, "clsRating": "good",
  "tbtMs": 907, "tbtRating": "poor",
  "fcpMs": 1252, "speedIndexMs": 1389, "ttfbMs": 37,
  "labCoreWebVitalsPass": false,
  "fix1": "Reduce JavaScript execution time", "fix1SavingsMs": 1000,
  "fix2": "Minimize main-thread work", "fix2SavingsMs": 900,
  "fix3": "Reduce unused JavaScript", "fix3SavingsMs": 850,
  "topFixes": "Reduce JavaScript execution time (~1.0 s); Minimize main-thread work (~0.9 s); Reduce unused JavaScript (~0.8 s)",
  "pageWeightKb": 1874, "requestCount": 106,
  "budgetPassed": false,
  "auditedAt": "2026-10-29T11:21:32.321Z"
}
```

With **Compare with the previous run** on you also get `previousPerformanceScore`, `performanceScoreChange`, `lcpChangeMs`, `clsChange`, `tbtChangeMs`, `regressed`, `improved` and a `changeNote` such as `score -36; CLS good -> poor`.

With a Google API key you also get `fieldDataSource` (`url`, `origin` or `none`), `fieldLcpP75Ms`, `fieldInpP75Ms`, `fieldClsP75`, `fieldFcpP75Ms`, `fieldTtfbP75Ms`, their ratings, `fieldCoreWebVitalsPass` and `fieldCollectionPeriod`.

A `RUN_SUMMARY` record in the key-value store has totals: pages audited, failures, average performance score, how many pages pass Core Web Vitals, and how many regressed or improved.

#### Thresholds used for ratings

| Metric | Good | Poor |
| --- | --- | --- |
| LCP (Largest Contentful Paint) | ≤ 2.5 s | > 4 s |
| INP (Interaction to Next Paint, field only) | ≤ 200 ms | > 500 ms |
| CLS (Cumulative Layout Shift) | ≤ 0.1 | > 0.25 |
| FCP (First Contentful Paint) | ≤ 1.8 s | > 3 s |
| TBT (Total Blocking Time, lab stand-in for INP) | ≤ 200 ms | > 600 ms |
| Speed Index | ≤ 3.4 s | > 5.8 s |
| TTFB (Time to First Byte) | ≤ 0.8 s | > 1.8 s |

In between is `needs-improvement`.

### Pricing

Pay per event. You only pay for audits that succeed.

| Event | Price |
| --- | --- |
| Lighthouse audit (one URL on one device, run in the Actor) | $0.02 |
| PageSpeed Insights audit (one URL on one device, with your own Google API key, beta) | $0.005 |

Real-user (CrUX) data, change tracking, budgets and HTML reports are included at no extra cost. Failed or refused pages are free. With **Runs per URL** set to 3, a page counts as 3 audits. You can cap the cost of any run with **Max total charge**; the Actor stops cleanly when it is reached.

Example: 100 pages on mobile and desktop = 200 audits = $4.00 (or $1.00 with the PageSpeed Insights engine).

### Integrations and API

- **Schedule it:** save your input as a Task with **Compare with the previous run** on, then add a daily or weekly Schedule. Each run flags pages that regressed.
- **Get notified:** add a Slack, email or webhook integration on run finish, and filter rows where `regressed` is `true` or `budgetPassed` is `false`.
- **Google Sheets, Looker Studio, Make, Zapier, n8n:** all have Apify connectors that start this Actor and read the dataset. The flat output maps straight to columns.
- **API / code:** run it synchronously and get the rows back in one request:

```bash
curl -X POST "https://api.apify.com/v2/acts/datacolada~lighthouse-core-web-vitals-auditor/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://example.com"}],"devices":["mobile","desktop"],"performanceBudget":90}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("datacolada/lighthouse-core-web-vitals-auditor").call(run_input={
    "startUrls": [{"url": "https://example.com"}],
    "devices": ["mobile", "desktop"],
    "compareWithPrevious": True,
    "monitorName": "my-site",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["url"], row["device"], row["performanceScore"], row.get("changeNote"))
```

### Tips

- **Use 8 GB of memory** (the default) when Lighthouse runs in the Actor. Lighthouse needs about 2 CPU cores for realistic numbers; with less, JavaScript-heavy pages get a worse TBT and score than on pagespeed.web.dev.
- **With a Google API key (beta), use the PageSpeed Insights engine and set memory to 1 GB.** Google's servers do the work, so the run is cheap and fast, and 5 audits run in parallel by default.
- Scores move a few points between runs on any tool. For decisions, set **Runs per URL** to 3 (median run is kept) and use **Change threshold** (default 10 points) so small noise is not flagged.
- Keep **Parallel audits** at 1 for Lighthouse in the Actor; parallel audits share CPU and lower scores.
- For a whole site, start with the sitemap and **Max URLs** of 20 to see the patterns, then audit the templates that matter (home, category, product, article).

### FAQ

**How do I get a Google API key? (2 minutes, free)** *(beta feature)* In Google Cloud Console create a project, open *APIs & Services > Library*, enable **PageSpeed Insights API** and **Chrome UX Report API**, then *Credentials > Create credentials > API key*. Paste it into **Google API key**. The key is stored as a secret input and is only sent to Google.

**What is the difference between lab and field data?** Lab data (Lighthouse) is one simulated page load on a mid-range phone or desktop: repeatable and good for debugging. Field data (CrUX) is the 75th percentile of real Chrome users over the last 28 days, and it is what Google uses for the Core Web Vitals ranking signal. This Actor gives you both in one row.

**Why does my score differ from PageSpeed Insights?** Lighthouse scores vary from run to run on every tool, and lab runs depend on the machine. The Actor calibrates CPU slowdown to its cloud machine, but heavy JavaScript pages can still score a few points lower. If you need numbers identical to pagespeed.web.dev, add a Google API key: the PageSpeed Insights engine runs the audit on Google's own servers.

**Why is INP missing from lab data?** INP needs real user interactions, so only field data has it. Total Blocking Time (TBT) is the lab metric that correlates with it.

**How does change tracking work?** With **Compare with the previous run** on, each row is compared with the last audit of the same URL and device under the same **Monitor name**. A row is `regressed` when the performance score drops by at least the threshold, or LCP, CLS or TBT moves to a worse rating. Use one monitor name per site or client.

**What is the "agentic browsing" category?** A new Lighthouse 13 category that checks how well AI agents and assistants can read and use a page. It is optional; tick it under **Categories**.

**Can it audit pages behind a login?** No. It audits public pages only.

**How long does an audit take?** Usually 6 to 25 seconds per page and device. Pages that never stop loading are cut off at the page load timeout (45 s by default).

### Limits and fair use

Only audit pages you are allowed to access. The Actor does not log in, solve captchas or bypass paywalls, and refuses private and internal network addresses. Sites with bot protection or rate limits may return an error row (not charged).

### Changelog

- 0.1.6 Google API key mode (PageSpeed Insights engine and CrUX field data) marked as beta.
- 0.1 First release: bulk mobile/desktop Lighthouse 13, ratings, top fixes, CrUX field data, PageSpeed Insights engine, change tracking, budgets, HTML reports.

# Actor input Schema

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

Required unless sitemapUrl is set. Public pages to audit. Each item must be an object with a full URL, e.g. \[{"url":"https://example.com"},{"url":"https://example.org/pricing"}]; plain strings are rejected by input validation. Each URL is audited once per device. Private and internal network addresses are refused.

## `sitemapUrl` (type: `string`):

Optional sitemap.xml URL, e.g. https://example.com/sitemap.xml. Every listed page is audited (sitemap index files are followed one level), capped by maxUrls. Use instead of or together with startUrls.

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

Upper limit on pages per run (after adding sitemap pages). Each URL is audited once per device.

## `devices` (type: `array`):

Mobile uses Lighthouse's default Moto G Power emulation with slow 4G and 4x CPU slowdown (what Google ranks on). Desktop uses Lighthouse's desktop preset. Pick both to get two rows per URL.

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

Performance is always included. Add Accessibility, Best practices, SEO, or the new Agentic Browsing category (how well AI agents can use the page: llms.txt, WebMCP, agent accessibility). Same price either way.

## `runsPerUrl` (type: `integer`):

Lighthouse scores vary from run to run. Set 3 to audit each URL/device three times and keep the median run (Google's recommended practice). Each run is charged as one audit.

## `maxOpportunities` (type: `integer`):

How many of the biggest improvement opportunities to list per page, ranked by estimated time saved.

## `performanceBudget` (type: `integer`):

Optional pass/fail threshold 0-100, e.g. 90. Each row gets budgetPassed = true when the performance score is at least this number. Leave empty for no budget.

## `compareWithPrevious` (type: `boolean`):

Compare each page with the previous run of the same monitor and flag regressions (score drop of at least the threshold below, or LCP/CLS/TBT moving to a worse rating). Schedule the Actor to turn this into a speed monitor.

## `monitorName` (type: `string`):

Baselines are kept per monitor name, so separate projects or clients do not overwrite each other.

## `scoreChangeThreshold` (type: `integer`):

Smallest performance score change that counts as a regression or improvement. Lighthouse naturally moves a few points between runs, so 10 avoids false alarms.

## `googleApiKey` (type: `string`):

Your own free Google Cloud API key. With the PageSpeed Insights API enabled, audits run on Google's servers (scores match pagespeed.web.dev). With the Chrome UX Report API enabled, you also get real-user (field) Core Web Vitals p75: LCP, INP, CLS, FCP, TTFB with pass/fail, using the URL's data or, if there is not enough, the whole site's. No extra charge. See the README for a 2-minute setup.

## `engine` (type: `string`):

With your own free Google API key the audits run on Google's PageSpeed Insights servers, so scores match pagespeed.web.dev exactly and runs are faster. Without a key, Lighthouse runs inside this Actor (same Lighthouse version, cloud CPU).

## `fieldDataLevel` (type: `string`):

Which CrUX record to use.

## `saveHtmlReport` (type: `boolean`):

Store the standard Lighthouse HTML report for each page and link it in reportUrl (open it in a browser or share it with a client).

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

1 gives the most accurate lab numbers. With Lighthouse in this run, each parallel audit needs about 8 GB of memory, otherwise audits share CPU and scores drop (capped at 3). With the PageSpeed Insights engine you can use up to 10, since Google's servers do the work. Leave empty for the default: 1 with Lighthouse, 5 with PageSpeed Insights.

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

How long Lighthouse waits for a page to load.

## `cpuCalibration` (type: `string`):

Lighthouse slows the CPU 4x for mobile, assuming a fast desktop machine. Cloud containers are slower, so raw defaults overstate TBT and LCP. Auto measures this machine's CPU (Lighthouse's own benchmarkIndex) and scales the slowdown so scores stay close to PageSpeed Insights. The multiplier used is in the output.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com"
    },
    {
      "url": "https://www.bbc.com/news"
    }
  ],
  "maxUrls": 50,
  "devices": [
    "mobile",
    "desktop"
  ],
  "categories": [
    "performance",
    "accessibility",
    "best-practices",
    "seo"
  ],
  "runsPerUrl": 1,
  "maxOpportunities": 3,
  "compareWithPrevious": false,
  "monitorName": "default",
  "scoreChangeThreshold": 10,
  "engine": "auto",
  "fieldDataLevel": "url-then-origin",
  "saveHtmlReport": false,
  "pageTimeoutSecs": 45,
  "cpuCalibration": "auto"
}
```

# Actor output Schema

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

Dataset rows: url, device, scores, lcpMs, cls, tbtMs, fcpMs, speedIndexMs, ratings, top fixes, field data, changes, error.

## `reports` (type: `string`):

Lighthouse HTML reports (when enabled) and the RUN_SUMMARY record in the default key-value store.

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

JSON with counts, average performance score, how many pages pass Core Web Vitals, and regressions.

# 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": [
        {
            "url": "https://example.com"
        },
        {
            "url": "https://www.bbc.com/news"
        }
    ],
    "devices": [
        "mobile",
        "desktop"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datacolada/lighthouse-core-web-vitals-auditor").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": [
        { "url": "https://example.com" },
        { "url": "https://www.bbc.com/news" },
    ],
    "devices": [
        "mobile",
        "desktop",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("datacolada/lighthouse-core-web-vitals-auditor").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": [
    {
      "url": "https://example.com"
    },
    {
      "url": "https://www.bbc.com/news"
    }
  ],
  "devices": [
    "mobile",
    "desktop"
  ]
}' |
apify call datacolada/lighthouse-core-web-vitals-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datacolada/lighthouse-core-web-vitals-auditor"
        }
    }
}
```

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/9drRJkWat4ZXInEgF/builds/VPy1sGh4v0BBNNzJo/openapi.json
