# Webpagina naar Markdown in Node.js

> Converteer webpagina's naar Markdown in Node.js met fetch: één pagina en een crawl-pollingloop. Vanaf US$ 0,07/1K pagina's, zonder KYC, betalen met crypto.

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

Node.js 18 en later leveren `fetch` mee, dus je hebt helemaal geen dependency nodig. Drie recepten: één pagina lezen, een lijst lezen met een kleine concurrency-pool, en een crawl-job volgen tot die klaar is.

**Kort antwoord — Hoe converteer ik een webpagina naar Markdown in Node.js?**

Gebruik de ingebouwde `fetch` van Node.js 18+: roep `https://webreaderapi.com/api/v1/read?url=…` aan met je sleutel in de `Authorization`-header en lees `markdown` uit het JSON-antwoord. **WebReaderAPI** geeft de hoofdinhoud van de pagina terug met de titel, auteur en datum. Eén pagina kost 1 credit, 2 met een browser, vanaf US$ 0,07/1K pagina's per oktober 2026. Zonder KYC; betalen met crypto.

## Wat heb ik nodig?

Node.js 18 of later, voor de globale `fetch`, en een API-sleutel in de omgevingsvariabele `WEBREADER_API_KEY`. De voorbeelden zijn ES-modules: sla ze op met de extensie `.mjs`, of zet `"type": "module"` in je `package.json`, zodat top-level `await` werkt.

De JSDoc-comments beschrijven de vorm van het antwoord, zodat editors zoals VS Code je aanvulling geven zonder een TypeScript-buildstap.

*read.mjs: één pagina*

```javascript
/**
 * @typedef {Object} Page
 * @property {string} url
 * @property {string} final_url
 * @property {number} status_code
 * @property {boolean} rendered
 * @property {number} credits_used
 * @property {string} [title]
 * @property {string} [author]
 * @property {string} [published_at]
 * @property {string} [language]
 * @property {string} [markdown]
 * @property {number} word_count
 */

/** @returns {Promise<Page>} */
export async function readPage(url, options = {}) {
  const params = new URLSearchParams({ url, ...options });
  const res = await fetch(`https://webreaderapi.com/api/v1/read?${params}`, {
    headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
    signal: AbortSignal.timeout(75_000),
  });
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body.error.message), { code: body.error.code });
  return body;
}

const page = await readPage('https://example.com/docs/getting-started', { max_chars: '20000' });
console.log(page.title, page.word_count, 'words,', page.credits_used, 'credit(s)');

```

## Hoe lees ik een lijst met URL's zonder tegen de limiet aan te lopen?

Laat een vast aantal workers URL's uit een gedeelde queue halen. Dat is eenvoudiger dan `Promise.all` over de hele lijst, wat elk verzoek tegelijk zou starten en tegen `429 concurrency_limit` aan zou lopen. Elk account heeft een limiet voor het aantal pagina's dat het tegelijk leest; je dashboard toont die, en support kan hem verhogen.

De pool hieronder bewaart fouten naast de resultaten, zodat één geweigerde pagina de run niet stopt. Weigeringen zoals `blocked_by_robots` zijn definitief en gratis; tel ze en ga verder.

*pool.mjs: een lijst met URL's, 8 tegelijk*

```javascript
import { readPage } from './read.mjs';

export async function readAll(urls, workers = 8) {
  const queue = [...urls];
  const results = [];
  async function worker() {
    while (queue.length) {
      const url = queue.shift();
      try {
        const page = await readPage(url, { max_chars: '50000' });
        results.push({ url, page });
      } catch (err) {
        results.push({ url, error: err.code ?? err.name });
      }
    }
  }
  await Promise.all(Array.from({ length: workers }, worker));
  return results;
}

const urls = Array.from({ length: 30 }, (_, i) => `https://example.com/blog/post-${i + 1}`);
for (const r of await readAll(urls)) console.log(r.url, '->', r.error ?? r.page.title);

