skills/scraperapi-nodejs-sdk/SKILL.md
Best-practices reference for the ScraperAPI Node.js / JavaScript SDK (scraperapi-sdk npm package). Consult whenever the user is writing, debugging, or reviewing JavaScript or TypeScript code that calls ScraperAPI. Use when user asks: "scrape a website with Node.js and ScraperAPI", "ScraperAPI JavaScript example", "how do I use scraperapi-sdk in Node", "ScraperAPI TypeScript", "ScraperAPI async await Node.js", "ScraperAPI POST request JavaScript", "Node.js ScraperAPI render", "ScraperAPI account info Node". Covers both CommonJS and ESM import styles, Promises and async/await, all request parameters, POST/PUT requests, account info, error handling, and credit costs.
npx skillsauth add scraperapi/scraperapi-skills scraperapi-nodejs-sdkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Requires: Node.js 14+, npm install scraperapi-sdk, SCRAPERAPI_API_KEY environment variable.
// CommonJS
const scraperapiClient = require('scraperapi-sdk')(process.env.SCRAPERAPI_API_KEY);
// ES Modules / TypeScript
import ScraperAPIClient from 'scraperapi-sdk';
const scraperapiClient = new ScraperAPIClient(process.env.SCRAPERAPI_API_KEY);
Never hardcode the API key. Read it from the environment every time.
| Situation | Pattern |
|-----------|---------|
| Single URL, result needed now | scraperapiClient.get(url) |
| 20+ URLs or batch work | Async Jobs API — fetch/axios to async.scraperapi.com/jobs |
| Supported platform (Amazon, Google, Walmart, eBay, Redfin) | Structured Data endpoint — api.scraperapi.com/structured/<vertical> |
| Page loads content via JavaScript | .get(url, { render: true }) |
| Site blocks datacenter proxies | .get(url, { premium: true }) |
| Need to POST a form or JSON body to the target | .post(url, options) |
// GET — returns HTML as a string (Promise-based)
const html = await scraperapiClient.get('https://example.com/');
// With parameters
const html = await scraperapiClient.get('https://example.com/', {
render: true,
country_code: 'us',
});
// Without async/await (Promise chain)
scraperapiClient.get('https://example.com/')
.then(html => console.log(html))
.catch(err => console.error(err));
// POST — forward a JSON body to the target site
const result = await scraperapiClient.post('https://example.com/api', {
body: JSON.stringify({ query: 'example' }),
headers: { 'Content-Type': 'application/json' },
});
// PUT — same signature, different HTTP method
const result = await scraperapiClient.put('https://example.com/resource', {
body: JSON.stringify({ name: 'updated' }),
headers: { 'Content-Type': 'application/json' },
});
// Render JavaScript before returning HTML
// Use when: page uses React/Vue/Angular, or initial scrape returns empty content
// Cost: +10 credits
const html = await scraperapiClient.get('https://spa-site.com/', { render: true });
// Wait for a specific element before capturing (requires render: true)
const html = await scraperapiClient.get('https://spa-site.com/', {
render: true,
wait_for_selector: '.product-list',
});
// Screenshot (auto-enables rendering)
const html = await scraperapiClient.get('https://example.com/', { screenshot: true });
Start without render: true. Add it only when the response is missing expected content.
// Route through a specific country — no extra credit cost
const html = await scraperapiClient.get('https://example.com/', { country_code: 'gb' });
// Premium residential/mobile proxies
// Cost: 10 credits (25 with render: true)
const html = await scraperapiClient.get('https://hard-site.com/', { premium: true });
// Ultra-premium — for the toughest anti-bot protections
// Cost: 30 credits (75 with render: true)
// Incompatible with custom headers — keep_headers is ignored when ultra_premium is set
const html = await scraperapiClient.get('https://hardest-site.com/', { ultra_premium: true });
premium and ultra_premium are mutually exclusive — never set both.
Escalation order: standard (1 cr) → render (10 cr) → premium (10 cr) → ultra_premium (30 cr).
// Reuse the same proxy IP across requests (same session_number = same IP)
// Sessions expire 15 minutes after last use
const page1 = await scraperapiClient.get('https://example.com/page1', { session_number: 42 });
const page2 = await scraperapiClient.get('https://example.com/page2', { session_number: 42 });
// Forward your own headers to the target site
// Note: keep_headers is ignored when ultra_premium: true
const html = await scraperapiClient.get('https://example.com/', {
keep_headers: true,
headers: { 'Accept-Language': 'en-US', 'Referer': 'https://google.com' },
});
// Emulate mobile or desktop browser
const html = await scraperapiClient.get('https://example.com/', { device_type: 'mobile' });
// Structured JSON for supported sites (Amazon, Google, etc.)
const data = await scraperapiClient.get('https://amazon.com/dp/B09V3KXJPB', { autoparse: true });
// Markdown — useful for LLM pipelines or documentation tools
const md = await scraperapiClient.get('https://docs.example.com/', { output_format: 'markdown' });
// Plain text
const text = await scraperapiClient.get('https://example.com/', { output_format: 'text' });
// Returns usage stats: concurrent request usage, total requests, account limits
const account = await scraperapiClient.account();
console.log(account);
Use this to monitor credit consumption and concurrency limits programmatically.
async function scrapeWithEscalation(url) {
const tiers = [
{}, // 1 credit
{ render: true }, // 10 credits
{ premium: true }, // 10 credits
{ premium: true, render: true }, // 25 credits
{ ultra_premium: true }, // 30 credits
];
for (const params of tiers) {
const html = await scraperapiClient.get(url, params);
if (html && html.includes('<html')) return html;
}
return null;
}
The sync SDK blocks on each call. For 20+ URLs, use the async endpoint directly to fan out jobs.
const API_KEY = process.env.SCRAPERAPI_API_KEY;
async function submitJob(url, apiParams = {}) {
const res = await fetch('https://async.scraperapi.com/jobs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: API_KEY, url, apiParams }),
});
return res.json(); // { id, status, statusUrl }
}
async function pollJob(job, maxWaitMs = 120_000, intervalMs = 5_000) {
const deadline = Date.now() + maxWaitMs;
while (Date.now() < deadline) {
const res = await fetch(job.statusUrl);
const data = await res.json();
if (data.status === 'finished') return data.response.body;
if (data.status === 'failed') throw new Error(`Job ${job.id} failed`);
await new Promise(r => setTimeout(r, intervalMs));
}
throw new Error(`Job ${job.id} timed out`);
}
// Batch — submit all, then collect
const urls = ['https://example.com/p1', 'https://example.com/p2'];
const jobs = await Promise.all(urls.map(submitJob));
const results = await Promise.all(jobs.map(pollJob));
For supported platforms, use structured endpoints instead of raw HTML — they return clean JSON without parsing logic.
async function structuredGet(vertical, params) {
const query = new URLSearchParams({ api_key: API_KEY, ...params });
const res = await fetch(`https://api.scraperapi.com/structured/${vertical}?${query}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json();
}
// Google SERP
const serp = await structuredGet('google/search', { query: 'javascript scraping' });
// Amazon product
const product = await structuredGet('amazon/product', { asin: 'B09V3KXJPB' });
// Walmart search
const items = await structuredGet('walmart/search', { query: 'standing desk' });
See structured data docs for all verticals and required fields.
async function safeScrape(url, params = {}) {
try {
return await scraperapiClient.get(url, params);
} catch (err) {
const status = err?.response?.status ?? err?.status;
if (status === 401) throw new Error('Invalid API key — check SCRAPERAPI_API_KEY');
if (status === 403) throw new Error('Blocked or out of credits — try premium or ultra_premium');
if (status === 429) throw new Error('Rate limit — reduce concurrency or switch to async');
if (status === 500 || status === 503) throw new Error('Transient error — retry with backoff');
throw err;
}
}
Status codes: 200 success, 401 bad key, 403 blocked/no credits, 404 not found (target), 429 rate limit, 500/503 transient (not charged, safe to retry).
| Request type | Credits |
|---|---|
| Standard | 1 |
| render: true | 10 |
| premium: true | 10 |
| premium: true + render: true | 25 |
| ultra_premium: true | 30 |
| ultra_premium: true + render: true | 75 |
development
SERP landscape analysis for SEO strategy decisions. Use this skill when the user wants to understand what a search results page actually looks like for their target keywords — including AI Overview presence and attribution, SERP feature composition, how Google is interpreting query intent, which competitors dominate specific keyword sets, and where organic rankings actually translate to visible traffic. Trigger on requests like "analyze the SERP for [keyword]," "why isn't my content getting traffic even though it ranks," "what does Google show for [keyword]," "which keywords are worth targeting," "is [keyword] dominated by AI Overviews," "who owns the SERP for [topic]," "SERP analysis," "keyword landscape," or any request to understand what's happening on a search results page before making a content or SEO strategy decision.
tools
Run a comprehensive SEO audit using ScraperAPI's live SERP and scraping tools — no setup required. Use this skill whenever the user wants to: audit SEO for a website, understand why a page isn't ranking, check SEO health, analyze keyword rankings, compare against competitors in search results, find content gaps, review on-page signals (titles, meta, headings, schema), diagnose a traffic drop, check indexation, or get prioritized SEO recommendations. Also trigger when the user says things like "why am I not showing up on Google," "my traffic dropped," "how do I rank for X," "what's wrong with my SEO," "SEO check," or "SEO review." This skill works out of the box — it uses the ScraperAPI MCP tools already connected to this session, with no CLI or API key setup needed.
development
Build and implement web scrapers using ScraperAPI. Use this skill whenever the user asks to build, write, create, or implement a scraper, or wants runnable code that extracts data from a website. Trigger on: "build me a scraper for [website]", "write a scraper that fetches product pages from [ecommerce site]", "I need to scrape [data] from [website]", "create a script that extracts [fields] from [URL]", "help me scrape [website] — I need [fields]", "write code to scrape [website]", "make a script that scrapes [website]", "implement a scraper for [URL]". Guides architectural decisions (structured endpoint vs. raw HTML, JS rendering, proxy tier, sync vs. async batch), then generates a complete runnable Python or Node.js script with retry logic, error handling, pagination, and credit estimation.
development
Use this skill whenever the user wants to check, track, or be alerted about product prices on Amazon, Walmart, or via Google Shopping. Trigger on: "monitor the price of this Amazon product", "did the price drop on [Walmart URL]?", "track these ASINs", "compare today's prices to last week", "alert me if [product] goes below $X", "what's the current price of [product]?", "check my price watchlist", "scrape the price of [URL]", "is [product] cheaper anywhere else?". Accepts ASINs, Amazon/Walmart product URLs, or free-text product queries for Google Shopping. Reads an optional baseline JSON file to detect changes, fetches live prices via ScraperAPI's structured endpoints, and reports increases, decreases, restocks, and out-of-stock transitions in a structured change report. Use this skill even when the user does not say the word "monitor" — any one-shot or recurring price-check request belongs here.