PageSpeed
PageSpeed
Run an official Google PageSpeed Insights audit on every prospect's website. The output ranks the list by site quality, exposes the weakest performers, and surfaces an angle worth pitching: a slow or broken site is a concrete improvement to offer.
The module never crawls a site directly. It delegates the measurement to Google, which keeps the signal comparable across prospects.
Inputs
The job accepts an array of POI dictionaries. The only field actually used is site_web; any other field is carried through to the output unchanged.
| Field | Type | Required | Notes |
|---|---|---|---|
items |
list[dict] |
yes | 1 to 10,000 POIs. Rows without site_web are kept and marked. |
source_job_id |
string |
no | UUID of the upstream job (typically a Google Maps scrap). |
{
"nom": "Studio Exemple",
"adresse": "1 rue de l'Exemple, 00000 Exempleville",
"site_web": "https://example.com"
}
Outputs
One row per input row, with the original columns kept. Empty cells mean the URL could not be scored (see Errors). The test runs with the mobile profile.
| Column | Type | Description |
|---|---|---|
tested_url, strategy, fetch_time |
string | URL tested, profile used (mobile) and time of the test. |
perf_score |
int 0-100 | Lighthouse performance score. |
seo_score |
int 0-100 | Lighthouse SEO score. |
a11y_score |
int 0-100 | Lighthouse accessibility score. |
best_practices_score |
int 0-100 | Lighthouse best-practices score. |
perf_verdict |
string | À refondre below 50, À améliorer below 90, OK otherwise. |
lcp_ms, fcp_ms, tti_ms, tbt_ms, speed_index_ms, ttfb_lab_ms |
int | Lab timings in milliseconds. Good LCP is under 2500. |
cls |
float | Cumulative Layout Shift. Good is under 0.1. |
crux_overall, crux_lcp_p75_ms, crux_fcp_p75_ms, crux_cls_p75, crux_inp_p75_ms |
mixed | Field data from real Chrome users for this URL, when Google has enough traffic. INP only exists here. |
origin_crux_overall, origin_crux_lcp_p75_ms |
mixed | Same field data for the whole site. |
top_opportunity_1, top_opportunity_2, top_opportunity_3 |
string | The three failing audits with the largest estimated saving, ready to quote in a message. |
error |
string | Why the row could not be scored, if applicable. |
The file also carries page weight (total_byte_weight_kb, weight_*_kb), estimated savings (savings_*), technical flags (uses_*, has_*), HTTP and security headers, cookies, TLS certificate, meta tags and DOM counts, DNS records (MX, SPF, DMARC), a security grade (mozilla_grade, mozilla_score) and the presence of robots.txt and sitemap.xml. The registry lists accessibility_score, lcp and inp under produces: these are signal names for a11y_score, lcp_ms and crux_inp_p75_ms.
Lifecycle
Standard outsend job lifecycle; see /docs/concepts/jobs-lifecycle. Progress is reported in sites; result count in audits.
Pipeline
needs: site_web
produces: perf_score, accessibility_score, seo_score,
best_practices_score, lcp, cls, inp
PageSpeed is a check module: it consumes a list and returns the same list enriched. Typical pattern: start from a scrap job, then run pagespeed against the resulting POIs.
Endpoints
Create a job
POST /api/jobs/pagespeed
Content-Type: application/json
{
"items": [
{ "nom": "Studio Exemple", "site_web": "https://example.com" }
],
"source_job_id": "8b1f...-uuid"
}
Response: a JobPublic envelope carrying the job UUID, its status, and the EF cost reserved for tracking.
Read a job
GET /api/jobs/{job_id}
GET /api/jobs/{job_id}/results
GET /api/jobs/{job_id}/export.csv
The CSV export is available once the job is completed.
Limits
See /docs/concepts/limits. Upstream is the Google PSI v5 free tier (one URL per request); bursts above the per-key quota are retried inside the job rather than failed.
Errors
| Condition | Behaviour |
|---|---|
POI has no site_web |
Row kept, audit columns empty, error set to URL absente ou invalide. |
| URL unreachable or returns a non-HTML page | Row kept, scores empty, error noted on the row. |
| PSI quota exhausted | Affected URLs are re-queued inside the job; if the quota stays exhausted the row is marked failed and the rest continues. |
| Site blocks the PSI fetcher | Row marked failed with the upstream error code; the job itself stays healthy. |
items empty |
400 Bad Request, no job created. |
Missing PAGESPEED_API_KEY server-side |
Job created but moves straight to failed. |
A failed row never blocks the job: the contract is "every input POI gets one output row, scored or explained".
What's next
techstack: detect the CMS, analytics, and frameworks behind each site. A weak PageSpeed score combined with a known-slow stack is a sharper angle than either signal alone.ads_intelligence: check whether the prospect is actively spending on ads. Paying for traffic that lands on a slow page is the highest-conviction pitch this module enables.