snakereach

Endpoint

Scrape a URL.

One URL in, one normalized document out: markdown, metadata, links, images, tables, and the timings for every stage that produced them.

POST/v1/scrapeAPI key

Acquire one URL: fetch, extract everything, return one normalized document.

Body

FieldTypeDetail
url requiredstringA bare host gets https:// prepended.
use_cachebooleanServe from the HTTP cache when fresh. Default true.
include_htmlbooleanReturn the raw HTML body. Default false. It is by far the largest field. The key is always present, just empty.
request
curl https://api.snakereach.com/v1/scrape \
  -H "X-API-Key: $SNAKEREACH_API_KEY" \
  -H "content-type: application/json" \
  -d '{"url": "https://example.com/article"}'
200 response
{
  "url": "https://example.com/article",
  "final_url": "https://example.com/article",
  "fetched_at": "2026-07-30T11:43:46.878250Z",
  "status": 200,
  "content_type": "text/html",
  "depth": 0,
  "title": "The Quiet Rise of Underwater Farming",
  "author": "Nadia Okafor",
  "published_date": "2025-11-03",
  "language": "en",
  "description": "How submerged greenhouses are reshaping coastal agriculture.",
  "keywords": ["aquaculture", "farming", "ocean"],
  "site_name": "Ocean Journal",
  "markdown": "# The Quiet Rise of Underwater Farming\n\nTwenty meters beneath …",
  "text": "The Quiet Rise of Underwater Farming\nTwenty meters beneath the Li …",
  "html": "",
  "links": [
    { "url": "https://example.com/", "text": "Home", "internal": true, "nofollow": false }
  ],
  "images": [
    { "url": "https://example.com/images/biosphere.jpg",
      "alt": "A submerged biosphere with basil plants", "title": "" }
  ],
  "tables": [
    { "caption": "Yield comparison",
      "headers": ["Crop", "Land yield", "Biosphere yield"],
      "rows": [["Basil", "1.0x", "1.4x"], ["Strawberry", "1.0x", "1.1x"]] }
  ],
  "records": [],
  "metadata": {
    "json_ld": [
      { "@context": "https://schema.org", "@type": "NewsArticle",
        "headline": "The Quiet Rise of Underwater Farming",
        "author": { "@type": "Person", "name": "Nadia Okafor" },
        "datePublished": "2025-11-03", "inLanguage": "en" }
    ]
  },
  "trace": {
    "stages": [
      { "name": "fetch",    "elapsed_ms": 22.2 },
      { "name": "parse",    "elapsed_ms": 1.3 },
      { "name": "content",  "elapsed_ms": 185.8 },
      { "name": "metadata", "elapsed_ms": 10.0 },
      { "name": "links",    "elapsed_ms": 0.1 },
      { "name": "media",    "elapsed_ms": 0.0 },
      { "name": "records",  "elapsed_ms": 0.1 },
      { "name": "combine",  "elapsed_ms": 0.0 }
    ],
    "cache_hit": false,
    "rendered": false,
    "redirects": [],
    "warnings": []
  }
}

Errors

  • 403 robots.txt disallows the URL, or it resolves to a non-public address
  • 413 the response body exceeded the size cap
  • 415 no parser is installed for that content type
  • 502 the page could not be fetched
  • 504 the upstream site timed out

What comes back

Always the same shape, see the Document schema for every field. A target site returning 404 is not an API error: you get a normal document with status: 404. The API only errors when it could not obtain a response at all.

Rendering

JavaScript pages are rendered automatically, and only when the page turns out to be a shell. There is no flag to force it; the pipeline decides, and the trace tells you what it decided via rendered.

Check capabilities.rendering on /v1/health first: when a deployment has no browser installed, JS-only pages return a warning in the trace rather than a body.