# Bulk PageSpeed Insights Checker — Core Web Vitals, SEO & Fixes (`wowlab/pagespeed-bulk-checker`) Actor

Run Google PageSpeed Insights (Lighthouse) on hundreds of URLs: Performance, Accessibility, Best Practices & SEO scores, lab metrics, real-user Core Web Vitals (CrUX) with PASSED/FAILED verdict and top fixes. Mobile/desktop. No API key needed.

- **URL**: https://apify.com/wowlab/pagespeed-bulk-checker.md
- **Developed by:** [Erwinbooze Ricardo](https://apify.com/wowlab) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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 PageSpeed Insights Checker — Core Web Vitals, SEO & Fixes

**Bulk PageSpeed Insights Checker** runs Google PageSpeed Insights (Lighthouse) on **hundreds of URLs in one run** and gives you one clean row per page: **Performance, Accessibility, Best Practices and SEO scores**, lab speed metrics (LCP, CLS, TBT, FCP, TTFB, Speed Index), **real-user Core Web Vitals from the Chrome UX Report (CrUX)** with a simple **PASSED / FAILED** verdict, and a short **list of the biggest fixes** with estimated time savings.

No coding, **no Google API key needed** (a built-in key is included; you can add your own), no browser to babysit. Export to CSV, Excel, JSON or Google Sheets, schedule it weekly, or call it from an AI agent.

### Why this PageSpeed checker?

- ✅ **Bulk** — paste 5 or 5,000 URLs (or bare domains); duplicates removed, invalid lines skipped.
- ✅ **Mobile, desktop or both** — `both` gives two rows per URL so you can compare.
- ✅ **All four Lighthouse scores** (0–100): Performance, Accessibility, Best Practices, SEO.
- ✅ **Real-user Core Web Vitals (CrUX)** — p75 LCP, CLS, INP, FCP, TTFB for the page *and* its whole origin, plus a `coreWebVitals` verdict (`PASSED`, `FAILED`, `INSUFFICIENT_DATA`, `NO_DATA`) using Google's thresholds (LCP ≤ 2.5 s, CLS ≤ 0.1, INP ≤ 200 ms).
- ✅ **Top opportunities, not a 2 MB report** — e.g. *Improve image delivery — Est savings of 35 KiB*, *Reduce unused JavaScript — 450 ms*, sorted by impact.
- ✅ **Failed URLs are free** — unreachable or blocked pages are listed in `RUN_SUMMARY` and are **not charged**.
- ✅ **Safe defaults** — gentle concurrency, automatic retries on Google rate limits / 5xx, a `maxUrls` cap and respect for your max-charge limit.
- ✅ **AI-agent ready** — simple input, flat JSON output; works through the **Apify MCP server** in Claude, ChatGPT, Cursor and other agents.

### Use cases

- **SEO agencies** — audit every client site (or every page of one site) in a single run and send a report.
- **Monitor Core Web Vitals** — schedule a weekly run and get alerted when a page drops from PASSED to FAILED.
- **Competitor benchmarking** — compare your speed and SEO scores with competitors, mobile vs desktop.
- **Lead generation** — find slow websites in a niche and pitch speed optimisation.
- **Accessibility checks** — quick Lighthouse accessibility score across many pages.
- **Developers & QA** — check pages after a release without opening PageSpeed Insights one URL at a time.

### Input

| Field | What it does | Default |
|---|---|---|
| `urls` | Pages or domains to check (required) | — |
| `strategy` | `mobile`, `desktop` or `both` | `mobile` |
| `categories` | Any of `performance`, `accessibility`, `best-practices`, `seo` | all four |
| `includeFieldData` | Real-user CrUX Core Web Vitals | `true` |
| `includeOpportunities` | Top fixes with estimated savings | `true` |
| `maxOpportunities` | Fixes kept per row | `8` |
| `maxUrls` | Safety cap per run | `50` |
| `maxConcurrency` | Audits in parallel (1–8) | `2` |
| `apiKey` | Optional own Google API key (stored encrypted) | built-in key |
| `locale` | Language of fix titles, e.g. `de`, `fr`, `ja` | `en` |
| `outputFailedUrls` | Also save failed URLs as rows (billed) | `false` |

```json
{
  "urls": ["https://example.com", "apify.com", "https://www.wikipedia.org"],
  "strategy": "both",
  "categories": ["performance", "seo", "accessibility", "best-practices"]
}
```

### Output

One dataset item per **URL × device**:

```json
{
  "url": "https://example.com/",
  "finalUrl": "https://example.com/",
  "strategy": "mobile",
  "fetchTime": "2026-10-30T13:47:45.462Z",
  "performanceScore": 100,
  "accessibilityScore": 96,
  "bestPracticesScore": 100,
  "seoScore": 80,
  "lcpMs": 754, "cls": 0, "inpMs": null, "tbtMs": 0, "fcpMs": 754, "ttfbMs": 1, "speedIndexMs": 754,
  "pageWeightKb": 2,
  "coreWebVitals": "PASSED",
  "fieldData": { "scope": "url", "lcpP75Ms": 1189, "clsP75": 0, "inpP75Ms": 83, "fcpP75Ms": 1022, "ttfbP75Ms": 690, "overallCategory": "FAST", "coreWebVitals": "PASSED" },
  "originFieldData": { "lcpP75Ms": 1189, "clsP75": 0, "inpP75Ms": 83, "coreWebVitals": "PASSED" },
  "opportunities": [
    { "id": "cache-insight", "title": "Use efficient cache lifetimes", "displayValue": "Est savings of 2 KiB", "score": 0.5, "overallSavingsMs": 0 }
  ],
  "reportUrl": "https://pagespeed.web.dev/analysis?url=https%3A%2F%2Fexample.com%2F&form_factor=mobile",
  "error": null
}
```

**Units:** all `...Ms` fields are milliseconds; `cls` / `clsP75` are unitless; scores are 0–100. Lab metrics come from a simulated Lighthouse load. **INP can only be measured on real users**, so `inpMs` (lab) is always `null` — use `tbtMs` as the lab proxy and `fieldData.inpP75Ms` for the real value. Pages with little traffic may have no URL-level CrUX data; then `fieldData.scope` is `origin` or `fieldData` is `null`.

A `RUN_SUMMARY` record in the key-value store lists counts, skipped invalid URLs and failed URLs with the error from Google.

### Pricing

Pay per result: **$0.003 per URL × device** checked successfully, plus Apify's tiny per-run start fee. 1,000 mobile checks ≈ $3. Failed URLs are not charged (unless you turn on `outputFailedUrls`).

### Tips & limits

- Each audit takes ~10–40 s on Google's side; 100 URLs at concurrency 2 take roughly 15–25 minutes.
- Google needs to reach the page from the public internet: pages behind logins, firewalls or bot protection fail with `FAILED_DOCUMENT_REQUEST` (free).
- Scores vary a few points between runs — that's normal Lighthouse variance.
- For very large or frequent jobs, add your own free Google API key (Google Cloud → enable *PageSpeed Insights API* → Credentials → API key) to get your own daily quota.

### FAQ

**Is this the official Google PageSpeed Insights?** It uses Google's public PageSpeed Insights API v5, so scores match pagespeed.web.dev. This Actor is not affiliated with Google.

**Do I need an API key?** No. Optionally bring your own for higher volume.

**Can I check a whole website?** Paste the list of page URLs (e.g. from your sitemap).

# Actor input Schema

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

Pages to audit (one per line). Bare domains like example.com get https:// added. Duplicates are removed.

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

Run Lighthouse as a mobile or desktop device. "both" gives two result rows per URL (mobile + desktop).

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

Which scores to compute. Fewer categories = slightly faster audits.

## `includeFieldData` (type: `boolean`):

Add Chrome UX Report field data (p75 LCP, CLS, INP, FCP, TTFB) for the URL and its origin, plus a PASSED/FAILED Core Web Vitals verdict. Low-traffic sites may have no field data.

## `includeOpportunities` (type: `boolean`):

Add a short list of the biggest performance problems (title, estimated savings in ms / bytes) instead of the full Lighthouse report.

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

How many opportunities to keep per URL, biggest savings first.

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

Safety cap on how many URLs are checked in one run (each URL × device = one billed result).

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

How many audits run at once. Each audit takes ~10–40 s on Google's side.

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

Optional. A free Google Cloud API key with the PageSpeed Insights API enabled. If empty, the Actor's built-in key is used. Stored encrypted.

## `locale` (type: `string`):

Locale for opportunity titles, e.g. en, de, fr, ja. Default: en.

## `outputFailedUrls` (type: `boolean`):

By default URLs that fail (unreachable, blocked, timeout) are only listed in the RUN_SUMMARY record and NOT charged. Turn on to also get them as dataset rows with an error field (these rows are billed like normal results).

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://www.wikipedia.org"
  ],
  "strategy": "mobile",
  "categories": [
    "performance",
    "accessibility",
    "best-practices",
    "seo"
  ],
  "includeFieldData": true,
  "includeOpportunities": true,
  "maxOpportunities": 8,
  "maxUrls": 50,
  "maxConcurrency": 2,
  "outputFailedUrls": false
}
```

# Actor output Schema

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

One row per URL × device: Lighthouse scores (0-100), lab metrics, real-user CrUX Core Web Vitals and top opportunities.

## `runSummary` (type: `string`):

Counts, skipped invalid URLs and failed URLs with error messages (failed URLs are not charged).

# 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",
        "https://www.wikipedia.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wowlab/pagespeed-bulk-checker").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",
        "https://www.wikipedia.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("wowlab/pagespeed-bulk-checker").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",
    "https://www.wikipedia.org"
  ]
}' |
apify call wowlab/pagespeed-bulk-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,wowlab/pagespeed-bulk-checker"
        }
    }
}
```

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/B4dNdlUTMo96fDLYK/builds/zgCle7bJFYBaKwXIa/openapi.json
