Reference
Read or export a rendered public page without launching a browser of your own.
POST /pages/snapshot and POST /pages/form-export are answered synchronously by the one Weles API process: a product sends a public HTTPS address and typed steps, Weles loads the page in its own browser and returns its text, structure and image, or the file the page downloads.
Why it exists#
Browsers belong to Weles. A product that needs a rendered page inside one of its own requests, such as a caption image a site draws or a competitor page read for research, calls these routes instead of starting Playwright or puppeteer itself. The browser, its network guard and its memory stay on the Weles host.
Requests#
Both routes take the general Weles API bearer (Authorization: Bearer <WELES_API_TOKEN>; the Skarbiec item echo-weles-api field token) and a JSON body. Common fields: url (required, public HTTPS without credentials or port), viewport { width, height } (required, positive integers in CSS pixels: the size the caller reads the page at; a request without it is refused with 'viewport: is required: give { width, height } in CSS pixels'), load_state one of domcontentloaded, load or networkidle (standard load), user_agent (optional text). No length or count is chosen by Weles; a viewport or value the browser cannot use comes back as its own refusal.
POST /pages/snapshot adds screenshot: none (standard), viewport or full. It answers data.text (the page's whole visible text), data.structured (title, description, canonical, language, robots, Open Graph, Twitter card, JSON-LD count, headings and their outline, navigation links, calls to action, forms with their fields, landmarks and design tokens: fonts, text and background colours, font sizes, border radii, every one the page holds) and data.screenshot (a lossless PNG as base64 of the mode asked for).
POST /pages/form-export adds fields, a list of { selector, value } filled in order, and click_text, the exact accessible name of the button that exports. It answers data.download with file_name, content_type, bytes and base64 of the whole file, taken from the page's own download, including a blob the page downloads through a generated link.
Every answer also carries final_url, status, viewport, load_state and refused_requests, the requests the page tried to make to a non-public address.
POST /pages/snapshot
{ "url": "https://example.com/", "viewport": { "width": <width>, "height": <height> }, "screenshot": "viewport" }
POST /pages/form-export
{ "url": "https://tokcomment.com/", "viewport": { "width": <width>, "height": <height> }, "load_state": "networkidle",
"fields": [{ "selector": "input[placeholder=\"Username\"]", "value": "wisent" },
{ "selector": "textarea", "value": "first!" }],
"click_text": "Export Image" }Network guard#
The target is admitted before a browser opens: its hostname must resolve only to public addresses, with the same ranges browser-evidence runs are held to (loopback, private, link-local, carrier-grade NAT, documentation, multicast and cloud-metadata names are refused). Every request the page makes afterwards is judged again by hostname; a request to a non-public or non-HTTPS address is aborted and listed in refused_requests.
Refusals and diagnosis#
Every refusal is { ok: false, code, error } with the code first in error.
401 unauthorized: no or wrong bearer. 500 missing_WELES_API_TOKEN: the process has no API bearer configured.
400 invalid_request: a field has the wrong shape (not text, not a positive integer, not one of the listed values, or missing); field names it, for example click_text or fields[2].selector.
422 target_refused: the url is not public HTTPS or resolves to a non-public address; error names the address or hostname.
429 pages_busy: as many pages are open as the host reports processors; open and limit give the count. Nothing is queued.
502 page_failed: the page answered a non-2xx status, no element matched a selector, no button carries click_text, or the download failed; error says which. 502 browser_failed: the browser itself failed; error carries its message.
Each request writes one JSON line event: page_route to the Weles API unit log with route, host, status, code, error and elapsed_ms, so a failing caller can be read on the host (stado service logs) without reproducing it.