Dev.to WebDev 🛠 Dev 👁 0 📖 2 min read

Bulk Core Web Vitals with the free PageSpeed Insights API (and a small hosted option)

Core Web Vitals are easiest to fix when you look at many URLs at once. Google’s PageSpeed Insights (PSI) API v5 is free with your own API key and returns lab Lighthouse scores plus real-user CrUX field data in one call.

Core Web Vitals are easiest to fix when you look at many URLs at once. Google’s PageSpeed Insights (PSI) API v5 is free with your own API key and returns lab Lighthouse scores plus real-user CrUX field data in one call.

1. Get a free Google API key

In Google Cloud, enable “PageSpeed Insights API”, create an API key, and check the Quotas page for your daily limit.

2. One URL, one call

curl "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://example.com&strategy=mobile&category=performance&key=YOUR_KEY"

Useful JSON paths:

  • Lab: lighthouseResult.audits (largest-contentful-paint, cumulative-layout-shift, total-blocking-time)
  • Field (when enough traffic): loadingExperience.metrics; else originLoadingExperience

3. Bulk loop (keep it polite)

import csv, json, time, urllib.parse, urllib.request

KEY = "YOUR_KEY"
URLS = ["https://example.com/", "https://example.com/pricing"]

def psi(url, strategy="mobile"):
    q = urllib.parse.urlencode({
        "url": url, "strategy": strategy,
        "category": "performance", "key": KEY,
    })
    with urllib.request.urlopen(
        "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?" + q,
        timeout=90,
    ) as r:
        return json.load(r)

rows = []
for u in URLS:
    data = psi(u)
    audits = data["lighthouseResult"]["audits"]
    rows.append({
        "url": u,
        "perf": data["lighthouseResult"]["categories"]["performance"]["score"],
        "lcp_ms": audits["largest-contentful-paint"]["numericValue"],
        "cls": audits["cumulative-layout-shift"]["numericValue"],
        "tbt_ms": audits["total-blocking-time"]["numericValue"],
        "fetched_at": data.get("analysisUTCTimestamp"),
    })
    time.sleep(0.5)  # stay under quota; back off on HTTP 429

with open("cwv.csv", "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=rows[0].keys())
    w.writeheader(); w.writerows(rows)
print(len(rows), "rows → cwv.csv")

Start from failing field metrics, then use lab audits to find the cause. Re-run after fixes; lab scores move between runs.

Hosted option (optional)

I built a small Apify Actor that runs the same PSI calls in bulk from a URL list, a sitemap or a domain, and exports CSV/JSON. You still bring your own free Google key. Disclosure: I am the creator.

https://apify.com/innovative_cookie/pagespeed-bulk

No Actor fee for now — only Apify platform usage (Free plan includes monthly credit).

Written with AI assistance.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.