# Bulk PageSpeed Insights & Core Web Vitals Checker (`open-data-tools/pagespeed-bulk`) Actor

Audit hundreds of URLs, or a whole site from its sitemap, with Google PageSpeed Insights: Lighthouse scores, lab Core Web Vitals, real-user CrUX field data with pass/fail, and the top fixes per page. Mobile and desktop. Uses your own free Google API key. No start fee.

- **URL**: https://apify.com/open-data-tools/pagespeed-bulk.md
- **Developed by:** [Open Data Tools](https://apify.com/open-data-tools) (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

$1.50 / 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 PageSpeed Insights & Core Web Vitals Checker

Run Google PageSpeed Insights on hundreds of pages in one go, or on a whole website straight from its sitemap. You get one clean row per page and device with:

- **Lighthouse scores**: performance, accessibility, best practices and SEO (0-100)
- **Lab Core Web Vitals**: LCP, CLS, TBT, FCP, Speed Index, Time to Interactive, server response time, page weight and request count
- **Real-user field data** from the Chrome UX Report: LCP, INP, CLS, FCP and TTFB at the 75th percentile, plus a **PASSED / FAILED Core Web Vitals assessment** (page-level when Google has it, otherwise origin-level, and the row tells you which)
- **The top fixes per page**, ranked by estimated time saved ("Reduce unused JavaScript (~450 ms)")
- A link to open each audit on pagespeed.web.dev, and optionally the full Lighthouse JSON

Mobile, desktop or both. Export to CSV, Excel, JSON or Google Sheets, or call it from the API, Make, Zapier or n8n.

### Why this one

| | This Actor |
|---|---|
| Many URLs per run | Yes, with parallel audits and automatic retries |
| Whole site from sitemap | Yes: give a domain or sitemap URL, it finds the pages (robots.txt, sitemap indexes, .xml.gz) |
| Field data (real users) | Yes, with pass/fail and the data scope |
| Flat, spreadsheet-ready rows | Yes: every metric is its own column; fixes are also one text cell |
| Performance budget | Yes: flag pages below a score you choose |
| Start fee | None |
| Failed audits | Never charged |

### Data source

Every number comes from Google's official [PageSpeed Insights API v5](https://developers.google.com/speed/docs/insights/v5/get-started), the same engine as pagespeed.web.dev. Nothing is scraped. Google runs the Lighthouse audit on its own servers, so results are not skewed by the machine this Actor runs on.

### You need a free Google API key (2 minutes)

Google gives every key **25,000 PageSpeed audits per day for free**. Without a key the API falls back to a quota shared by everyone on the internet, which is almost always used up.

1. Open [console.cloud.google.com](https://console.cloud.google.com/) and pick or create a project.
2. Go to **APIs & Services > Library**, search **PageSpeed Insights API** and click **Enable**.
3. Go to **APIs & Services > Credentials > Create credentials > API key**. Optionally restrict the key to the PageSpeed Insights API.
4. Paste the key into the **Google PageSpeed Insights API key** field. Apify stores it encrypted.

No billing account is needed for PageSpeed Insights.

### Input

```json
{
  "urls": ["https://example.com", "https://example.com/pricing"],
  "sitemapUrls": ["example.com"],
  "maxUrlsPerSitemap": 200,
  "excludePatterns": ["/tag/", "/page/\\d+"],
  "apiKey": "YOUR_KEY",
  "strategies": ["mobile", "desktop"],
  "categories": ["performance", "seo", "accessibility", "best-practices"],
  "maxOpportunities": 5,
  "minPerformanceScore": 50
}
```

- **urls**: pages to audit. `https://` is added if you leave it out.
- **sitemapUrls**: a domain finds its sitemap through robots.txt and common paths; a sitemap URL is read directly. Use the include/exclude patterns to keep only the pages you care about (for example `/blog/`).
- **strategies**: each device is a separate audit and a separate row.
- **minPerformanceScore**: pages below it get `belowThreshold: true`. Good for weekly alerts.
- **saveFullReport**: also stores the complete Lighthouse JSON for each page.

### Output

One row per page and device:

```json
{
  "url": "https://web.dev/",
  "strategy": "desktop",
  "status": "ok",
  "performanceScore": 70,
  "accessibilityScore": 90,
  "bestPracticesScore": 96,
  "seoScore": 92,
  "lcpMs": 994,
  "fcpMs": 914,
  "tbtMs": 536,
  "cls": 0.128,
  "speedIndexMs": 1336,
  "serverResponseMs": 4,
  "totalBytes": 3758311,
  "requestCount": 96,
  "fieldDataScope": "url",
  "fieldLcpMs": 2688,
  "fieldInpMs": 71,
  "fieldCls": 0.07,
  "fieldCwvAssessment": "FAILED",
  "topOpportunities": "Minimize main-thread work (~550 ms) | Reduce JavaScript execution time (~500 ms) | Render-blocking requests (~350 ms)",
  "belowThreshold": true,
  "reportUrl": "https://pagespeed.web.dev/analysis?url=https%3A%2F%2Fweb.dev%2F&form_factor=desktop"
}
```

Pages that cannot be audited (site down, 4xx/5xx, blocked) come back as rows with `status: "error"`, an `errorCode` such as `FAILED_DOCUMENT_REQUEST` and a readable message. They are not charged.

The run's key-value store also holds a **SUMMARY** record: average scores and lab metrics per device, how many pages pass Core Web Vitals, how many are below your budget, and the 10 slowest pages.

### Pricing

Pay per event, no start fee:

| Event | Price |
|---|---|
| Page audit (one page on one device, successful) | $0.0015 |

Examples: 100 pages on mobile = $0.15. 500 pages on mobile and desktop (1,000 audits) = $1.50. Failed audits cost nothing. You can set a maximum charge per run in Apify and the Actor stops cleanly when it is reached.

### Use cases

- **SEO audits**: check every page of a client site from its sitemap and hand over a spreadsheet of the worst pages and their top fixes.
- **Core Web Vitals monitoring**: schedule a weekly run and send `belowThreshold` pages to Slack or email with an Apify integration.
- **Competitor benchmarks**: compare your key pages against competitors on mobile and desktop.
- **Before/after deploys**: run the same URL list after each release and compare scores.

### Limits and tips

- Each audit takes Google 5-30 seconds. With the default 5 parallel audits, 100 pages take about 5-8 minutes.
- Google allows about 400 requests per 100 seconds and 25,000 per day per key. The Actor backs off and retries on rate limits, and stops with a clear message if your daily quota runs out.
- Lab scores vary a few points between runs; that is how Lighthouse works. Field data is a 28-day rolling average from real Chrome users and only exists for pages and sites with enough traffic.
- The Actor uses 256 MB of memory and no browser.

### FAQ

**Is this allowed?** Yes. It calls Google's public PageSpeed Insights API with your own key, which is what the API is for.

**Why not run Lighthouse inside the Actor?** Google's servers give consistent, comparable numbers and include real-user field data. A headless browser in a shared container gives noisier scores and costs more memory.

**Can I audit pages behind a login?** No. PageSpeed Insights can only reach public pages.

Questions or a missing metric? Open an issue on the Actor's Issues tab.

# Actor input Schema

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

Pages to audit, one per line. https:// is added if missing. Duplicates are removed.

## `sitemapUrls` (type: `array`):

Optional. A domain (example.com) finds its sitemap through robots.txt; a sitemap URL (sitemap.xml, sitemap index, .xml.gz, .txt) is read directly. Page URLs found are added to the audit, up to the limit below per entry.

## `maxUrlsPerSitemap` (type: `integer`):

Stop after this many page URLs from each sitemap entry. Filters below apply first.

## `includePatterns` (type: `array`):

Keep only sitemap URLs matching at least one regular expression (case-insensitive). Example: /blog/

## `excludePatterns` (type: `array`):

Drop sitemap URLs matching any of these regular expressions. Example: /tag/

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

Your own free key: 25,000 audits per day at no cost from Google. Create it in 2 minutes at console.cloud.google.com (APIs & Services > Library > PageSpeed Insights API > Enable, then Credentials > Create credentials > API key). Without a key the Actor tries Google's shared keyless quota, which is usually exhausted. Stored encrypted.

## `strategies` (type: `array`):

Mobile, desktop or both. Each device is a separate audit (and a separate row).

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

Scores to return. Core Web Vitals lab metrics and field data come with every audit.

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

How many of the biggest performance fixes (estimated savings) to list per page. 0 turns this off.

## `minPerformanceScore` (type: `integer`):

Optional performance budget (0-100). Pages below it get belowThreshold = true, so you can filter or alert on them. 0 turns it off.

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

Optional locale for audit titles, such as en, de, fr, es, pt-BR. Default English.

## `saveFullReport` (type: `boolean`):

Also store each page's complete Lighthouse report in the run's key-value store and link it in fullReportUrl.

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

Audits run at the same time. Google allows about 4 requests per second per key; each audit takes 5-30 s, so 5-10 is safe.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "https://web.dev"
  ],
  "maxUrlsPerSitemap": 100,
  "strategies": [
    "mobile"
  ],
  "categories": [
    "performance",
    "accessibility",
    "best-practices",
    "seo"
  ],
  "maxOpportunities": 5,
  "minPerformanceScore": 0,
  "saveFullReport": false,
  "concurrency": 5
}
```

# Actor output Schema

## `audits` (type: `string`):

One row per page and device with scores, Core Web Vitals and top fixes.

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

Averages per device, Core Web Vitals pass count and the 10 slowest pages.

# 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",
        "https://web.dev"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("open-data-tools/pagespeed-bulk").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",
        "https://web.dev",
    ] }

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

```

## MCP server setup

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

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/VJEKMCDbkByUPx41F/builds/MMIsAqbSpA6bv4lsv/openapi.json
