NEWScrapingAnt MCP for Claude Code, Cursor & Windsurf — try it free →
Skip to main content
Version: v2

Migration from ScraperAPI

Migrate from ScraperAPI to ScrapingAnt web scraping API with explicit request settings.

This guide covers synchronous HTML requests. It explains the request, response and retry changes needed to move an existing workload safely.

What is ScraperAPI?​

ScraperAPI is a web scraping API with browser rendering and proxy rotation capabilities. It's a low-code solution that allows you to scrape websites.

It does provide plenty of request customisation options along with a simple API.

What ScrapingAnt API could offer?​

ScrapingAnt is an alternative to ScraperAPI for teams evaluating browser rendering, proxy rotation and HTML or JSON scraping responses. It offers:

  • Paid plans with no concurrency cap; the free plan allows one concurrent request
  • Explicit datacenter or residential proxy selection
  • Browser rendering and custom in-page JavaScript
  • HTML and extended JSON response endpoints

Compare success rate, latency and cost per useful result on your own target pages before moving production traffic. Different providers' proxy tiers and browser behavior are not interchangeable.

Prerequisites​

To start the migration process you need to have:

Choose representative target pages that are safe to request repeatedly, and set the API key environment variables shown below before running examples.

tip

The free plan allows one active request. Queue requests sequentially and review credit costs before evaluating browser or residential proxy modes.

Contact us via support@scrapingant.com for pricing inquiries.

Migration process​

Step 1. Make API endpoint changes​

ScraperAPI's synchronous HTML endpoint is https://api.scraperapi.com. For ScrapingAnt, choose the response format your application needs:

These are alternatives for synchronous scraping. ScraperAPI's async jobs, structured extraction and rendering instruction sets need separate integration work; changing the endpoint alone does not migrate them.

Step 2. Make API request changes​

Both APIs accept the target url as a query parameter. Replace ScraperAPI's api_key with ScrapingAnt's x-api-key, using your ScrapingAnt key from the dashboard.

ScraperAPI's default is non-rendered HTML; enable rendering with render=true. ScrapingAnt's default is browser=true. Preserve a non-rendered workload by explicitly setting browser=false. The examples use query builders so a target URL containing its own query parameters stays intact:

curl --get 'https://api.scraperapi.com' --max-time 75 \
--data-urlencode "api_key=${SCRAPERAPI_API_KEY}" \
--data-urlencode 'url=https://example.com/?q=tea&sort=asc' \
--data-urlencode 'render=false'
curl --get 'https://api.scrapingant.com/v2/general' --max-time 45 \
--data-urlencode "x-api-key=${SCRAPINGANT_API_KEY}" \
--data-urlencode 'url=https://example.com/?q=tea&sort=asc' \
--data-urlencode 'browser=false' \
--data-urlencode 'proxy_type=datacenter' \
--data-urlencode 'timeout=30'

Set the relevant API key environment variable before running either example. For rendered pages, change render or browser to true explicitly. Rendering and proxy selection affect ScrapingAnt credit cost.

ScraperAPI parameterScrapingAnt alternativeMigration action
country_codeproxy_countryChoose a supported country from proxy settings, for example US. Every country in the documented proxy_country list works with both datacenter and residential proxies, at the normal credit cost for that proxy type, with no geotargeting surcharge.
premiumExplicit proxy_type choiceScraperAPI's premium pool includes residential/mobile IPs. Evaluate ScrapingAnt's residential mode if needed; the pools are not equivalent.
ultra_premiumNo direct equivalentThis enables ScraperAPI's advanced bypass tier. Do not translate it automatically to proxy_type=residential; test a deliberate browser/proxy configuration and its cost.
renderbrowserSet true or false explicitly because the defaults differ. See browser settings.
keep_headersHeaders prefixed with ant-Remove the flag and prefix each intended target header, for example ant-Accept-Language. See custom headers.
wait_for_selectorwait_for_selectorBoth use a selector wait with rendering enabled. Set browser=true and verify the selector and timing on the target. See selector waiting.

Check ScraperAPI's supported parameters, rendering and premium tiers against the full ScrapingAnt parameter reference.

Step 3. Test your changes and integration​

Check a representative target's content, cookies and status before switching production traffic. For each chosen configuration, record useful outputs, total charged credits including retries, and latency. Compare credits per useful result rather than treating every outer 200 as a useful page.

Keep the previous provider configuration available behind a provider-selection setting. Move a small batch of safe reads first; if expected fields, output quality or the credit budget fail your checks, stop the new queue and route subsequent work back to the previous integration. Avoid sending duplicate state-changing operations during a switch.

A successful /v2/general request returns outer HTTP 200 with the target status in Ant-page-status-code. On /v2/extended, check the outer HTTP status first, then read the target's JSON status_code and html. A target 403 or 404 in those fields is a separate result, not an API authentication error. See response formats and errors.

