No KYC — no ID, no selfie, no documents. Pay in crypto: BTC, USDT, USDC, ETH, SOL, LTC
Language: English
Get an API key

Docs · response

Read API response format, field by field

Every /read call returns one JSON object: the page's content in the format you asked for, its metadata, and three fields that tell you what happened and what it cost. Job results reuse the same object.

Last updated: · 5 min read

Quick answer

What does the WebReaderAPI read response contain?

A WebReaderAPI /read response holds the page content in markdown (or text or html), its metadata (title, description, author, published_at, language, site_name, word_count), and the facts of the fetch: final_url, status_code, rendered and credits_used. A plain page uses 1 credit, from $0.07/1K pages as of October 2026. No KYC; pay in crypto.

Which fields describe the fetch?

These fields are always present in a successful response.

FieldTypeMeaning
urlstringThe address you sent
final_urlstringThe address actually read, after redirects (5 at most)
status_codeintegerThe HTTP status the site returned for the final address, normally 200
fetched_atstringTime of the fetch, ISO 8601 in UTC
renderedbooleantrue when a headless browser built the page
credits_usedintegerCredits billed for this page: 1, 2 with a browser, plus 10 with country; PDFs 1 per started 10 pages

Which fields describe the page?

Metadata comes from the page itself: its title tag, meta tags, structured data and visible byline. A field the page does not provide is absent, so test for it before use.

FieldTypeMeaning
titlestringThe page or article title
descriptionstringThe summary the page gives of itself
languagestringLanguage code of the content, such as en or de
authorstringThe author named on the page
published_atstringPublication date stated by the page
site_namestringThe site's own name
word_countintegerWords in the returned content, after extraction and before max_chars

Where is the content itself?

One content field is returned, named after the format you chose.

FieldWhenContent
markdownformat=markdown (default)Headings, paragraphs, lists, tables and links in Markdown; images too with include_images=true
textformat=textPlain text, paragraphs separated by blank lines
htmlformat=htmlCleaned HTML of the main content, without scripts, styles or ads
linksinclude_links=trueList of {url, text} for the links found on the page, absolute URLs
A complete response (values are illustrative)
{
  "url": "https://example.com/guides/compost",
  "final_url": "https://example.com/guides/compost-at-home",
  "status_code": 200,
  "fetched_at": "2026-10-22T10:02:44Z",
  "rendered": false,
  "credits_used": 1,
  "title": "Compost at home: a beginner's guide",
  "description": "What to put in a compost bin, and what to leave out.",
  "language": "en",
  "author": "Sam Rivera",
  "published_at": "2026-09-14",
  "site_name": "Example Garden",
  "markdown": "# Compost at home: a beginner's guide\n\nA compost bin turns kitchen scraps into soil...\n\n## What goes in\n\n- Fruit and vegetable peels\n- Coffee grounds\n\nSee also [Choosing a bin](https://example.com/guides/bins).",
  "word_count": 1184,
  "links": [
    { "url": "https://example.com/guides/bins", "text": "Choosing a bin" }
  ]
}

How do I tell a rendered page from a plain one?

Look at rendered. With render=auto, the API first reads the raw HTML; it starts a browser only when that HTML holds too little text, and then sets rendered to true and credits_used to 2. If a site you read often always comes back rendered, send render=true from the start: the cost is the same and you skip a wasted first step.

If a page comes back unrendered but thin, compare word_count with what you see in a browser. A low count usually means the content needs JavaScript; retry once with render=true.

Why can final_url differ from url?

Because sites redirect. A short link, an old address, a missing trailing slash or a language switch all send you elsewhere. The API follows up to 5 redirects and reports the address it finally read in final_url.

Store final_url as the canonical source of a document in a RAG index. Two different url values that end at the same final_url are the same page, so you can drop the duplicate before embedding it.

What does a job result look like?

GET https://webreaderapi.com/api/v1/jobs/{job_id} returns job_id, status (queued, running or done), results, next_cursor and the job's running credits_used. Each item of results is one of two shapes:

  • a full /read response, exactly as described above, for a page that was read;
  • {url, error} for a page that was not, where error has the same code and message as an API error.

next_cursor is present while more results are ready; send it back as cursor to get them. The batch and crawl page has a complete polling loop.

A job result page (values are illustrative)
{
  "job_id": "job_5c1e8a90d2",
  "status": "done",
  "results": [
    { "url": "https://example.com/blog/post-1", "final_url": "https://example.com/blog/post-1", "status_code": 200, "rendered": false, "credits_used": 1, "title": "Post one", "markdown": "# Post one\n\n...", "word_count": 802 },
    { "url": "https://example.org/members/area", "error": { "code": "target_refused", "message": "The site refused the request.", "target_status": 403 } }
  ],
  "credits_used": 1
}

What does an error response look like?

An error comes back with an HTTP status of 400 or more and a JSON body {"error": {"code", "message"}}. When the site itself refused the request, target_status gives the status the site sent. No error is billed. The errors page lists every code with its cause and whether a retry can help.

Response format: common questions

Is the Markdown cut when I set max_chars?

Yes. The content field stops at that many characters. word_count still describes the whole extracted content, so you can see how much was left out.

Why is author or published_at missing?

Because the page does not state it in a way that can be read. Many pages give no author or date. Absent fields are omitted rather than returned empty.

Links in the links list are absolute. Write your code to accept both forms in the Markdown body, and resolve relative ones against final_url.

Can I get the raw HTML of the whole page?

The closest is format=html with main_content=false, which returns the whole page cleaned of scripts and styles. The original byte-for-byte HTML is not part of v1.

From $0.07/1K pages · no KYC

Get an API key