Markdown API

Convert any webpage to clean, structured Markdown. Strip away navigation, ads, and boilerplate to get just the content — perfect for LLM ingestion, AI pipelines, and content processing.

API Version

v3.0 enables smart defaults — auto_proxy, auto_render, and retry are all on by default. The best proxy and rendering strategy is chosen automatically for each target domain.

Endpoint

HTTP
GET https://opengraph.io/api/3.0/markdown/{encoded_url}?app_id=YOUR_APP_ID

Parameters

Path Parameters

ParameterTypeDescription
encoded_urlstringRequired. URL-encoded target URL

Query Parameters

ParameterTypeDefaultDescription
app_idstring-Required. Your API key
only_main_contentbooleantrueStrip navigation, sidebars, and footers — return only the primary content
include_tagsstring-Comma-separated HTML tags to include (e.g., article,main,section)
exclude_tagsstring-Comma-separated HTML tags to exclude (e.g., nav,footer,aside)
cache_okbooleantrueAllow cached results
accept_langstringen-USLanguage header for localized content
auto_proxybooleantrueAutomatically select optimal proxy
auto_renderbooleantrueAutomatically enable JS rendering when needed
retrybooleantrueAuto-retry failed requests with proxy escalation
formatstringmarkdownResponse format. markdown (default) returns the raw Markdown as plain text with Content-Type: text/markdown — identical to the existing behavior, so current integrations are unaffected. json returns a structured envelope containing the Markdown plus page metadata, character/token usage, fetch debug info, and (when requested) AI safety results. Any other value returns a 400 error.
max_charsinteger-Optional cap on the returned Markdown length — any positive integer. Non-numeric or non-positive values return a 400 error. When the output is truncated: raw mode sets X-Markdown-Truncated: true and X-Markdown-Truncation-Reason; JSON mode sets usage.truncated: true and usage.truncation_reason: "max_chars_exceeded".
ai_sanitizebooleanfalseRun an AI safety pass over the page before conversion to detect common prompt-injection patterns (hidden text, suspicious instructions, encoded payloads). Adds 1 credit to X-BILLING-REQUESTS when enabled.
ai_sanitize_modestringsanitizeControls what happens when suspicious content is detected (only applies when ai_sanitize=true). sanitize — strip the risky content and return cleaned Markdown plus an ai_safety summary. warn — return the original, unmodified Markdown with the ai_safety summary attached. block — return a 422 error instead of Markdown when the risk score is high. Invalid values fall back to sanitize.

Response Headers

HeaderPresentDescription
X-Request-IdAlwaysUnique ID for this request — also included as request_id in every JSON body (success or error). Use it when reporting an issue.
X-BILLING-REQUESTSAlwaysCredits billed for this request. Reflects the proxy tier that actually succeeded when retry escalated tiers, not just the tier initially requested.
X-Markdown-Character-Countformat=markdown onlyLength of the returned Markdown body, in characters.
X-Markdown-Truncated / X-Markdown-Truncation-ReasonOnly when truncatedSet when max_chars was exceeded and the body was cut off.
X-AI-Safety-Score / X-AI-Safety-LevelOnly with ai_sanitize=trueRisk score (0–1) and level (low/medium/high) for the fetched page, in format=markdown mode. In format=json mode this is the ai_safety object instead.

Example Request

# Default: plain text/markdown body
curl "https://opengraph.io/api/3.0/markdown/https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FWeb_scraping?app_id=YOUR_APP_ID"

# format=json: structured envelope with metadata, usage, and debug info
curl "https://opengraph.io/api/3.0/markdown/https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FWeb_scraping?app_id=YOUR_APP_ID&format=json"

Raw Markdown Response (default)

When format=markdown (default), the response body is unchanged from previous versions of this endpoint — plain text with Content-Type: text/markdown. The headers below are additive.

Response headers
Content-Type: text/markdown
X-Request-Id: 3f1a9c2e-8b4d-4e7a-9c1a-2d6f8e0b5a7c
X-BILLING-REQUESTS: 1
X-Markdown-Character-Count: 4820
# Only present when max_chars was exceeded:
X-Markdown-Truncated: true
X-Markdown-Truncation-Reason: max_chars_exceeded
# Only present when ai_sanitize=true:
X-AI-Safety-Score: 0.12
X-AI-Safety-Level: low

JSON Response (format=json)

When format=json, the response is a structured envelope. ai_safety is only present when ai_sanitize=true was requested — it's omitted entirely otherwise, rather than being sent as null.

Response
{
  "markdown": "# Example Article\n\nMain content here...",
  "metadata": {
    "title": "Example Article Title",
    "description": "A short description from the page's meta tags.",
    "canonical_url": "https://example.com/article",
    "site_name": "Example Site",
    "image": "https://example.com/og-image.jpg",
    "language": "en",
    "final_url": "https://example.com/article"
  },
  "usage": {
    "character_count": 4820,
    "estimated_token_count": 1205,
    "truncated": false,
    "truncation_reason": null,
    "max_chars": null
  },
  "debug": {
    "full_render_used": false,
    "auto_render_triggered": false,
    "proxy_used": null,
    "retry_used": false,
    "retry_attempts": 1,
    "final_status_code": 200
  },
  "request_id": "3f1a9c2e-8b4d-4e7a-9c1a-2d6f8e0b5a7c"
}

Adding ai_sanitize=true attaches an ai_safety object:

ai_safety (when ai_sanitize=true)
"ai_safety": {
  "risk_score": 0.12,
  "risk_level": "low",
  "action_taken": "sanitize",
  "signals": [],
  "recommendation": "No action needed."
}

Structured Errors

Every error response — regardless of format — is JSON with an error object and the same request_id that was returned in X-Request-Id. Check error.code, not the HTTP status alone, since several distinct failure modes can share a status code.

Example error response
{
  "error": {
    "code": -2201,
    "message": "Invalid max_chars value. Must be a positive integer."
  },
  "request_id": "3f1a9c2e-8b4d-4e7a-9c1a-2d6f8e0b5a7c"
}
HTTP Statuserror.codeMeaning
400-2200Invalid format — must be markdown or json
400-2201Invalid max_chars — must be a positive integer
400variesThe target URL could not be fetched (DNS failure, timeout, blocked, etc.)
404-4000The fetch succeeded but returned no HTML content
422-4001Blocked by ai_sanitize_mode=block — high prompt-injection risk detected. The response also includes an ai_safety object explaining why.
500-4002HTML-to-Markdown conversion failed unexpectedly

Use Cases

  • LLM and AI content ingestion pipelines
  • RAG (Retrieval-Augmented Generation) data preparation
  • Content migration between platforms
  • Documentation scraping and archival
  • Clean text extraction for NLP processing
  • Safe ingestion of untrusted external pages with AI safety sanitization

Related