```

## Hoe volg ik een crawl-job in Node.js?

Start de job met `POST https://webreaderapi.com/api/v1/crawl` en lees dan `https://webreaderapi.com/api/v1/jobs/{job_id}` in een loop. Geef `cursor` mee telkens wanneer `next_cursor` terugkomt; als er geen cursor is en de status `done` is, is de job klaar. Wacht tussen lege polls en verdubbel de wachttijd tot 30 seconden, want een crawl die de Crawl-delay van een site respecteert kan traag zijn.

De [batch- en crawl-pagina](https://webreaderapi.com/nl/docs/crawl/) beschrijft hoe de crawl zijn pagina's kiest en hoe `limit` begrenst wat hij leest.

*crawl.mjs: start een crawl en verzamel elke pagina*

```javascript
const headers = {
  Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`,
  'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const start = await fetch('https://webreaderapi.com/api/v1/crawl', {
  method: 'POST',
  headers,
  body: JSON.stringify({ url: 'https://docs.example.com/', limit: 300, include_paths: ['/docs/*'] }),
});
const { job_id } = await start.json();

const pages = [];
let cursor = '';
let wait = 2000;
for (;;) {
  const url = `https://webreaderapi.com/api/v1/jobs/${job_id}${cursor ? `?cursor=${encodeURIComponent(cursor)}` : ''}`;
  const job = await (await fetch(url, { headers })).json();
  pages.push(...job.results.filter((r) => !r.error));
  if (job.next_cursor) {
    cursor = job.next_cursor;
    wait = 2000;
    continue;
  }
  if (job.status === 'done') break;
  await sleep(wait);
  wait = Math.min(wait * 2, 30000);
}
console.log(pages.length, 'pages read, job', job_id);

```

## Hoe geef ik het resultaat door aan een model?

Stuur de Markdown, niet de hele JSON. Het veld `markdown` is wat een model zou moeten lezen; de metadata kun je beter bewaren voor citaties. Zet de titel en `final_url` ervoor, zodat het model zijn bron kan noemen, en houd `max_chars` op een grootte die de context van je model aankan, zoals 20.000 tekens per pagina.

De [OpenAI function-calling-pagina](https://webreaderapi.com/nl/docs/openai/) laat de volledige tool-loop in Python zien; dezelfde `readPage`-functie hierboven kan dienen als de tool-body in een Node.js-agent.

## Node.js: veelgestelde vragen

### Werkt dit in Deno, Bun of de browser?

Deno en Bun ondersteunen dezelfde `fetch` en ES-modules. Roep de API niet aan vanuit een browserpagina: de sleutel zou zichtbaar zijn voor elke bezoeker. Roep hem aan vanuit je server.

### Is er een npm-package?

Nee. De functies op deze pagina zijn de hele integratie. WebReaderAPI is gewoon HTTPS en JSON, dus je houdt zelf controle over retries, timeouts en logging.

### Hoe ga ik om met 429 concurrency_limit?

Verlaag het aantal workers, of probeer het opnieuw na een korte wachttijd die elke keer verdubbelt. Een 429 kost niets, en de [errors-pagina](https://webreaderapi.com/nl/docs/errors/) heeft een kant-en-klare backoff-functie.

### Wat kost het lezen van 10.000 pagina's?

Ongeveer 10.000 credits voor gewone pagina's, meer als sommige een browser nodig hebben. 10.000 pagina's kosten US$ 3,75; Prepaid credits verlopen nooit: ongebruikte pagina's blijven op je account staan tot je ze gebruikt.

---

WebReaderAPI: WebReaderAPI is een web reader-API voor AI-agents die elke openbare webpagina omzet in schone Markdown, betaald met crypto zonder ID te uploaden. Prepaid credits vanaf US$ 0,07/1K pagina's verlopen nooit, en robots.txt wordt gerespecteerd. Zonder KYC — geen ID, geen selfie, geen documenten. Betalen met crypto.