Use this retry policy for reads that are safe to repeat:

Outer API resultAction
403Stop. Inspect JSON detail locally for an invalid key, exhausted quota or IP restriction; fix that condition first.
404ScrapingAnt could not reach the site or the worker timed out (unreachable site). This is not a target 404 in Ant-page-status-code. The helpers stop here: check the URL's reachability, optional snippets/selectors and the API timeout before sending the request again.
409Queue free-plan work sequentially. A small delayed retry budget can handle an overlap.
423Detection: retry within a small budget, then review settings deliberately.
500A small delayed retry budget may handle a temporary server failure.
Redirects, validation errors, other statuses, network failure or client timeoutStop and diagnose. A timeout does not prove the server finished.

The examples below make at most three GET attempts, with increasing delays and jitter for outer 409, 423 and 500 only. Every attempt sends the same browser and proxy mode, extra API parameters and headers. Set browser=True / browser: true explicitly when rendering is needed. Review credit costs before choosing residential or rendering; there is no automatic mode upgrade.

ScrapingAnt charges no credits for a request when the ScrapingAnt API itself returns a non-200 status (failed, detected or any other error), so a retry that ends in an API error costs nothing. An outer 200 is charged even if the target page inside it is a 403, 404 or otherwise unusable. Each response's Ant-credits-cost header reports the credits spent; add it up across attempts to track the real cost of a job.

Python: install requests with python -m pip install requests, then save this helper in your script:

import random
import time
import requests

API_TIMEOUT = 30 # ScrapingAnt execution limit in seconds (documented range 5-60).
CLIENT_TIMEOUT = (5, API_TIMEOUT + 15) # Connect and read timeouts; read must exceed API_TIMEOUT.


class ScrapingAntError(RuntimeError):
def __init__(self, response, attempt):
self.status_code = response.status_code
try:
self.detail = response.json().get("detail")
except (ValueError, AttributeError):
self.detail = None
super().__init__(f"ScrapingAnt HTTP {self.status_code} after {attempt} attempt(s)")


def get_response(url, api_key, *, browser=False, proxy_type="datacenter", params=None, headers=None):
query = {
**(params or {}),
"url": url,
"x-api-key": api_key,
"browser": str(browser).lower(),
"proxy_type": proxy_type,
"timeout": API_TIMEOUT,
}
request_headers = dict(headers or {})
for attempt in range(1, 4):
try:
response = requests.get(
"https://api.scrapingant.com/v2/general",
params=query,
headers=request_headers,
timeout=CLIENT_TIMEOUT,
allow_redirects=False,
)
except requests.RequestException:
raise RuntimeError("Transport failure or timeout; check the outcome before retrying") from None
if response.status_code == 200:
return response
error = ScrapingAntError(response, attempt)
response.close()
if error.status_code not in (409, 423, 500) or attempt == 3:
raise error
time.sleep(2 ** (attempt - 1) + random.uniform(0, 0.25))


def page_html(response):
# Requests assumes ISO-8859-1 for text/* without a charset; default to UTF-8 instead.
has_charset = "charset=" in response.headers.get("Content-Type", "").lower()
encoding = response.encoding if has_charset and response.encoding else "utf-8"
return response.content.decode(encoding, errors="replace")

Set SCRAPINGANT_API_KEY in your environment, then call the helper. Pass other API parameters, such as proxy_country, wait_for_selector or js_snippet, in params (use a list, such as {"block_resource": ["image", "font"]}, to repeat a parameter), and ant- prefixed target headers in headers:

import os

response = get_response(
"https://example.com/?q=tea&sort=asc",
os.environ["SCRAPINGANT_API_KEY"],
browser=False,
params={"proxy_country": "US"},
headers={"ant-Accept-Language": "en-US"},
)
print("Target status:", response.headers.get("Ant-page-status-code"))
print("Credits charged:", response.headers.get("Ant-credits-cost"))
html = page_html(response)
# Check the target status and expected content before passing html to your parser.

JavaScript (Node.js 22+): built-in fetch needs no package installation. Save this helper in a .mjs file:

const API_TIMEOUT = 30; // ScrapingAnt execution limit in seconds (documented range 5-60).
const CLIENT_TIMEOUT_MS = (API_TIMEOUT + 15) * 1000; // Must exceed API_TIMEOUT.

