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.
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
GET https://opengraph.io/api/3.0/markdown/{encoded_url}?app_id=YOUR_APP_IDParameters
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| encoded_url | string | Required. URL-encoded target URL |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| app_id | string | - | Required. Your API key |
| only_main_content | boolean | true | Strip navigation, sidebars, and footers — return only the primary content |
| include_tags | string | - | Comma-separated HTML tags to include (e.g., article,main,section) |
| exclude_tags | string | - | Comma-separated HTML tags to exclude (e.g., nav,footer,aside) |
| cache_ok | boolean | true | Allow cached results |
| accept_lang | string | en-US | Language header for localized content |
| auto_proxy | boolean | true | Automatically select optimal proxy |
| auto_render | boolean | true | Automatically enable JS rendering when needed |
| retry | boolean | true | Auto-retry failed requests with proxy escalation |
| format | string | markdown | Response 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_chars | integer | - | 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_sanitize | boolean | false | Run 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_mode | string | sanitize | Controls 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
| Header | Present | Description |
|---|---|---|
| X-Request-Id | Always | Unique ID for this request — also included as request_id in every JSON body (success or error). Use it when reporting an issue. |
| X-BILLING-REQUESTS | Always | Credits billed for this request. Reflects the proxy tier that actually succeeded when retry escalated tiers, not just the tier initially requested. |
| X-Markdown-Character-Count | format=markdown only | Length of the returned Markdown body, in characters. |
| X-Markdown-Truncated / X-Markdown-Truncation-Reason | Only when truncated | Set when max_chars was exceeded and the body was cut off. |
| X-AI-Safety-Score / X-AI-Safety-Level | Only with ai_sanitize=true | Risk 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.
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: lowJSON 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.
{
"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": {
"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.
{
"error": {
"code": -2201,
"message": "Invalid max_chars value. Must be a positive integer."
},
"request_id": "3f1a9c2e-8b4d-4e7a-9c1a-2d6f8e0b5a7c"
}| HTTP Status | error.code | Meaning |
|---|---|---|
| 400 | -2200 | Invalid format — must be markdown or json |
| 400 | -2201 | Invalid max_chars — must be a positive integer |
| 400 | varies | The target URL could not be fetched (DNS failure, timeout, blocked, etc.) |
| 404 | -4000 | The fetch succeeded but returned no HTML content |
| 422 | -4001 | Blocked by ai_sanitize_mode=block — high prompt-injection risk detected. The response also includes an ai_safety object explaining why. |
| 500 | -4002 | HTML-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