Migrating from ZenRows to Zyte API#

Learn how to migrate from ZenRows to Zyte API.

Feature comparison#

The following table summarizes the feature differences between both products:

Feature

Zyte API

ZenRows

API

HTTP or proxy

HTTP

Client software

Python, Scrapy

Python, NodeJS

Restricted website categories

None

Banks, payment gateways, visas/permits, government

Advanced ban avoidance

Always available, automatic

Only Business+, manual

Automatic extraction

AI-powered, standard schemas, supports crawling

Undocumented website support, item type support or output schema

Markdown output

No

Yes

Geolocation

249 countries, data center support

190 countries, no data center support

Sessions

Client-managed (15m) and server-managed

Client-managed only (10m), no cookies

Actions

Basic (15), advanced, website-specific and custom

Basic only (10)

Screenshots

JPEG/PNG, configurable viewport, cannot target element

PNG only, fixed viewport, can target element

Network capture

Up to 5 MiB / 10 responses

Unlimited

Network blocking

No

Yes

JavaScript disabling

Yes

No

Server-side CSS selectors

No

Yes

Rate limiting

RPM-based

Concurrency-based

Overuse handling

Rate-limiting responses

Rate-limiting responses followed by IP blocking

Usage data

UI only

UI and API

Automatic extraction#

ZenRows supports automatic extraction, but their documentation does not provide details on supported websites, item types or output schemas.

Zyte API automatic extraction is AI-based, i.e. it works on any website of a supported type (e.g. e-commerce, blogs/news, job postings), and we provide detailed documentation about output schemas. It also supports automatic crawling.

Sessions#

ZenRows only supports client-managed sessions, and limits them to 10 minutes. Moreover, their sessions do not maintain cookies, you must do that on the client side.

Zyte API allows 15 minutes for client-managed sessions, but also supports server-managed sessions with much longer lifetimes and an easier API. Moreover, the Scrapy plugin supports an additional session management API.

Screenshots#

Both ZenRows and Zyte API support PNG screenshots of the visible viewport or the full page.

ZenRows allows taking a screenshot of a specific element.

Zyte API allows configuring the browser viewport.

Zyte API can return both browserHtml and screenshot on the same request, i.e. get the browser HTML matching a given screenshot. In ZenRows you would need 2 separate requests, and the contents of each might not be a perfect match.

Rate limiting#

ZenRows limits the number of concurrent requests that you can send, starting at 10 with the most basic plan.

Zyte API limits the number of requests per minute (RPM) that you can send. It is 500 by default for all accounts, but you can get a higher limit for free.

For services like these that support advanced features like browser rendering or automatic extraction, which usually increase response times, RPM rate limiting allows you to maintain your throughput regardless of which features you use thanks to unlimited concurrency, while concurrency-based limits slow down your crawls as you use features that make requests slower.

For example, assuming an HTTP request takes 2 seconds and a browser request takes 20 seconds, switching from HTTP requests to browser requests with ZenRows would make your crawl 10 times slower, while Zyte API would allow you to maintain a similar crawl speed by using more concurrent requests to make up for the response time increase.

Overuse handling#

When you exceed your concurrency with ZenRows, they start by sending rate-limiting responses, but eventually they block your IP address for increasing amounts of time.

With Zyte API, reaching your rate limit is not only allowed, but encouraged, and you can request a higher RPM limit for free if you need it.

Migrating#

The main differences between the HTTP APIs of ZenRows and Zyte API are how request parameters are defined and how the response is encoded.

In ZenRows, you send a GET request, and you specify parameters in the URL query string, URL-encoded, e.g.

curl "https://api.zenrows.com/v1/?apikey=YOUR_API_KEY&url=https%3A%2F%2Ftoscrape.com"

The API response body comes straight from the target website:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Scraping Sandbox</title>

HTTP response headers from the target website are also received as regular headers, only prefixed with Zr-, and the response URL (which might not match the request URL, e.g. in case of redirection) is received as the special Zr-Final-Url header:

Zr-Content-Encoding: br
Zr-Content-Type: text/html
Zr-Final-Url: https://toscrape.com/

In Zyte API, you send a POST request, and you specify parameters in the request body as JSON, e.g.

curl \
    --user YOUR_API_KEY: \
    --header 'Content-Type: application/json' \
    --data '{"url": "https://toscrape.com", "httpResponseBody": true, "httpResponseHeaders": true}' \
    --compressed \
    https://api.zyte.com/v1/extract

The API response is a JSON object with all the response data from the target website:

{
    "url": "https://toscrape.com/",
    "statusCode": 200,
    "httpResponseBody": "PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KICAgIDx…",
    "httpResponseHeaders": [
        {
            "name": "content-type",
            "value": "text/html"
        },
        {
            "name": "content-encoding",
            "value": "br"
        }
    ]
}

Note

httpResponseBody is base64-encoded to support binary responses, like images or PDF files.

Once you understand how to migrate a simple request like the one above, you can migrate any other request the same way, replacing ZenRows parameters with Zyte API counterparts.

Parameter mapping#

ZenRows

Zyte API

(default)

httpResponseBody, httpResponseHeaders

apikey

Use basic authentication

url

url

js_render

browserHtml

custom_headers

customHttpRequestHeaders

premium_proxy

ipType=residential (not required to avoid bans)

proxy_country

geolocation (does not require ipType=residential)

session_id

session.id (must be UUID4)

device

device

original_status

N/A (see statusCode)

allowed_status_codes

N/A (see Bad website responses)

block_resources

Not supported

json_response

See Network capture

css_extractor

Not supported

autoparse

See Zyte API automatic extraction

markdown_response

Not supported

screenshot

screenshot

screenshot_fullpage

screenshotOptions.fullPage=true

screenshot_selector

Not supported

For parameters defining browser actions, see Action mapping.

Action mapping#

These are ZenRows actions and their Zyte API counterparts.
check: click
click: click
evaluate: evaluate
fill: type
scroll_x: scrollTo
scroll_y: scrollTo
select_option: select
uncheck: click
wait: waitForTimeout
wait_for: waitForSelector

wait_for only supports CSS selectors, while waitForSelector also supports XPath selectors.

ZenRows also has a solve_captcha action that requires you to specify which CAPTCHA you need to solve, while Zyte API avoids bans automatically, no action necessary.

The following Zyte API actions are not supported by ZenRows:
doubleClick
goto
hide
hover
keyPress
reload
scrollBottom
searchKeyword
setLocation
waitForNavigation
waitForRequest
waitForResponse

Zyte API also supports custom actions.

ZenRows actions have frame_-prefixed counterparts that work on iframes, and a utility action (frame_reveal) to inject iframe contents into the main DOM. On Zyte API you need to use custom actions to interact with iframes.