semust logo

API Platform

On-Page API

Check one page the way Google and a browser see it — Lighthouse scores and Core Web Vitals, an on-page SEO audit, or its main content as text and Markdown — at a flat price per request.

Check a single page. One endpoint serves three reports, selected with the type parameter: a full Lighthouse run (performance, accessibility, best practices and SEO scores, Core Web Vitals and every failed check), a fast on-page SEO audit (title, description, headings, content, links, size, load time and the problems found), and the page's main content as structured sections and Markdown.

Requests longer than 60 seconds

This endpoint always runs requests as tasks. A request that runs longer than 60 seconds — a Lighthouse run on a slow page can — returns 202 with a task_id; collect the result from GET /v1/tasks/{task_id}. Every response, including a normal 200, carries the task id in the X-Task-Id header. Use ?wait= to change how long the request waits, and an Idempotency-Key header to retry safely.

Authentication

HeaderTypeDescription
SEMUST-API-USERstringYour API user's username
SEMUST-API-PASSWORDstringYour API user's password
Accept-LanguagestringOptional. Send tr to receive error messages in Turkish

Create API credentials from the API Access page.

SEMUST-API-USER: your_username
SEMUST-API-PASSWORD: your_password
Content-Type: application/json

Report Types

typeReturnsTypical timePrice
lighthouse (default)Lighthouse category scores, Core Web Vitals and the failed checks, mobile or desktop10–30 s$0.0055
auditOn-page SEO audit: title, description, headings, word count, links, size, load time and the problems found~1 s (with JavaScript ~3 s)$0.000165 (with JavaScript $0.00165)
contentThe page's main content as sections (heading + text), contact details found, and optionally the whole page as Markdown~1 s$0.000165

The price is per request and does not depend on the device, the categories or Markdown. A page that cannot be checked — blocked, missing or unreachable — returns an error and is not charged (see Errors).

{
  "type": "lighthouse",
  "url": "https://www.python.org/",
  "device": "mobile"
}

Request Parameters

A parameter that does not apply to the chosen type is rejected rather than ignored, and a misspelled one is named in the error with a suggestion. A JSON null is treated as "not sent".

Body

typestringdefault: lighthouse

lighthouse, audit or content.

urlstring

Required. The page to check: an http or https address on a domain name, up to 2048 characters. Without a scheme, https:// is assumed. localhost, IP addresses and other schemes are rejected (INVALID_URL). Redirects are followed and the final address is returned.

devicestringdefault: mobile

lighthouse only. mobile (a mid-range phone on a throttled connection, as PageSpeed Insights tests) or desktop.

categoriesstring[]

lighthouse only. Any of performance, accessibility, best_practices, seo; all four by default. The price is the same; asking for fewer only shortens the response. metrics is returned only with performance.

languagestringdefault: en

lighthouse only. The language of audit titles, descriptions and display values, e.g. tr. GET /v1/on-page/languages lists the supported languages.

javascriptbooleandefault: false

audit only. Render the page in a browser with JavaScript before auditing it, for pages that build their content client-side. Ten times the price.

markdownbooleandefault: false

content only. Also return the whole page as Markdown in data.markdown. Same price.

idempotency_keystring

Optional, up to 128 characters. Repeating a request with the same key returns the same task — its 202 while it runs, its stored result once it finishes — and it is charged once. The key is reserved until 72 hours after the task finishes. Same as the Idempotency-Key header; if you send both, this field wins.

Query

waitintegerdefault: 60

Seconds to wait for the result, 0–80. If the request is still running after that, the response is 202 with a task_id. 0 answers 202 at once.

Headers

Idempotency-Keystring

Optional. Works like idempotency_key above; if you send both, the body field wins.

GET /v1/on-page/languages lists the languages Lighthouse can write its results in. It is free.

A request still running after 60 seconds returns 202. The call() helper on Tasks & Long-Running Requests polls until the result is ready.

curl -X POST https://data.semust.com/v1/on-page \
  -H "SEMUST-API-USER: your_username" \
  -H "SEMUST-API-PASSWORD: your_password" \
  -H "Content-Type: application/json" \
  -d '{"type": "lighthouse", "url": "https://www.python.org/", "device": "mobile"}'

Response

Every report returns the request as it ran — type, the normalized url and the options that apply to the type — and the result in one data object.

