Node.js Integration Guide
Scrape anti-bot protected sites with Node.js. Uses native fetch (Node 18+) — no dependencies required.
Prerequisites: Node.js 18+ (for native fetch). Optional:
npm install cheerio for HTML parsing.
Sync Scraping
Scrape a single URL and get the HTML back immediately. No polling needed.
const response = await fetch(
"https://api.ultrawebscrapingapi.com/v1/scrape",
{
method: "POST",
headers: {
"X-API-Key": "your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: [{ url: "https://example.com" }],
mode: "sync",
}),
}
);
const data = await response.json();
console.log(data.html); Async Scraping
Submit multiple URLs, poll for completion, then fetch all results with Promise.all.
const API_KEY = "your_api_key";
const BASE = "https://api.ultrawebscrapingapi.com/v1";
// 1. Submit scrape job
const submitRes = await fetch(`${BASE}/scrape`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: [
{ url: "https://site-a.com/page1" },
{ url: "https://site-b.com/page2" },
{ url: "https://site-c.com/page3" },
],
mode: "async",
}),
});
const { subscriptionId } = await submitRes.json();
// 2. Poll for completion
const poll = async () => {
const res = await fetch(
`${BASE}/subscription/${subscriptionId}`,
{ headers: { "X-API-Key": API_KEY } }
);
return res.json();
};
let status = await poll();
while (status.processing > 0 || status.queued > 0) {
console.log(`Completed: ${status.completed}/${status.total}`);
await new Promise((r) => setTimeout(r, 5000));
status = await poll();
}
// 3. Fetch results
const results = await Promise.all(
status.jobs
.filter((j) => j.status === "completed")
.map((j) =>
fetch(`${BASE}/result/${subscriptionId}/${j.index}`, {
headers: { "X-API-Key": API_KEY },
}).then((r) => r.json())
)
);
for (const r of results) {
console.log(`${r.url} — ${r.html.length} chars`);
} Parse with Cheerio
Use Cheerio (jQuery-like API) to extract structured data from the scraped HTML.
import * as cheerio from "cheerio";
// Scrape the page
const response = await fetch(
"https://api.ultrawebscrapingapi.com/v1/scrape",
{
method: "POST",
headers: {
"X-API-Key": "your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: [{ url: "https://example.com/products" }],
mode: "sync",
}),
}
);
const { html } = await response.json();
// Parse with Cheerio
const $ = cheerio.load(html);
const products = [];
$(".product-card").each((_, el) => {
products.push({
name: $(el).find(".product-name").text().trim(),
price: $(el).find(".product-price").text().trim(),
url: $(el).find("a").attr("href"),
});
});
console.log(`Found ${products.length} products`);
products.forEach((p) => console.log(` ${p.name} — ${p.price}`)); Batch Scraping
A reusable function for batch scraping with controlled concurrency on result fetching.
const API_KEY = "your_api_key";
const BASE = "https://api.ultrawebscrapingapi.com/v1";
async function scrapeBatch(urls) {
// 1. Submit
const res = await fetch(`${BASE}/scrape`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: urls.map((url) => ({ url })),
mode: "async",
}),
});
const { subscriptionId } = await res.json();
// 2. Wait
let status;
do {
await new Promise((r) => setTimeout(r, 5000));
const pollRes = await fetch(
`${BASE}/subscription/${subscriptionId}`,
{ headers: { "X-API-Key": API_KEY } }
);
status = await pollRes.json();
} while (status.processing > 0 || status.queued > 0);
// 3. Fetch results (concurrent with limit)
const results = [];
const CONCURRENCY = 10;
const jobs = status.jobs.filter((j) => j.status === "completed");
for (let i = 0; i < jobs.length; i += CONCURRENCY) {
const batch = jobs.slice(i, i + CONCURRENCY);
const batchResults = await Promise.all(
batch.map((j) =>
fetch(`${BASE}/result/${subscriptionId}/${j.index}`, {
headers: { "X-API-Key": API_KEY },
}).then((r) => r.json())
)
);
results.push(...batchResults);
}
return results;
}
// Usage
const urls = [
"https://site-a.com/page1",
"https://site-a.com/page2",
"https://site-b.com/page1",
];
const results = await scrapeBatch(urls);
console.log(`Scraped ${results.length} pages`); Error Handling
Production-ready scraping with retry logic, rate limit backoff, and request timeouts.
async function scrapeWithRetry(url, apiKey, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 120_000);
const response = await fetch(
"https://api.ultrawebscrapingapi.com/v1/scrape",
{
method: "POST",
headers: {
"X-API-Key": apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: [{ url }],
mode: "sync",
}),
signal: controller.signal,
}
);
clearTimeout(timeout);
if (response.ok) return response.json();
if (response.status === 402) {
throw new Error("Insufficient credits");
}
if (response.status === 429) {
const wait = 2 ** attempt * 5000;
console.log(`Rate limited, waiting ${wait / 1000}s...`);
await new Promise((r) => setTimeout(r, wait));
continue;
}
if (response.status === 503) {
console.log("No capacity, retrying in 30s...");
await new Promise((r) => setTimeout(r, 30_000));
continue;
}
console.log(`Error ${response.status}: ${await response.text()}`);
} catch (err) {
if (err.name === "AbortError") {
console.log(`Timeout on attempt ${attempt + 1}`);
} else throw err;
}
}
throw new Error(`Failed after ${maxRetries} attempts`);
}
// Usage
const result = await scrapeWithRetry("https://example.com", "your_api_key");
console.log(result.html);