WebExtrator Web Page Rendering API Integration Guide

POST https://api.acedata.cloud/webextrator/render

The WebExtrator Web Page Rendering API is a web rendering service based on headless Chromium. Given a URL, it returns the fully rendered HTML (including content injected by JS), plain text, page title, and final URL.

Render is the lowest-level interface of WebExtrator. If you need structured extraction results (article body, product price, recipe ingredients, etc.), please use /webextrator/extract — it runs a complete set of typed extraction pipelines on the same rendering basis.

Application Process

To use the WebExtrator service page, first go to the Ace Data Cloud Console to obtain your API Token for backup.

If you are not logged in or registered, you will be automatically redirected to the login page inviting you to register and log in, and after completion, you will be automatically returned to the current page.

One API Token can call all services on the platform, no need to apply separately for each service. The first application will grant a free quota for a free experience; when the quota is insufficient, you can recharge the general balance in the console.

📘 Complete documentation: WebExtrator Service Page →

Authentication

All WebExtrator interfaces use standard Bearer Token authentication:

Authorization: Bearer YOUR_API_KEY
Content-Type:  application/json

Request Parameters

Field Type Required Default Description
url string The URL of the page to render, must be http(s)://.
user_agent string Built-in UA pool rotation Custom User-Agent.
timeout number 30 Single navigation timeout (seconds).
wait_until enum networkidle Load completion event: load / domcontentloaded / networkidle / commit.
delay number 0 Additional wait seconds after wait_until is triggered (for SPA re-rendering).
wait_for_selector string Wait for this CSS selector to appear, more stable than networkidle.
block_resources string[] ["image","font","media"] Types of resources to block, optional: image / font / media / stylesheet / xhr / fetch.
headers object Additional HTTP request headers (e.g., {"Accept-Language": "en-US"}).
cookies array Cookies injected before navigation, structure as below.
callback_url string Callback address in asynchronous mode, the platform will POST the complete result to this address when the task is completed.
bypass_cache boolean false Skip Redis cache reading (but will still write this result back to cache).
cache_ttl_seconds number 3600 Custom TTL for this write to cache, passing 0 means do not cache this response.
async boolean false Set to true to immediately return task_id, results can be retrieved via callback_url or Tasks API.

The platform contract uniformly uses snake_case. The internal rendering service supports camelCase, but external calls always use snake_case.

{
  "name":      "string",
  "value":     "string",
  "domain":    "string",
  "path":      "/",
  "expires":   1735689600,
  "httpOnly":  false,
  "secure":    true,
  "sameSite":  "Lax"
}

Synchronous Response

{
  "success": true,
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "trace_id": "550e8400-e29b-41d4-a716-446655440001",
  "started_at": 1777717800.123,
  "finished_at": 1777717801.234,
  "elapsed": 1.111,
  "data": {
    "kind": "render",
    "url": "https://example.com",
    "finalUrl": "https://example.com/",
    "title": "Example Domain",
    "status": 200,
    "html": "<!DOCTYPE html><html>...</html>",
    "text": "Example Domain\nThis domain is for use in illustrative examples...",
    "userAgent": "Mozilla/5.0 ...",
    "elapsedMs": 1108
  }
}
Field Type Description
data.kind string Fixed "render".
data.url string The URL you submitted.
data.finalUrl string The final URL after following redirects.
data.title string The rendered document.title.
data.status number | null The HTTP status code of the main navigation.
data.html string The complete rendered HTML.
data.text string Snapshot of document.body.innerText (use Extract for cleaner body).
data.userAgent string The actual UA used.
data.elapsedMs number Time taken for browser rendering only.
data.cached boolean? true when cache is hit.
data.cacheStoredAt number? Unix millisecond timestamp when the cache entry was first written.

Asynchronous Response

When async=true (or providing callback_url), it immediately returns (HTTP 200):

{
  "success": true,
  "task_id": "550e8400-...",
  "trace_id": "6ba7b810-...",
  "started_at": 1777717800.123
}

The result will be pushed via POST to callback_url (if configured), or actively queried through /webextrator/tasks.

Callback Structure

The platform POSTs an envelope identical to the synchronous mode to callback_url, Content-Type: application/json. Returning any 2xx is considered confirmed; 5xx will be retried with exponential backoff for about 5 minutes.

Error Response

HTTP error.code Meaning
400 bad_request The request body did not pass Zod validation (missing url, incorrect type, etc.).
401 unauthorized Missing or invalid Authorization: Bearer ….
402 (x402) Insufficient platform balance, returning x402 payment request envelope.
408 timeout Navigation exceeded timeout.
429 queue_busy Sync queue is congested, please retry or use async=true.
500 internal_error Unhandled exception on the server side (browser crash, etc.), Worker will automatically retry once.

Error structure:

{
  "success": false,
  "task_id": "...",
  "trace_id": "...",
  "started_at": 1777717800.123,
  "finished_at": 1777717800.135,
  "elapsed": 0.012,
  "error": { "code": "bad_request", "message": "url: Invalid url" }
}

Example

cURL

curl -X POST https://api.acedata.cloud/webextrator/render \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "wait_until": "networkidle",
    "block_resources": ["image", "media", "font"]
  }'

Python (requests)

import os, requests

API_KEY = os.environ["ACEDATA_API_KEY"]

resp = requests.post(
    "https://api.acedata.cloud/webextrator/render",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={
        "url": "https://example.com",
        "wait_until": "networkidle",
        "block_resources": ["image", "media", "font"],
    },
    timeout=60,
)
resp.raise_for_status()
data = resp.json()["data"]
print(data["title"], data["status"], len(data["html"]))

Node.js (fetch)

const apiKey = process.env.ACEDATA_API_KEY;

const res = await fetch('https://api.acedata.cloud/webextrator/render', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example.com',
    wait_until: 'networkidle',
    block_resources: ['image', 'media', 'font'],
  }),
});
const { data } = await res.json();
console.log(data.title, data.status, data.html.length);

Asynchronous + Callback

curl -X POST https://api.acedata.cloud/webextrator/render \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "async": true,
    "callback_url": "https://your-app.example.com/hooks/webextrator"
  }'

Immediately returns { "success": true, "task_id": "...", "trace_id": "...", "started_at": 1777717800.123 }; When the task is completed, the platform will POST the complete result to your callback_url.

Force Bypass Cache

curl -X POST https://api.acedata.cloud/webextrator/render \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "bypass_cache": true
  }'

Tips and Pitfalls

  • Choosing wait_until correctly is important. networkidle is the most stable but slowest; domcontentloaded is fast but may miss asynchronously injected content; load is suitable for traditional static pages.
  • Cache Key ignores async. Synchronous and asynchronous requests for the same URL hit the same cache entry, switching freely will not invalidate it.
  • Cache Key ignores bypass_cache and cache_ttl_seconds. These two are operational switches and do not affect the response content.
  • cookies and headers will bucket cache. Customizing these two will cause the first hit of the same combination to fail.
  • Heavy SPAs often exceed the default 30 seconds. It is recommended to use timeout: 60, wait_until: "domcontentloaded", delay: 4, and combine with wait_for_selector to wait for the elements of real concern.
  • block_resources is the fastest way to reduce latency. By default, images/fonts/media are blocked; if your extraction does not rely on CSS layout, adding stylesheet can make it even faster.