lighthouse scores are 0–100, as PageSpeed Insights shows them; a category you did not ask for is null. metrics are lab measurements from this run. failed_audits lists every scored check that did not pass, grouped by category in report order and, within a category, the biggest estimated saving first. Titles and descriptions are in language. Lab results vary a little from run to run, as in any Lighthouse tool.

audit returns what the page itself says about its SEO, and issues names the problems found (see the list below); an empty list means none.

content returns the page's main content in sections and everything outside it — navigation, sidebars, related blocks — in secondary_sections.

The examples below are real responses (the Lighthouse one was run with "language": "tr"; descriptions are shortened).

{
  "success": true,
  "type": "lighthouse",
  "url": "https://www.python.org/",
  "device": "desktop",
  "categories": ["performance", "accessibility", "best_practices", "seo"],
  "language": "tr",
  "data": {
    "final_url": "https://www.python.org/",
    "lighthouse_version": "13.4.0",
    "fetched_at": "2026-11-07T03:08:11Z",
    "scores": { "performance": 94, "accessibility": 79, "best_practices": 100, "seo": 92 },
    "metrics": {
      "first_contentful_paint_ms": 641,
      "largest_contentful_paint_ms": 1085,
      "total_blocking_time_ms": 0,
      "cumulative_layout_shift": 0.122,
      "speed_index_ms": 641,
      "time_to_interactive_ms": 1085
    },
    "failed_audits": [
      {
        "id": "render-blocking-insight",
        "category": "performance",
        "title": "Oluşturma engelleme istekleri",
        "description": "İstekler sayfanın ilk oluşturma işlemini engelliyor…",
        "score": 0,
        "display_value": "Tahmini tasarruf: 370 ms.",
        "savings_ms": 350,
        "savings_bytes": null
      },
      {
        "id": "unused-css-rules",
        "category": "performance",
        "title": "Kullanılmayan CSS'yi azaltın",
        "description": "Ağ etkinliğinin kullandığı bayt sayısını azaltmak üzere…",
        "score": 0,
        "display_value": "Tahmini tasarruf: 125 KiB",
        "savings_ms": 120,
        "savings_bytes": 128464
      },
      {
        "id": "color-contrast",
        "category": "accessibility",
        "title": "Arka plan ve ön plan renkleri yeterli kontrast oranına sahip değil.",
        "description": "Birçok kullanıcı, düşük kontrastlı metni okumakta zorlanır…",
        "score": 0,
        "display_value": null,
        "savings_ms": null,
        "savings_bytes": null
      }
    ],
    "passed_count": 53,
    "failed_count": 18,
    "warnings": []
  },
  "cost": 0.0055,
  "cached": false,
  "request_id": "0b7e6f1a-3c2d-4e5f-9a8b-1c2d3e4f5a6b"
}

Response Fields Reference

Envelope

FieldTypeDescription
urlstringThe address as checked: scheme and host lowercased, the host in ASCII (punycode) form, no #fragment
device, categories, languagestring, string[], stringlighthouse only. The options the run used, defaults filled in
javascriptbooleanaudit only. Whether the page was rendered with JavaScript; decides the price
markdownbooleancontent only. Whether Markdown was requested

lighthouse → data

