curl --request POST \
--url https://api.zenrows.com/v1/crawls \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"url": "https://www.scrapingcourse.com/ecommerce/"
}
'import requests
url = "https://api.zenrows.com/v1/crawls"
payload = { "url": "https://www.scrapingcourse.com/ecommerce/" }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({url: 'https://www.scrapingcourse.com/ecommerce/'})
};
fetch('https://api.zenrows.com/v1/crawls', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const url = 'https://api.zenrows.com/v1/crawls';
const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({url: 'https://www.scrapingcourse.com/ecommerce/'})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.zenrows.com/v1/crawls"
payload := strings.NewReader("{\n \"url\": \"https://www.scrapingcourse.com/ecommerce/\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
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/crawls",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'url' => 'https://www.scrapingcourse.com/ecommerce/'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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/crawls")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"url\": \"https://www.scrapingcourse.com/ecommerce/\"\n}"
response = http.request(request)
puts response.read_bodyHttpResponse<String> response = Unirest.post("https://api.zenrows.com/v1/crawls")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"url\": \"https://www.scrapingcourse.com/ecommerce/\"\n}")
.asString();{
"crawl_id": "c_01M3XP7RZD4JT88F7PNPGBFRAF",
"status": "running",
"url": "https://www.scrapingcourse.com/ecommerce/",
"max_items": 100,
"max_pages": 10,
"include_patterns": [
"/product/"
],
"exclude_patterns": [],
"discovery": [
"links"
],
"coverage": {
"pages_fetched": 0,
"pages_failed": 0,
"items_found": 0
},
"duplicates_removed": 0,
"created_at": "2026-10-09T09:00:12Z",
"results": [],
"next_cursor": "cur_Y18wMU0zWFA3UlpENEpUODhGN1BOUEdCRlJBRjow"
}{
"code": "unknown_parameter",
"title": "Unknown parameter",
"detail": "The request has a parameter this endpoint does not accept: max_depth.",
"status": 400,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"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": "idempotency_request_in_flight",
"title": "Request in flight",
"detail": "A request with this Idempotency-Key is still in progress. Retry when it ends.",
"status": 409,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"code": "invalid_start_url",
"title": "Invalid start URL",
"detail": "The start URL must be a public http or https URL.",
"status": 422,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"code": "too_many_crawls",
"title": "Too many active crawls",
"detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
"status": 429,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"code": "internal_error",
"title": "Internal error",
"detail": "Something failed on our side. Retry later.",
"status": 500,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}Start a crawl
Start a crawl from one URL and return at once with 202 Accepted, the crawl in the body and its path in the Location header. Each page it opens is one Fetch request with Adaptive Stealth Mode, billed 1 to 25 credits; failed pages are not billed. Documented at https://docs.zenrows.com/crawl/endpoints#start-a-crawl.
curl --request POST \
--url https://api.zenrows.com/v1/crawls \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"url": "https://www.scrapingcourse.com/ecommerce/"
}
'import requests
url = "https://api.zenrows.com/v1/crawls"
payload = { "url": "https://www.scrapingcourse.com/ecommerce/" }
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({url: 'https://www.scrapingcourse.com/ecommerce/'})
};
fetch('https://api.zenrows.com/v1/crawls', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));const url = 'https://api.zenrows.com/v1/crawls';
const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({url: 'https://www.scrapingcourse.com/ecommerce/'})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.zenrows.com/v1/crawls"
payload := strings.NewReader("{\n \"url\": \"https://www.scrapingcourse.com/ecommerce/\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
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/crawls",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'url' => 'https://www.scrapingcourse.com/ecommerce/'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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/crawls")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"url\": \"https://www.scrapingcourse.com/ecommerce/\"\n}"
response = http.request(request)
puts response.read_bodyHttpResponse<String> response = Unirest.post("https://api.zenrows.com/v1/crawls")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"url\": \"https://www.scrapingcourse.com/ecommerce/\"\n}")
.asString();{
"crawl_id": "c_01M3XP7RZD4JT88F7PNPGBFRAF",
"status": "running",
"url": "https://www.scrapingcourse.com/ecommerce/",
"max_items": 100,
"max_pages": 10,
"include_patterns": [
"/product/"
],
"exclude_patterns": [],
"discovery": [
"links"
],
"coverage": {
"pages_fetched": 0,
"pages_failed": 0,
"items_found": 0
},
"duplicates_removed": 0,
"created_at": "2026-10-09T09:00:12Z",
"results": [],
"next_cursor": "cur_Y18wMU0zWFA3UlpENEpUODhGN1BOUEdCRlJBRjow"
}{
"code": "unknown_parameter",
"title": "Unknown parameter",
"detail": "The request has a parameter this endpoint does not accept: max_depth.",
"status": 400,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"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": "idempotency_request_in_flight",
"title": "Request in flight",
"detail": "A request with this Idempotency-Key is still in progress. Retry when it ends.",
"status": 409,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"code": "invalid_start_url",
"title": "Invalid start URL",
"detail": "The start URL must be a public http or https URL.",
"status": 422,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"code": "too_many_crawls",
"title": "Too many active crawls",
"detail": "Your account already runs 3 active jobs. Wait for one to end, then start the crawl again.",
"status": 429,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}{
"code": "internal_error",
"title": "Internal error",
"detail": "Something failed on our side. Retry later.",
"status": 500,
"instance": "urn:zenrows:request:9ac5b40be6127c8809b91babda784059"
}Authorizations
Batch, Crawl, the Extract endpoints and the account endpoint read the same key from the X-API-Key header.
Headers
Makes a retry safe: a retry with the same key and body returns the same crawl and starts no second one. The same key with a different body is 422 idempotency_key_reused.
255Body
The start URL: a public http or https URL. The crawl starts on this exact URL and stays on its domain, subdomains included.
2048How many link steps to follow from the start URL. At 1, the links on the start page. Omit it to follow links until max_items or max_pages stops the crawl.
1 <= x <= 100000Stop after keeping this many URLs.
1 <= x <= 100000Stop after fetching this many pages. Caps what the crawl costs. If both limits are reached together, stop_reason is max_pages.
1 <= x <= 100000Keep, and open, only URLs that contain at least one of these texts, such as /product/. The start URL is never returned.
Drop URLs that contain any of these texts, even when they match an include pattern.
html also returns the HTML of each kept page. Omit it to get URLs only.
html Response
The crawl started.
A crawl, its coverage so far and one page of results.
completed: nothing was left to open, or a limit was reached (see stop_reason). stopped: you stopped it. failed: see error.
running, completed, stopped, failed Why the crawl ended early. Absent when nothing was left to open, and when the crawl failed.
max_items, max_pages, user Present only when status is failed. Older crawls can carry domain_not_allowed (the domain was not prepared for Extract).
Show child attributes
Show child attributes
The start URL: a public http or https URL. The crawl starts on this exact URL and stays on its domain, subdomains included.
2048How many link steps to follow from the start URL. At 1, the links on the start page. Omit it to follow links until max_items or max_pages stops the crawl.
1 <= x <= 100000Stop after keeping this many URLs.
1 <= x <= 100000Stop after fetching this many pages. Caps what the crawl costs. If both limits are reached together, stop_reason is max_pages.
1 <= x <= 100000Keep, and open, only URLs that contain at least one of these texts, such as /product/. The start URL is never returned.
Drop URLs that contain any of these texts, even when they match an include pattern.
html also returns the HTML of each kept page. Omit it to get URLs only.
html ["links"]: the crawl follows the links in each page's HTML. Older crawls can also list pagination.
links, pagination Show child attributes
Show child attributes
Links met again and dropped. Results never hold a duplicate.
Absent while the crawl runs.
Show child attributes
Show child attributes
Send it as cursor on the next read. Never null while the crawl runs; null once it has ended and its last results were read.
Was this page helpful?