curl --request POST \
--url 'https://api.zenrows.com/v1/?apikey=' \
--header 'Content-Type: application/x-www-form-urlencoded'import requests
url = "https://api.zenrows.com/v1/?apikey="
payload = {}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({})
};
fetch('https://api.zenrows.com/v1/?apikey=', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const encodedParams = new URLSearchParams();
const url = 'https://api.zenrows.com/v1/?apikey=';
const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: encodedParams
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.zenrows.com/v1/?apikey="
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.zenrows.com/v1/?apikey=",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "",
CURLOPT_HTTPHEADER => [
"Content-Type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}require 'uri'
require 'net/http'
url = URI("https://api.zenrows.com/v1/?apikey=")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/x-www-form-urlencoded'
response = http.request(request)
puts response.read_bodyHttpResponse<String> response = Unirest.post("https://api.zenrows.com/v1/?apikey=")
.header("Content-Type", "application/x-www-form-urlencoded")
.asString();<!doctype html>
<html lang="en-US">
<head>
<title>Ecommerce Test Site to Learn Web Scraping</title>
</head>
<body>
<h1>Shop</h1>
...
</body>
</html>{
"code": "REQS004",
"instance": "/v1",
"status": 400,
"title": "Invalid value provided for 'js_render' parameter; invalid boolean value 'maybe' (REQS004)",
"type": "https://docs.zenrows.com/api-error-codes#REQS004"
}{
"code": "AUTH002",
"detail": "Invalid API key.",
"instance": "/v1",
"status": 401,
"title": "Invalid apikey provided (AUTH002)",
"type": "https://docs.zenrows.com/api-error-codes#AUTH002"
}{
"code": "AUTH004",
"detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
"instance": "/v1",
"status": 402,
"title": "Usage exceeded (AUTH004)",
"type": "https://docs.zenrows.com/api-error-codes#AUTH004"
}{
"code": "REQS007",
"detail": "Extract has not been prepared for example.org yet. Ask for it with POST /v1/extract/prepared-domains, then retry once it reports ready. GET /v1/extract/domains lists what Extract serves today.",
"instance": "/v1",
"status": 403,
"title": "Extract is not prepared for the requested domain (example.org) (REQS007)",
"type": "https://docs.zenrows.com/api-error-codes#REQS007"
}{
"code": "RESP001",
"detail": "The target could not be returned under this configuration. Try js_render=true and premium_proxy=true, or mode=auto.",
"instance": "/v1",
"status": 422,
"title": "Could not get content (RESP001)",
"type": "https://docs.zenrows.com/api-error-codes#RESP001"
}{
"code": "AUTH008",
"detail": "Every concurrency slot on the plan is in use. Retry when a request in flight finishes.",
"instance": "/v1",
"status": 429,
"title": "Concurrency limit reached (AUTH008)",
"type": "https://docs.zenrows.com/api-error-codes#AUTH008"
}Fetch a page with a POST
Send a POST to the target through Zenrows. Takes the same query parameters as fetchPage; the request body is forwarded to the target as is, and the response carries the target’s content.
curl --request POST \
--url 'https://api.zenrows.com/v1/?apikey=' \
--header 'Content-Type: application/x-www-form-urlencoded'import requests
url = "https://api.zenrows.com/v1/?apikey="
payload = {}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({})
};
fetch('https://api.zenrows.com/v1/?apikey=', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const encodedParams = new URLSearchParams();
const url = 'https://api.zenrows.com/v1/?apikey=';
const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: encodedParams
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.zenrows.com/v1/?apikey="
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.zenrows.com/v1/?apikey=",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "",
CURLOPT_HTTPHEADER => [
"Content-Type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}require 'uri'
require 'net/http'
url = URI("https://api.zenrows.com/v1/?apikey=")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/x-www-form-urlencoded'
response = http.request(request)
puts response.read_bodyHttpResponse<String> response = Unirest.post("https://api.zenrows.com/v1/?apikey=")
.header("Content-Type", "application/x-www-form-urlencoded")
.asString();<!doctype html>
<html lang="en-US">
<head>
<title>Ecommerce Test Site to Learn Web Scraping</title>
</head>
<body>
<h1>Shop</h1>
...
</body>
</html>{
"code": "REQS004",
"instance": "/v1",
"status": 400,
"title": "Invalid value provided for 'js_render' parameter; invalid boolean value 'maybe' (REQS004)",
"type": "https://docs.zenrows.com/api-error-codes#REQS004"
}{
"code": "AUTH002",
"detail": "Invalid API key.",
"instance": "/v1",
"status": 401,
"title": "Invalid apikey provided (AUTH002)",
"type": "https://docs.zenrows.com/api-error-codes#AUTH002"
}{
"code": "AUTH004",
"detail": "This account has used all its credits for the period. Upgrade or add credits to continue.",
"instance": "/v1",
"status": 402,
"title": "Usage exceeded (AUTH004)",
"type": "https://docs.zenrows.com/api-error-codes#AUTH004"
}{
"code": "REQS007",
"detail": "Extract has not been prepared for example.org yet. Ask for it with POST /v1/extract/prepared-domains, then retry once it reports ready. GET /v1/extract/domains lists what Extract serves today.",
"instance": "/v1",
"status": 403,
"title": "Extract is not prepared for the requested domain (example.org) (REQS007)",
"type": "https://docs.zenrows.com/api-error-codes#REQS007"
}{
"code": "RESP001",
"detail": "The target could not be returned under this configuration. Try js_render=true and premium_proxy=true, or mode=auto.",
"instance": "/v1",
"status": 422,
"title": "Could not get content (RESP001)",
"type": "https://docs.zenrows.com/api-error-codes#RESP001"
}{
"code": "AUTH008",
"detail": "Every concurrency slot on the plan is in use. Retry when a request in flight finishes.",
"instance": "/v1",
"status": 429,
"title": "Concurrency limit reached (AUTH008)",
"type": "https://docs.zenrows.com/api-error-codes#AUTH008"
}Authorizations
Fetch, Extract, Crawl and the account endpoint accept the key as the apikey query parameter. Keys are per account and self-serve: create one in the Zenrows dashboard (app.zenrows.com), or, for an agent with no human present, POST https://app.zenrows.com/api/agent/signup.
Query Parameters
The URL of the page to retrieve.
"https://www.scrapingcourse.com/ecommerce/"
Adaptive Stealth Mode. auto starts from the cheapest viable configuration and escalates to JavaScript rendering or premium proxies only when the target requires it. You are billed for the configuration that succeeds.
auto Render the page in a headless browser before returning it. Required for content that only exists after JavaScript runs.
JSON array of browser instructions (click, fill, scroll, wait) executed on the page before the content is returned. Requires js_render.
Forward your own request headers (cookies, referer) to the target.
Route the request through residential IPs. Required by most protected sites.
Two-letter country code for the exit IP. Requires premium_proxy.
^[a-z]{2}$"us"
Reuse the same IP across requests for up to 10 minutes. Any integer you choose identifies the session.
Return the target's own HTTP status code instead of the Zenrows one.
Comma-separated status codes whose body should be returned instead of raising an error, for example 404,500.
CSS selector to wait for before returning. Requires js_render.
Milliseconds to wait after load before returning. Requires js_render.
x >= 0Comma-separated resource types to block (for example image,media,font). Blocking is on by default.
Return a JSON envelope that also carries the network requests (XHR/fetch) the page made.
JSON object mapping output keys to CSS selectors, applied to the retrieved page.
"{\"title\":\"h1\",\"price\":\".price\"}"
Return structured JSON extracted from the page with no selectors to write (Extract). Omit it and Extract is off. auto and native return the website's own field names; standard returns a canonical schema shared by every website in a vertical (real estate only for now). Extract works on any prepared domain, with any active API key (prepare a new one with POST /extract/prepared-domains), and is currently free on top of the Fetch cost. A domain, or a kind of page on it, that is not prepared yet answers 403 REQS007: see requestExtractDomain.
auto, native, standard Comma-separated list of the fields extract should return, dot-notated for fields inside a group (for example products.name,products.price). Omit it to receive every field.
"products.name,products.price"
Deprecated in favour of Extract (extract=auto). Returns general-purpose JSON parsed from the page, not tailored to the website.
Convert the page before returning it: Markdown, plaintext or PDF.
markdown, plaintext, pdf Return an above-the-fold screenshot of the page. Requires js_render.
Return a full-page screenshot. Requires js_render.
Screenshot only the element matching this CSS selector. Requires js_render.
Screenshot image format.
png, jpeg JPEG quality, 1 to 100. Only with screenshot_format=jpeg.
1 <= x <= 100Comma-separated data types to pull out of the retrieved HTML (for example emails,phone_numbers).
Body
Forwarded to the target as is.
The body is of type object.
Response
The target's content, in the shape the request asked for: HTML by default, Markdown or plaintext with response_type, a PDF or PNG/JPEG binary for response_type=pdf and the screenshot parameters, and JSON for extract, css_extractor, autoparse or json_response.
The page as returned by the target.
Was this page helpful?