Use case · rendered public pages

Turn a JavaScript website into JSON

A raw HTTP response can contain an app shell while the browser-rendered page contains the product, listing, or article your integration needs. ExtractAPI can render a public page in Chromium and return bounded metadata, headings, text, structured data, links, and selected text through one authenticated REST request.

When browser rendering helps

Use it when the initial response is mostly a root element and script bundles, or when useful content appears after a client-side request. A browser is not automatically better: server-rendered HTML and an upstream JSON feed are often cheaper and simpler. Compare both paths for your target.

Expectation: javascript:true enables page JavaScript, but it does not guarantee that every SPA, protected site, login flow, CAPTCHA, or third-party widget will render successfully.

Input and synthetic output

The following example uses demo.example and invented values so it can be copied without contacting a real site. selector is returned as the custom array; there is no selectorText field in the API contract.

curl -X POST https://extractapi.app/v1/extract \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://demo.example/products/widget",
    "javascript": true,
    "waitFor": "[data-ready=\"true\"]",
    "selector": "[data-price]",
    "extractLinks": true
  }'
{
  "status": "ok",
  "url": "https://demo.example/products/widget",
  "data": {
    "title": "Widget Pro | Demo Store",
    "metaDescription": "A synthetic product page for examples.",
    "h1": "Widget Pro",
    "headings": [{"level":"h1","text":"Widget Pro"}],
    "mainContent": "Widget Pro In stock $49.00",
    "structuredData": [{"@type":"Product","name":"Widget Pro"}],
    "custom": ["$49.00"],
    "links": [{"text":"Specifications","href":"/products/widget/specs"}],
    "pageStats": {"textLength": 31, "linkCount": 1, "imageCount": 0, "scriptCount": 4},
    "canonical": "https://demo.example/products/widget",
    "language": "en"
  },
  "responseTimeMs": 842,
  "bytesReturned": 912,
  "fetchedAt": "2026-09-05T00:00:00.000Z"
}

Implement it with native Node.js

The script below reads the key from the process environment, accepts a public URL, handles non-success responses, and prints only the sanitized API response. Node does not load a .env file by itself; export the variable or use your approved environment loader before starting the process.

// extract-rendered.mjs
const [target] = process.argv.slice(2);
const key = process.env.EXTRACTAPI_KEY;

if (!target || !/^https?:\/\//i.test(target)) {
  console.error('Usage: EXTRACTAPI_KEY=YOUR_API_KEY node extract-rendered.mjs https://example.com');
  process.exitCode = 2;
} else if (!key || /^(YOUR_API_KEY|ext_your)/i.test(key)) {
  console.error('Set EXTRACTAPI_KEY to a real key before making a request.');
  process.exitCode = 2;
} else {
  try {
    const response = await fetch('https://extractapi.app/v1/extract', {
      method: 'POST',
      headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
      body: JSON.stringify({ url: target, javascript: true })
    });
    const body = await response.json();
    if (!response.ok || body.status !== 'ok') {
      console.error(JSON.stringify({ error: body.error || `HTTP ${response.status}` }));
      process.exitCode = 1;
    } else {
      console.log(JSON.stringify(body, null, 2));
    }
  } catch (error) {
    console.error(JSON.stringify({ error: 'Request failed', detail: error.message }));
    process.exitCode = 1;
  }
}

POSIX: EXTRACTAPI_KEY=YOUR_API_KEY node extract-rendered.mjs https://example.com. PowerShell: $env:EXTRACTAPI_KEY="YOUR_API_KEY"; node .\extract-rendered.mjs https://example.com. Keep the key out of shell history where practical and never commit it.

Supported workflow

  1. Fetch the same public URL with a lightweight client and inspect whether the required text is already in the HTML.
  2. If the content is client-rendered, call the API with javascript:true; use a stable waitFor selector when the page exposes one.
  3. Use selector for a narrow field and normalize the returned custom text in your own code. Use structuredData when a site publishes JSON-LD.
  4. Persist only the fields your application needs. Track the response status and request ID when troubleshooting, not the target page’s private content.

Limitations

FAQ

Will this work for every React or Vue site?

No. Rendering helps when the data is available to a normal public browser, but a site can still require authentication, block automated traffic, or depend on unsupported interactions. Test a representative target before designing a hard dependency.

What does the API return for JSON-LD?

Valid script[type="application/ld+json"] blocks are returned in data.structuredData, subject to response limits. Malformed blocks are skipped.

Can I turn off JavaScript?

Yes. Omit javascript or send false when the initial HTML is enough. The default authenticated extractor enables JavaScript unless explicitly disabled.

Get a free API key