API Documentation

ExtractAPI turns an allowed public URL into structured JSON with a single REST call. The browser-backed path can render JavaScript before extracting metadata, content, JSON-LD, links, images, and an optional selector; protected or unsafe targets may still fail.

Base URL: https://extractapi.app
All API requests use Authorization: Bearer YOUR_API_KEY header.

First extraction

Start free with 50 trial requests and no card. Verify an email to unlock 500 requests/month. Your free key is displayed once: copy it directly to an environment variable, then choose an example below.

1. Get a keyCreate a free API key on the homepage.
2. Keep it secretSet EXTRACTAPI_KEY locally. Do not commit it, paste it into browser code, or send it to support.
3. Extract a public URLCopy one example and replace the target URL with a page you are allowed to access.

Choose a workflow: AI-agent web extraction, JavaScript website to JSON, or competitor price monitoring.

Use-case guides

Choose the workflow closest to your integration. Each guide includes a supported request, representative output, and the limits to plan for.

JavaScript website to JSONRender and extract dynamic pages →
Competitor price monitoringBuild a monitored workflow →

Endpoints

POST /v1/extract Extract data from a URL

Request Body

FieldTypeRequiredDefaultDescription
urlstring✅ YesThe page URL to extract (HTTP/HTTPS)
selectorstringNoCSS selector for custom element extraction
waitForstringNoCSS selector to wait for before extracting
extractImagesbooleanNofalseInclude image src and alt attributes
extractLinksbooleanNofalseInclude link href and text
javascriptbooleanNotrueEnable JavaScript rendering

Example — cURL

export EXTRACTAPI_KEY="YOUR_API_KEY"

curl --request POST https://extractapi.app/v1/extract \
  --header "Authorization: Bearer $EXTRACTAPI_KEY" \
  --header "Content-Type: application/json" \
  --data '{"url":"https://example.com"}'

Example — Node.js (18+)

const response = await fetch('https://extractapi.app/v1/extract', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EXTRACTAPI_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ url: 'https://example.com' })
});

if (!response.ok) throw new Error(`ExtractAPI returned ${response.status}`);
const { data } = await response.json();
console.log(data.title);

Example — Python

import os
import requests

response = requests.post(
    'https://extractapi.app/v1/extract',
    headers={'Authorization': f"Bearer {os.environ['EXTRACTAPI_KEY']}"},
    json={'url': 'https://example.com'},
    timeout=30,
)
response.raise_for_status()
print(response.json()['data']['title'])

Keep keys in server-side environment variables. Never put a key in frontend JavaScript or a public repository.

Illustrative success response

This is a synthetic response shape. Target content, timings, and byte counts vary by page and are not a performance or availability claim.

{
  "status": "ok",
  "url": "https://example.com/product/123",
  "data": {
    "title": "Product Name — Example Store",
    "metaDescription": "...",
    "metaKeywords": "...",
    "openGraph": { "og:title": "...", "og:image": "..." },
    "h1": "Product Name",
    "headings": [
      { "level": "h1", "text": "Product Name" },
      { "level": "h2", "text": "Description" }
    ],
    "mainContent": "Full page text...",
    "structuredData": [
      { "@context": "https://schema.org", "@type": "WebPage", "name": "Example Domain" }
    ],
    "canonical": "https://example.com/product/123",
    "language": "en",
    "links": [
      { "text": "About", "href": "https://example.com/about" }
    ],
    "images": [
      { "src": "https://example.com/image.png", "alt": "Example", "width": 640, "height": 480 }
    ],
    "custom": ["$12.00"],
    "pageStats": {
      "textLength": 8432,
      "linkCount": 47,
      "imageCount": 12,
      "scriptCount": 5
    }
  },
  "responseTimeMs": 1247,
  "bytesReturned": 1583,
  "fetchedAt": "2026-07-22T16:30:00.000Z"
}

Illustrative error response

{
  "status": "error",
  "url": "https://blocked-site.example",
  "error": "Target could not be extracted",
  "responseTimeMs": 3021
}
POST /v1/extract/batch Extract up to 10 URLs

Request

{
  "urls": [
    "https://example.com/product/1",
    "https://example.com/product/2"
  ]
}

Response

{
  "status": "ok",
  "results": [
    {
      "status": "ok",
      "url": "https://example.com/product/1",
      "data": { "title": "Example Product" },
      "responseTimeMs": 123,
      "bytesReturned": 456,
      "fetchedAt": "2026-01-01T00:00:00.000Z"
    },
    {
      "status": "error",
      "url": "https://example.com/product/2",
      "error": "Target could not be extracted",
      "responseTimeMs": 301
    }
  ]
}
GET /v1/stats View your usage

Response

{
  "apiKeyName": "My Project",
  "plan": "pro",
  "monthlyUsage": 1247,
  "monthlyLimit": 25000,
  "remaining": 23753,
  "upgradeUrl": "/#pricing",
  "quotaResetAt": "2026-08-01T00:00:00.000Z",
  "billingPortalAvailable": true,
  "recentRequests": [
    {
      "url": "https://example.com/product/1",
      "status": "ok",
      "response_time_ms": 123,
      "created_at": "2026-01-01 00:00:00"
    }
  ]
}

Free-tier verification

The free key starts with 50 trial requests. Submit the key and an email to POST /free-key-verification; the verification link unlocks 500 requests/month. The key itself is never stored in the verification record.

curl --request POST https://extractapi.app/free-key-verification \
  --header "Content-Type: application/json" \
  --data '{"apiKey":"YOUR_FREE_API_KEY","email":"[email protected]"}'

Billing portal

Paid keys can open Stripe's hosted portal for invoices, payment methods, cancellation, and plan changes:

curl --request POST https://extractapi.app/create-portal-session \
  --header "Authorization: Bearer $EXTRACTAPI_KEY"

Key rotation

Rotate a compromised key without losing usage history or subscription state. The replacement is returned once; update your server-side secret immediately:

curl --request POST https://extractapi.app/v1/rotate-key \
  --header "Authorization: Bearer $EXTRACTAPI_KEY"
GET /health Server health

Authentication

All API requests require an API key passed in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Choose the Free plan to receive an ext_free_ key immediately — no credit card or Stripe checkout required. The trial starts at 50 requests; verify an email to unlock 500/month. Paid-plan keys are shown on the checkout success page.

Error Codes

HTTPMeaning
200Extraction succeeded (status: "ok")
400Missing or invalid url field
401Missing or invalid API key
403API key is inactive or invalid
422Extraction failed or URL is blocked (SSRF protection)
429Rate limit or monthly limit exceeded
500Internal server error

For authentication errors, check that the server-side Authorization: Bearer value is present and has not expired. For 429, wait for the returned Retry-After; do not guess a countdown. A blocked target means the URL or a redirect failed safety validation. An empty result can mean the page rendered no readable content; try a supported selector or inspect the response ID with support. Selector errors indicate an invalid or unsupported CSS selector. Include the request ID and sanitized error category when contacting support, never the key or page contents.

Rate Limits

Each API key is rate-limited per second and per month:

When rate-limited, you'll receive HTTP 429 with a Retry-After header. Authenticated responses also include X-Quota-Limit, X-Quota-Remaining, and X-Quota-Reset.

URL Safety

ExtractAPI validates all URLs for safety:

Support

Need help? Email [email protected]. Include your target URL, language, and error message — never include your API key.