brime

Extract

POST /v1/extract — turn URLs into clean markdown.

POST /v1/extract fetches one or more URLs and returns clean markdown. Handles HTML, PDF, DOCX, and SPA hydration; auto-escalates to a real Chrome render when needed.

This endpoint requires an Idempotency-Key header. The Python and Node.js SDKs auto-generate one per call. If you call it directly, set your own UUID.

Quick example

from brime import Brime

client = Brime()
result = client.extract(urls=[
    "https://example.com",
    "https://en.wikipedia.org/wiki/Generative_artificial_intelligence",
])

for r in result.results:
    print(r.url, r.method, r.content_type, len(r.markdown))
for f in result.failed:
    print("FAIL", f.url, f.error.code, f.error.message)
import { Brime } from "@brime-ai/brime";

const client = new Brime();
const result = await client.extract({
  urls: ["https://example.com", "https://en.wikipedia.org/wiki/Generative_artificial_intelligence"],
});

for (const r of result.results) {
  console.log(r.url, r.method, r.content_type, r.markdown.length);
}
for (const f of result.failed) {
  console.log("FAIL", f.url, f.error.code, f.error.message);
}
curl https://api.brime.dev/v1/extract \
  -H "Authorization: Bearer $BRIME_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://example.com", "https://en.wikipedia.org/wiki/Generative_artificial_intelligence"]}'

Request

FieldTypeDefaultDescription
urlsstring | string[]required1–10 URLs.
cleanbooltrueSmart-clean HTML→markdown pipeline (readability-style noise strip, CMS template cleanup, citation strip). false falls back to a raw regex strip + htmd. See Smart-clean below.
include_metadataboolfalseAdds debug fields (timings, detection) under metadata on each result. The unified metadata block (title, description, author, published_date, canonical, og_image, language) is always emitted regardless of this flag.
per_url_timeout_msinteger250005,000–30,000.

Headers

HeaderRequiredNotes
AuthorizationyesBearer sk-brime-...
Idempotency-KeyyesAny string. SDK auto-generates UUID4 if you don't set.

Response

{
  "results": [
    {
      "url": "https://example.com",
      "markdown": "# Example Domain\n\nThis domain is for use in...",
      "method": "worker_static",
      "content_type": "html",
      "status": 200,
      "latency_ms": 312,
      "metadata": {
        "title": "Example Domain",
        "description": null,
        "author": null,
        "published_date": null,
        "canonical": "https://example.com/",
        "og_image": null,
        "language": "en"
      }
    }
  ],
  "failed": [
    {
      "url": "https://blocked.example.com",
      "error": {
        "code": "bot_challenge",
        "message": "Bot challenge detected; browser tier also failed",
        "needs_browser": false
      }
    }
  ],
  "request_id": "req_01J...",
  "credits_used": 2,
  "latency_ms": 1845
}

Result fields

FieldTypeWhen presentNotes
urlstringalwaysThe deduped input URL.
markdownstringalwaysExtracted text (markdown for HTML/PDF, plain text for DOCX / hydration fallback).
methodstringalwaysSee Tier dispatch.
content_typestringalways"html", "pdf", or "docx".
statusintegerusuallyOrigin HTTP status.
latency_msintegerusuallyEnd-to-end per-URL latency.
render_latency_msintegerchrome_render onlyBrowser-render time.
metadataobjectalways (when worker emits any field)Unified page metadata, see below.
detectionstringwhen include_metadata=trueEngine signal trail (e.g. "static", "bot:datadome,escalated").

metadata block

Always an object when present; each sub-field is a non-empty string or null. The block reflects what the engine could derive from the page; DOCX results always have all-null metadata.

FieldSource priority
title<meta og:title> → <meta twitter:title> → <title>
description<meta og:description> → <meta name=description>
author<meta article:author> → <meta name=author>
published_date<meta article:published_time> → name=date → pubdate → dc.date.issued → JSON-LD datePublished
canonical<link rel=canonical> → <meta og:url> → request URL
og_image<meta og:image> → <meta twitter:image>
language<html lang> → <meta og:locale>

Tier dispatch

methodTierWhat ran
worker_pdfstaticPDF parsed and converted to markdown.
worker_docxstaticDOCX parsed to plain text.
worker_staticstaticHTML cleaned and converted to markdown.
worker_hydrationstaticSingle-page app hydration data extracted as JSON.
worker_rust_mdstaticLegacy method retained for cached-response parsing.
chrome_renderbrowserFull headless-browser render.

The browser tier auto-escalates when:

  • A bot challenge is detected (Cloudflare, hCaptcha, DataDome, etc.).
  • A single-page app returned no content after static hydration.
  • A static fetch returned a non-2xx status.

Pricing is 1 credit per deduped input URL regardless of tier — Chrome escalations are not surcharged. See pricing.

failed[].error.code

CodeMeaning
fetch_failedOrigin returned non-2xx (HTTP status in detection).
bot_challengeBot/captcha pattern detected; Tier 2 also failed.
garbledBody was binary or non-text.
spa_no_contentSPA without hydration; Tier 2 also empty.
render_failedChrome render call failed, returned empty, or returned thin content (text_len < 100).
network_errorDNS, TCP, or fetch abort.
unsupported_formatFile type not in supported set.
internal_errorCatch-all for unexpected engine error.

Smart-clean

The HTML → markdown pipeline runs a deterministic readability-style pre-processor by default. Six phases:

  1. DOM parse (linkedom).
  2. Noise selector strip — <script> / <style> / <nav> / <footer> / <aside>, cookie banners, ad containers, framework chrome (Wikipedia sidebars, etc.).
  3. Semantic content cascade (<article> / <main> / [role="main"] priority, multi-container merge for CMS pages).
  4. Density-scoring fallback when the cascade returns empty.
  5. htmd_wasm HTML→markdown conversion.
  6. Markdown post-process: CMS template tokens stripped, AEM UUID content-references removed, inline citations ([1], [1,2]) trimmed, "References" / "See also" section-cutoff.

Pass clean: false to opt out — you'll get the pre-refactor pipeline (regex strip → htmd, no post-process). Same response shape, lower latency (~180 ms faster on average), but noisier output. Use it for A/B testing or when smart-clean over-trims a specific site.

Smart-clean applies to both worker_static and chrome_render paths. PDF, DOCX, and hydration outputs are unaffected.

Edge cases

  • Mixed success: a request with 5 URLs may return 4 in results and 1 in failed. The 200 status applies to the request as a whole; per-URL outcomes live in those arrays.
  • Idempotent retries: if you re-send with the same Idempotency-Key within 24 h, you get the cached response and pay nothing.
  • Empty urls: 400 invalid_request.
  • More than 10 URLs: 400 invalid_request.
  • chrome_render thin output: A successful Chrome render that yields fewer than 100 characters is demoted to failed[] with code: "render_failed" rather than returned as an empty results[] entry.

Errors

StatuscodeMeaning
400invalid_requestMalformed body, empty urls, >10 URLs.
401unauthorizedMissing/revoked API key.
429rate_limitedPer-key budget hit.
502upstream_errorBrowser tier or fetcher degraded.