Page Speed

Issue a single GET against a URL from a server-side probe and return the wire-level speed metrics: time-to-first-byte, total response size, whether compression is in play, the HTTP version that was negotiated, and a count of response headers.

It's not a synthetic Lighthouse run — there's no rendering, no Core Web Vitals, no JavaScript execution. What you get is a fast, cheap signal you can call thousands of times per day to spot regressions, flag uncompressed responses, or confirm that HTTP/2/3 actually rolled out on your CDN.

For on-page SEO signals see /v1/seo/audit. For broken-link checks see /v1/seo/broken-links.

Endpoint

GET /v1/seo/pagespeed

Base URL: https://seo.toolkitapi.io

Query Parameters

Field Type Required Description
url string Yes Absolute URL to test. Must be http:// or https://.

Response Fields

Field Type Description
url string Final URL after redirects.
status_code integer HTTP status from the final response.
ttfb_ms number End-to-end time from start of request to fully-received body, in milliseconds, rounded to 2 dp.
total_size_bytes integer Length of the response body as received (after decompression by the HTTP client).
content_encoding string | null Raw Content-Encoding response header, or null if absent.
is_compressed boolean true if content_encoding is one of gzip, br, deflate, zstd.
http_version string | null Negotiated HTTP version (e.g. "HTTP/1.1", "HTTP/2").
headers_count integer Number of headers on the final response.

About ttfb_ms: despite the name, this is wall-clock time for the whole GET (connect + TLS + first byte + body). It's labelled TTFB for backwards compatibility with the schema; treat it as "total fetch time". The probe follows redirects with a 15 s timeout.

Examples

curl

curl -G "https://seo.toolkitapi.io/v1/seo/pagespeed" \
  -H "x-api-key: $TOOLKIT_API_KEY" \
  --data-urlencode "url=https://example.com"

Python

import requests

resp = requests.get(
    "https://seo.toolkitapi.io/v1/seo/pagespeed",
    params={"url": "https://example.com"},
    headers={"x-api-key": API_KEY},
    timeout=30,
)
data = resp.json()

print(f"{data['url']} → {data['status_code']} "
      f"in {data['ttfb_ms']} ms over {data['http_version']}")
print(f"  size: {data['total_size_bytes']/1024:.1f} KB, "
      f"compressed: {data['is_compressed']} ({data['content_encoding']})")

if not data["is_compressed"]:
    print("  ⚠️  No compression on the wire — check your CDN config")
if data["http_version"] == "HTTP/1.1":
    print("  ⚠️  Still on HTTP/1.1 — consider HTTP/2 or HTTP/3")

JavaScript

const url = new URL("https://seo.toolkitapi.io/v1/seo/pagespeed");
url.searchParams.set("url", "https://example.com");

const resp = await fetch(url, {
  headers: { "x-api-key": process.env.TOOLKIT_API_KEY },
});
const data = await resp.json();

console.log(
  `${data.url} → ${data.status_code} in ${data.ttfb_ms} ms over ${data.http_version}`,
);

if (data.ttfb_ms > 800) console.warn("Slow response");
if (!data.is_compressed) console.warn("Uncompressed response");

Example Response

{
  "url": "https://example.com/",
  "status_code": 200,
  "ttfb_ms": 184.42,
  "total_size_bytes": 14823,
  "content_encoding": "gzip",
  "is_compressed": true,
  "http_version": "HTTP/2",
  "headers_count": 18
}

Error Responses

Status Reason
400 URL failed validation (not absolute, bad scheme, or SSRF-blocked host).
502 Generic network/TLS/connection error reaching the target.
504 The target took longer than the 15-second probe timeout.

Notes

  • Single sample, not a benchmark. TTFB varies; for stable numbers run multiple samples and take a median yourself.
  • total_size_bytes is post-decompression. If the server returned 4 KB gzip that decoded to 14 KB, you'll see 14823, not 4096. Use it as a "rendered HTML weight" signal, not a "bytes on the wire" metric.
  • No assets are fetched. Only the document at url itself is requested — no images, JS, CSS, or fonts. This is intentional, to keep the probe light.
  • HTTP/3 / QUIC support depends on the upstream client; you'll typically see HTTP/2 even when curl reports HTTP/3 against the same origin.
  • The probe sends a fixed User-Agent: WebScrapingToolkit/1.0 (+https://devtoolkit.api) — some origins serve different responses based on UA.
  • Each call goes through the same SSRF guard as /v1/seo/audit; private/loopback hosts are rejected with 400.