Docs / Node.js

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);