async function getResponse(url, apiKey, {browser = false, proxyType = 'datacenter', params = {}, headers = {}} = {}) {
const endpoint = new URL('https://api.scrapingant.com/v2/general');
const fixed = {url, 'x-api-key': apiKey, browser: String(browser), proxy_type: proxyType, timeout: String(API_TIMEOUT)};
const query = new URLSearchParams();
for (const [name, value] of Object.entries(params)) {
if (name in fixed) continue;
for (const item of [].concat(value)) query.append(name, String(item)); // Arrays repeat the parameter.
}
for (const [name, value] of Object.entries(fixed)) query.set(name, value);
endpoint.search = query.toString();
const requestHeaders = {...headers};

for (let attempt = 1; attempt <= 3; attempt++) {
let response, body;
try {
response = await fetch(endpoint, {
method: 'GET',
headers: requestHeaders,
signal: AbortSignal.timeout(CLIENT_TIMEOUT_MS),
redirect: 'manual',
});
body = await response.text();
} catch {
throw new Error('Transport failure or timeout; check the outcome before retrying');
}
if (response.status === 200) {
return {
html: body,
targetStatus: response.headers.get('Ant-page-status-code'),
creditsCost: response.headers.get('Ant-credits-cost'),
};
}
const error = new Error(`ScrapingAnt HTTP ${response.status} after ${attempt} attempt(s)`);
error.status = response.status;
try { error.detail = JSON.parse(body).detail; } catch { /* Non-JSON gateway or redirect response. */ }
if (![409, 423, 500].includes(response.status) || attempt === 3) throw error;
await new Promise(resolve => setTimeout(resolve, (2 ** (attempt - 1) + Math.random() / 4) * 1000));
}
}

With SCRAPINGANT_API_KEY set, add this call and run the file with node your-file.mjs:

const result = await getResponse(
'https://example.com/?q=tea&sort=asc',
process.env.SCRAPINGANT_API_KEY,
{browser: false, params: {proxy_country: 'US'}, headers: {'ant-Accept-Language': 'en-US'}},
);
console.log('Target status:', result.targetStatus);
console.log('Credits charged:', result.creditsCost);
// Check targetStatus and expected content before passing result.html to your parser.

The query builder encodes the full target URL once, preserving its own &, +, % and fragment characters. API_TIMEOUT is sent as the timeout query parameter and limits API execution in seconds; the documented range is 5–60 seconds. The client limit is derived from it (API_TIMEOUT + 15) and must always be longer, otherwise your client can give up on a request that ScrapingAnt still completes and charges. Change API_TIMEOUT rather than passing timeout in params. Python's read timeout measures inactivity rather than a total wall-clock deadline; the JavaScript signal covers each attempt including body consumption.

A 3xx response from the API is treated as a non-retryable status error in both languages: Python disables redirect following and JavaScript uses redirect: 'manual'.

The error objects retain detail for diagnosis, while their messages omit the key and request URL. Redact detail before logging or sharing it. Avoid logging full requests or exception objects containing credentials or private target data.

Do not reuse this GET retry loop for state-changing POST, PUT, PATCH or DELETE requests, or for browser snippets that submit forms or otherwise change state. A timeout or server error does not establish whether the target operation already happened. Confirm its outcome or use a target-supported idempotency mechanism before repeating it. See request methods and safe retries.

Validate success, latency and billing on your own workload.

Further support​

For workload fit and commercial considerations, return to the ScraperAPI alternative comparison.

This document provides the basic information about the migration process from ScraperAPI to ScrapingAnt API.

We recommend checking the latest documentation for both APIs to have better overview across feature alternatives at ScrapingAnt.

Complex integrations could require additional support, so don't hesitate to reach us via support@scrapingant.com in case of any questions.

FAQ​

What is the difference between ScrapingAnt and ScraperAPI?​

ScrapingAnt is an alternative to ScraperAPI with its own set of features and technology wrapped in a simple API. It combines browser rendering and proxy rotation; results depend on the target and the settings you select.

Where can I find the full list of parameters for ScrapingAnt API?​

You can find the full list of parameters for ScrapingAnt API here.

Does ScrapingAnt provide libraries for different programming languages?​

Yes, ScrapingAnt provides libraries for different programming languages:

  • Python - Python client for ScrapingAnt API
  • JS - Javascript client for ScrapingAnt API

Does ScrapingAnt provide a free plan?​

Yes, ScrapingAnt provides a free plan with 10,000 API credits per month. You can subscribe to a free plan while registration process here.

Does ScrapingAnt bill for unsuccessful requests?​

ScrapingAnt charges no credits for a request when the ScrapingAnt API itself returns a non-200 status (failed, detected or any other error). An outer HTTP 200 is charged even when the target page inside it is a 403, 404 or otherwise unwanted, so inspect its status and content. Browser and proxy choices set the cost of each charged request; see credits.

Does ScrapingAnt limit the number of concurrent requests?​

Paid plans have no plan concurrency cap. The free plan allows one concurrent API request. Concurrency-limit errors return HTTP 409.

Parameter mappings checked against the linked official references on October 18, 2026. Recheck provider-specific options when updating your integration.