# SERP API in Node.js: fetch, een worker pool en paginering

> Roep de SerpCrypto SERP-API aan vanuit Node.js 18+ met fetch: een getypeerde client, een worker pool onder je concurrency limit en een pagineringsloop.

- URL: https://serpcrypto.com/nl/docs/node/
- Laatst bijgewerkt: 2026-10-22
- Uitgever: SerpCrypto (https://serpcrypto.com)

Geen dependency: Node.js heeft `fetch` sinds versie 18. Een kleine client met JSDoc-types voor editors en TypeScript, een pool die de limiet van je account respecteert, en een pagineringsloop die stopt als de resultaten op zijn.

**Snel antwoord — Hoe gebruik ik een SERP-API in Node.js?**

Roep `fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q }))` aan met de header `Authorization: Bearer <key>` en lees `await res.json()`. Node.js 18+ heeft geen package nodig. **SerpCrypto** geeft Google- of Bing-zoekresultaten als JSON voor 1 credit per geslaagde zoekopdracht, vanaf US$ 0,30/1K zoekopdrachten, en brengt errors nooit in rekening. Betalen met crypto, zonder KYC.

## Node.js-setup in één oogopslag

| Attribuut | Waarde |
| --- | --- |
| Runtime | Node.js 18 of later (ingebouwde `fetch`, `AbortSignal.timeout`) |
| Modules | ES modules: `.mjs`-bestanden of `"type": "module"` in package.json |
| Sleutel | `process.env.SERPCRYPTO_API_KEY` |
| Timeout | 90 seconden met `AbortSignal.timeout(90_000)` |
| Parallelle zoekopdrachten | Een pool afgestemd op `concurrency_limit` |
| Types | JSDoc-typedefs, gelezen door VS Code en `tsc --checkJs` |

## Hoe schrijf ik een kleine getypeerde client?

Zet het endpoint, de header en de foutafhandeling in één module. De JSDoc-regels `@typedef` beschrijven het antwoord, zodat editors `organic_results` automatisch aanvullen en je code type-checken zonder build-stap. TypeScript-gebruikers kunnen dezelfde shapes in een interface kopiëren.

De functie `search` gooit een `Error` met de HTTP-status en de fout-`code` van de API in het bericht. Je code kan dan beslissen om `429`, `502` en `504` opnieuw te proberen en bij de andere te stoppen, zoals de [foutenpagina](https://serpcrypto.com/nl/docs/errors/) uitlegt.

*serp-client.mjs*

```javascript
// serp-client.mjs — Node.js 18+, no dependency
const API_URL = "https://serpcrypto.com/api/v1/search";
const CREDITS_URL = "https://serpcrypto.com/api/v1/credits";
const headers = { Authorization: `Bearer ${process.env.SERPCRYPTO_API_KEY}` };

/**
 * @typedef {Object} OrganicResult
 * @property {number} position
 * @property {string} title
 * @property {string} link
 * @property {string} [snippet]
 * @property {string} [date]
 */

/**
 * @typedef {Object} SearchResponse
 * @property {Object} search_metadata
 * @property {string} search_metadata.id
 * @property {string} search_metadata.status
 * @property {number} search_metadata.credits_used
 * @property {OrganicResult[]} [organic_results]
 * @property {Object} [pagination]
 * @property {number} pagination.current
 * @property {number} [pagination.next_page]
 */

/**
 * Run one search (1 credit when it succeeds).
 * @param {string} q
 * @param {Record<string, string | number>} [params]
 * @returns {Promise<SearchResponse>}
 */
export async function search(q, params = {}) {
  const query = new URLSearchParams({ q, ...Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)])) });
  const res = await fetch(`${API_URL}?${query}`, { headers, signal: AbortSignal.timeout(90_000) });
  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    const err = new Error(`${res.status} ${body.error?.code ?? "error"}: ${body.error?.message ?? ""}`);
    err.status = res.status;
    throw err;
  }
  return res.json();
}

/** Free: credits left, used today and the concurrency limit. */
export async function credits() {
  const res = await fetch(CREDITS_URL, { headers });
  if (!res.ok) throw new Error(`credits: HTTP ${res.status}`);
  return res.json();
}
```

## Hoe voer ik zoekopdrachten parallel uit zonder een 429 te krijgen?

Start zoveel workers als je account toestaat en laat elke worker het volgende keyword uit een gedeelde lijst pakken. De pool leest `concurrency_limit` uit het endpoint voor gratis credits, zodat hij nooit meer zoekopdrachten tegelijk verstuurt dan het account accepteert.

Een mislukt keyword wordt vastgelegd en de worker gaat verder. Draai de mislukte opdrachten daarna opnieuw: fouten kosten niets, dus een tweede ronde is gratis tot het lukt.

*batch.mjs: een pool van workers*

```javascript
// batch.mjs — parallel searches, never more than the account's limit at once
import { search, credits } from "./serp-client.mjs";

const keywords = ["password manager", "note taking app", "time tracking software", "invoice software"];
const { concurrency_limit: limit } = await credits();

let next = 0;
const results = new Map();

async function worker() {
  while (next < keywords.length) {
    const kw = keywords[next++];
    try {
      const data = await search(kw, { gl: "us", hl: "en" });
      results.set(kw, data.organic_results?.[0]?.link ?? null);
    } catch (err) {
      results.set(kw, `failed: ${err.message}`);
    }
  }
}

await Promise.all(Array.from({ length: Math.min(limit, keywords.length) }, worker));
console.table(Object.fromEntries(results));
```

## Hoe haal ik meerdere pagina's met resultaten op?

Loop over `page` en stop zodra `pagination.next_page` ontbreekt. Ongeveer 10 organische resultaten per pagina, zoals Google levert sinds het in september 2025 stopte met num=100; elke extra pagina kost nog een credit. Een controle van drie pagina's voor één keyword kost drie credits; een keyword met maar één pagina aan resultaten kost één.

*pages.mjs*

```javascript
// pages.mjs — up to three pages, stop when results end
import { search } from "./serp-client.mjs";

async function topResults(q, pages = 3, params = {}) {
  const rows = [];
  for (let page = 1; page <= pages; page++) {
    const data = await search(q, { ...params, page });
    for (const r of data.organic_results ?? []) rows.push({ page, position: r.position, link: r.link });
    if (!data.pagination?.next_page) break; // nothing more: save the credits
  }
  return rows;
}

console.log(await topResults("headless cms", 3, { gl: "de", hl: "en" }));
```

## Kan ik de API aanroepen vanuit een browser of een edge function?

Vanuit een server of edge function wel: Cloudflare Workers, Vercel en Deno bieden allemaal dezelfde `fetch`. Vanuit een browserpagina niet: de API-sleutel zou zichtbaar zijn voor elke bezoeker. Zet ertussen een kleine server-route die de sleutel bevat en alleen de parameters doorstuurt die je toestaat.

Dezelfde regel geldt voor mobiele apps. Alles wat naar het apparaat van een gebruiker gaat, kan worden gelezen, dus sleutels blijven op je servers.

## Hoe houd ik de kosten voorspelbaar in Node.js?

Tel de calls die je doet: één geslaagde call is één credit, tegen US$ 0,56/1K zoekopdrachten op het 100.000 zoekopdrachten-pack. Controleer `credits_remaining` vóór een grote batch en stop de pool wanneer die bijna op nul staat, in plaats van een reeks `402`-antwoorden te verzamelen. Prepaid zoekcredits verlopen nooit: ongebruikte zoekopdrachten blijven op je account staan tot je ze gebruikt, dus een ongebruikt restant blijft bewaard voor de volgende klus.

## Node.js-vragen

### Is er een npm-package voor SerpCrypto?

Nee. De client hierboven is ongeveer 40 regels standaard JavaScript met `fetch`, dus er is niets van ons te installeren. Kopieer hem naar je project en pas hem aan.

### Werkt dit met CommonJS (require)?

De voorbeelden gebruiken ES modules voor top-level `await`. Wikkel in een CommonJS-bestand de calls in een functie `async` en gebruik `fetch` op dezelfde manier; die is globaal in Node.js 18+.

### Hoe gebruik ik het met TypeScript?

Kopieer de JSDoc-shapes naar een `interface SearchResponse` en typeer het resultaat van `res.json()` ermee. Optionele blokken zoals `organic_results?` moeten optioneel blijven, omdat een pagina ze niet altijd toont.

### Welke Node.js-versie heb ik nodig?

Node.js 18 of later voor de ingebouwde `fetch`. `AbortSignal.timeout` is beschikbaar vanaf Node.js 17.3, dus 18 dekt alles op deze pagina.

---

SerpCrypto: SerpCrypto is een SERP-API voor developers en AI-agents die Google- en Bing-resultaten als JSON retourneert, betaald met crypto zonder ID te uploaden. Prepaid zoekcredits vanaf US$ 0,30/1K zoekopdrachten verlopen nooit. Zonder KYC — geen ID, geen selfie, geen documenten. Betalen met crypto.