FieldTypeDescription
final_urlstringWhere the page ended up after redirects
lighthouse_version, fetched_atstring, string | nullLighthouse version, and when the page was loaded (ISO 8601, UTC)
scoresobjectperformance, accessibility, best_practices, seo: 0–100, or null when not requested
metricsobject | nullLab values in milliseconds — first_contentful_paint_ms, largest_contentful_paint_ms, total_blocking_time_ms, speed_index_ms, time_to_interactive_ms — and the unitless cumulative_layout_shift. null unless performance was requested
failed_auditsobject[]id (Lighthouse's audit id), category, title, description (Markdown, with a "learn more" link), score 0–100, display_value, savings_ms and savings_bytes (estimated savings, null when not applicable)
passed_count, failed_countintegerScored checks that passed and failed in the requested categories
warningsstring[]Lighthouse's own notes about the run, e.g. a redirect or a page that loaded slowly

audit → data

FieldTypeDescription
final_url, status_codestring, integerThe address that answered after redirects, and its HTTP status
scorenumber | nullOn-page score, 0–100: how many of the checks the page passes, weighted
title, description, canonicalstring | nullFrom the page's <title>, meta description and canonical link
h1, headingsstring[], objectThe H1 texts, and the number of headings at each level h1…h6
word_count, readabilityinteger | null, number | nullWords of visible text, and the Flesch reading-ease score (0–100, higher is easier; calibrated for English)
linksobjectinternal and external link counts
images, scripts, stylesheetsinteger | nullCounts on the page
size_bytes, transfer_bytesinteger | nullHTML size, and bytes transferred (compressed)
load_time_ms, timinginteger | null, objectTotal load time, and its parts: connect_ms, waiting_ms (time to first byte), download_ms, dom_complete_ms, time_to_interactive_ms
issuesstring[]The problems found, from the list below
fetched_atstring | nullWhen the page was fetched (ISO 8601, UTC)

issues values: no_https, https_to_http_links, no_title, title_too_long, title_too_short, multiple_title_tags, irrelevant_title, no_description, irrelevant_description, irrelevant_meta_keywords, no_h1_tag, duplicate_meta_tags, not_canonical (the canonical link points to another page), seo_unfriendly_url, no_doctype, no_encoding_meta_tag, charset_mismatch, meta_refresh_redirect, render_blocking_resources, high_loading_time, high_waiting_time, no_content_encoding, page_over_3mb, large_page_size, small_page_size, low_content_rate, high_content_rate, low_character_count, high_character_count, low_readability_rate, no_image_alt, no_image_title, no_favicon, structured_data_errors, deprecated_html_tags, uses_flash, uses_frames, lorem_ipsum, broken_links, broken_resources.

content → data

FieldTypeDescription
titlestring | nullThe page's main heading as the content reads
languagestring | nullThe content's language, e.g. tr
sections, secondary_sectionsobject[]level (heading level), heading and text (paragraphs separated by newlines). sections is the main content; secondary_sections is what surrounds it
word_countintegerWords in sections
contactsobjectemails and phones found on the page
markdownstring | nullThe whole page as Markdown when "markdown": true, otherwise null

Errors

Every error carries a stable code, a readable error, and retryable; where it helps also field, hint and allowed. Send Accept-Language: tr for Turkish messages. You are never charged for an error. The full list, shared with the other APIs, is on Error Codes. Specific to this endpoint:

StatusCodeMeaningWhat to do
202—Not an error: still running after wait secondsPoll GET /v1/tasks/{task_id}; see Tasks
400URL_REQUIREDNo urlSend the page to check
400INVALID_URLNot a public http/https address: another scheme, localhost, an IP address, a name without a dotSend a URL on a domain name
400INVALID_PARAMETERe.g. an unknown device, categories value or language; field names it and allowed lists the valuesFix the field
422PAGE_BLOCKEDThe site refused the request (HTTP 401, 403 or 429), usually bot protection such as Cloudflare. The status is in the message. Not chargedAllow automated checks for the page, or check another page
422PAGE_UNAVAILABLEThe page could not be loaded: it answered with an error status (in the hint, e.g. HTTP 404), the host does not resolve or did not answer, or the page has no readable content. Not chargedCheck the address; retryable is true when trying again can help

Why a blocked page is an error and not a result: Lighthouse scores whatever page it receives. Behind bot protection that is the challenge page, and a "SEO 40" for it says nothing about your site. Sites that block headless browsers often still answer a plain fetch, so audit without javascript may work where lighthouse does not.

{
  "error": "The site refused the request (HTTP 403)",
  "code": "PAGE_BLOCKED",
  "field": "url",
  "hint": "Bot protection (such as Cloudflare) often blocks automated checks. Allow it for this check or try another page. You were not charged",
  "retryable": false,
  "request_id": "3f2b1c4d-0000-4000-8000-000000000001"
}

Credits & Limits

RequestCost
lighthouse$0.0055
audit$0.000165
audit with "javascript": true$0.00165
content (with or without Markdown)$0.000165

A page that cannot be checked (PAGE_BLOCKED, PAGE_UNAVAILABLE) is not charged.

Results are cached for 15 minutes, so that a page you have just fixed is checked again soon. A cached answer is marked "cached": true and billed at the same price as a live one.

Per-minute and per-day limits are set on your account (429 RATE_LIMIT_EXCEEDED). At most 5 requests per API user run at the same time; more get 429 TOO_MANY_CONCURRENT_REQUESTS with Retry-After. A request that has returned 202 keeps its place until its task finishes. At most 100 tasks per API user can be unfinished at once (429 TOO_MANY_PENDING_TASKS). Polling has its own limit and does not count against any of these; see Tasks.

Last updated: 2026-11-07