# PageSpeed Insights v5 + CrUX API Reference ## Table of Contents 1. [PageSpeed Insights v5](#pagespeed-insights-v5) 2. [CrUX API (Daily)](#crux-api-daily) 3. [CrUX History API (Weekly)](#crux-history-api-weekly) 4. [Core Web Vitals Thresholds](#core-web-vitals-thresholds) --- ## PageSpeed Insights v5 **Endpoint:** `GET https://www.googleapis.com/pagespeedonline/v5/runPagespeed` ### Parameters | Param | Type | Description | |-------|------|-------------| | `url` | string | Required. URL to analyze. | | `category` | string | `ACCESSIBILITY`, `BEST_PRACTICES`, `PERFORMANCE`, `SEO`. Can specify multiple. | | `strategy` | string | `DESKTOP` or `MOBILE` (default). | | `locale` | string | Locale for text (e.g., `en`). | | `key` | string | API key. Optional but recommended for quota. | ### Response Structure ``` { "id": "https://example.com/", "loadingExperience": { ... }, // URL-level CrUX data "originLoadingExperience": { ... }, // Origin-level CrUX data "lighthouseResult": { "categories": { "performance": { "score": 0.85 }, "accessibility": { "score": 0.92 }, "best-practices": { "score": 0.88 }, "seo": { "score": 0.95 } }, "audits": { ... } // Individual audit results }, "analysisUTCTimestamp": "2026-03-27T..." } ``` ### Field Data Metrics (in loadingExperience) | PSI Key | CrUX Metric | Unit | |---------|-------------|------| | `LARGEST_CONTENTFUL_PAINT_MS` | LCP | ms | | `INTERACTION_TO_NEXT_PAINT` | INP | ms | | `CUMULATIVE_LAYOUT_SHIFT_SCORE` | CLS | unitless | | `FIRST_CONTENTFUL_PAINT_MS` | FCP | ms | | `EXPERIMENTAL_TIME_TO_FIRST_BYTE` | TTFB | ms | Each metric contains: `percentile` (p75), `distributions[]` ({min, max, proportion}), `category` (FAST/AVERAGE/SLOW/NONE). ### Key Lighthouse Audit IDs `first-contentful-paint`, `largest-contentful-paint`, `total-blocking-time`, `cumulative-layout-shift`, `speed-index`, `interactive` ### Rate Limits - 25,000 QPD with API key - 240 QPM - Free, no billing required ### Note on Field Data Migration Google is migrating CrUX field data out of PSI. For field data, prefer the CrUX API directly. Use PSI primarily for Lighthouse lab data. --- ## CrUX API (Daily) **Endpoint:** `POST https://chromeuxreport.googleapis.com/v1/records:queryRecord` Send the API key in the `X-Goog-Api-Key` header, not in the URL. ### Request ```json { "origin": "https://example.com", "formFactor": "PHONE", "metrics": ["largest_contentful_paint", "interaction_to_next_paint", "cumulative_layout_shift"] } ``` | Field | Description | |-------|-------------| | `origin` | Origin URL (mutually exclusive with `url`) | | `url` | Specific page URL (mutually exclusive with `origin`) | | `formFactor` | `DESKTOP`, `PHONE`, `TABLET` (optional, omit for all) | | `metrics` | Array of metric names (optional, omit for all) | ### Available Metrics | Metric | Type | Notes | |--------|------|-------| | `largest_contentful_paint` | int (ms) | Core Web Vital | | `largest_contentful_paint_resource_type` | fractions | LCP resource type, added January 2025 | | `largest_contentful_paint_image_time_to_first_byte` | int (ms) | LCP image subpart, added January 2025 | | `largest_contentful_paint_image_resource_load_delay` | int (ms) | LCP image subpart, added January 2025 | | `largest_contentful_paint_image_resource_load_duration` | int (ms) | LCP image subpart, added January 2025 | | `largest_contentful_paint_image_element_render_delay` | int (ms) | LCP image subpart, added January 2025 | | `interaction_to_next_paint` | int (ms) | Core Web Vital (replaced FID) | | `cumulative_layout_shift` | **string** | Core Web Vital. **String-encoded!** Parse carefully. | | `first_contentful_paint` | int (ms) | | | `experimental_time_to_first_byte` | int (ms) | | | `round_trip_time` | int (ms) | Replaced effectiveConnectionType (Feb 2025) | | `navigation_types` | fractions | navigate, navigate_cache, reload, etc. | | `form_factors` | fractions | desktop/phone/tablet distribution | ### Response ```json { "record": { "key": { "origin": "https://example.com" }, "metrics": { "largest_contentful_paint": { "histogram": [ { "start": 0, "end": 2500, "density": 0.72 }, { "start": 2500, "end": 4000, "density": 0.18 }, { "start": 4000, "density": 0.10 } ], "percentiles": { "p75": 2100 } }, "cumulative_layout_shift": { "percentiles": { "p75": "0.05" } } }, "collectionPeriod": { "firstDate": { "year": 2026, "month": 2, "day": 27 }, "lastDate": { "year": 2026, "month": 3, "day": 26 } } } } ``` ### Important - **CLS p75 is a string** (e.g., `"0.05"` not `0.05`). Always parse as float from string. - Last histogram bin has **no `end`** (extends to infinity). - Densities sum to approximately 1.0. - **404** = no data (insufficient Chrome traffic). Not an auth error. - Updated daily ~04:00 UTC with ~2 day lag. ### Rate Limits - 150 QPM shared between CrUX and CrUX History APIs - Free, no paid increase available --- ## CrUX History API (Weekly) **Endpoint:** `POST https://chromeuxreport.googleapis.com/v1/records:queryHistoryRecord` Send the API key in the `X-Goog-Api-Key` header, not in the URL. Same request format as CrUX API. Returns up to **25 weekly collection periods**. ### Response Differences from CrUX API Instead of single values, returns timeseries: ```json { "record": { "metrics": { "largest_contentful_paint": { "histogramTimeseries": [ { "start": 0, "end": 2500, "densities": [0.70, 0.71, 0.72, ...] }, { "start": 2500, "end": 4000, "densities": [0.19, 0.18, 0.18, ...] }, { "start": 4000, "densities": [0.11, 0.11, 0.10, ...] } ], "percentilesTimeseries": { "p75s": [2200, 2150, 2100, ...] } } }, "collectionPeriods": [ { "firstDate": { "year": 2025, "month": 9, "day": 29 }, "lastDate": { "year": 2025, "month": 10, "day": 26 } }, ... ] } } ``` ### NaN Handling - `"NaN"` string for densities in ineligible periods - `null` for percentile values in ineligible periods - Always check for these before numeric operations ### Update Schedule - Updated **Mondays** ~04:00 UTC - Each period = 28-day rolling average ending on a Sunday --- ## Core Web Vitals Thresholds Current as of 2026-07-09; no threshold changes were announced. INP replaced FID on March 12, 2024. | Metric | Good | Needs Improvement | Poor | |--------|------|-------------------|------| | **LCP** | ≤ 2,500ms | 2,500–4,000ms | > 4,000ms | | **INP** | ≤ 200ms | 200–500ms | > 500ms | | **CLS** | ≤ 0.1 | 0.1–0.25 | > 0.25 | | **FCP** | ≤ 1,800ms | 1,800–3,000ms | > 3,000ms | | **TTFB** | ≤ 800ms | 800–1,800ms | > 1,800ms | FID was removed from Chrome's field-data tools (CrUX, PSI) on September 9, 2024. Never reference FID in outputs.