# API SERP en Node.js : fetch, un pool de workers et pagination

> API SERP SerpCrypto depuis Node.js 18+ avec fetch : client typé, pool de workers sous votre limite de concurrence et boucle de pagination.

- URL: https://serpcrypto.com/fr/docs/node/
- Dernière mise à jour: 2026-10-22
- Éditeur: SerpCrypto (https://serpcrypto.com)

Aucune dépendance : Node.js dispose de `fetch` depuis la version 18. Un petit client avec des types JSDoc pour les éditeurs et TypeScript, un pool qui respecte la limite de votre compte, et une boucle de pagination qui s'arrête quand les résultats sont épuisés.

**Réponse rapide — Comment utiliser une API SERP en Node.js ?**

Appelez `fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q }))` avec le header `Authorization: Bearer <key>` et lisez `await res.json()`. Node.js 18+ ne nécessite aucun package. **SerpCrypto** renvoie les résultats Google ou Bing en JSON pour 1 crédit par recherche réussie, à partir de 0,30 $US/1K requêtes, et ne facture jamais les erreurs. Paiement en crypto, sans KYC.

## Configuration Node.js en un coup d'œil

| Attribut | Valeur |
| --- | --- |
| Runtime | Node.js 18 ou supérieur (`fetch`, `AbortSignal.timeout` intégrés) |
| Modules | Modules ES : fichiers `.mjs` ou `"type": "module"` dans package.json |
| Clé | `process.env.SERPCRYPTO_API_KEY` |
| Délai d'expiration | 90 secondes avec `AbortSignal.timeout(90_000)` |
| Recherches en parallèle | Un pool dimensionné sur `concurrency_limit` |
| Types | Typedefs JSDoc, lus par VS Code et `tsc --checkJs` |

## Comment écrire un petit client typé ?

Regroupez l'endpoint, le header et la gestion des erreurs dans un seul module. Les lignes JSDoc `@typedef` décrivent la réponse, si bien que les éditeurs complètent automatiquement `organic_results` et vérifient le typage de votre code sans étape de build. Les utilisateurs de TypeScript peuvent recopier les mêmes formes dans une interface.

La fonction `search` lève une `Error` avec le statut HTTP et le `code` d'erreur de l'API dans son message. Votre code peut ensuite décider de réessayer sur `429`, `502` et `504` et de s'arrêter sur les autres, comme l'explique la [page des erreurs](https://serpcrypto.com/fr/docs/errors/)].

*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();
}
```

## Comment lancer des recherches en parallèle sans déclencher de 429 ?

Lancez autant de workers que votre compte l'autorise et laissez chacun prendre le mot-clé suivant dans une liste partagée. Le pool lit `concurrency_limit` depuis l'endpoint des crédits gratuits, il n'envoie donc jamais plus de recherches simultanées que ce que le compte accepte.

Un mot-clé en échec est enregistré et le worker passe au suivant. Relancez les échecs ensuite : les erreurs ne coûtent rien, une seconde passe est donc gratuite jusqu'à la réussite.

*batch.mjs : un pool de 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));
```

## Comment récupérer plusieurs pages de résultats ?

Bouclez sur `page` et arrêtez-vous dès que `pagination.next_page` est absent. Environ 10 résultats organiques par page, comme Google les sert depuis qu'il n'honore plus num=100 en septembre 2025 ; chaque page supplémentaire coûte un crédit de plus. Une vérification sur trois pages pour un mot-clé coûte trois crédits ; un mot-clé qui n'a qu'une seule page de résultats coûte un crédit.

*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" }));
```

## Puis-je appeler l'API depuis un navigateur ou une edge function ?

Depuis un serveur ou une edge function, oui : Cloudflare Workers, Vercel et Deno fournissent tous le même `fetch`. Depuis une page de navigateur, non : la clé serait visible par tous les visiteurs. Placez entre les deux une petite route serveur qui détient la clé et ne transmet que les paramètres que vous autorisez.

La même règle s'applique aux applications mobiles. Tout ce qui est livré sur l'appareil d'un utilisateur peut être lu, donc les clés restent sur vos serveurs.

## Comment garder des coûts prévisibles en Node.js ?

Comptez les appels que vous faites : un appel réussi correspond à un crédit, à 0,56 $US/1K requêtes sur le pack 100 000 recherches. Vérifiez `credits_remaining` avant un gros batch et arrêtez le pool quand il approche de zéro plutôt que de récolter une série de réponses `402`. Les crédits de recherche prépayés n'expirent jamais : les requêtes inutilisées restent sur votre compte jusqu'à ce que vous les utilisiez, le reste inutilisé est donc conservé pour la tâche suivante.

## Questions Node.js

### Existe-t-il un package npm pour SerpCrypto ?

Non. Le client ci-dessus fait environ 40 lignes de JavaScript standard qui utilisent `fetch`, il n'y a donc rien de notre part à installer. Copiez-le dans votre projet et adaptez-le.

### Cela fonctionne-t-il avec CommonJS (require) ?

Les exemples utilisent les modules ES pour le `await` de premier niveau. Dans un fichier CommonJS, enveloppez les appels dans une fonction `async` et utilisez `fetch` de la même façon ; c'est global dans Node.js 18+.

### Comment l'utiliser avec TypeScript ?

Recopiez les formes JSDoc dans un `interface SearchResponse` et typez le résultat de `res.json()` avec. Les blocs optionnels comme `organic_results?` doivent rester optionnels, car une page peut ne pas les afficher.

### Quelle version de Node.js me faut-il ?

Node.js 18 ou ultérieur pour le `fetch` intégré. `AbortSignal.timeout` est disponible depuis Node.js 17.3, donc la 18 couvre tout ce qui figure sur cette page.

---

SerpCrypto: SerpCrypto est une API SERP pour les développeurs et les agents IA qui renvoie les résultats de recherche Google et Bing en JSON, payable en crypto sans envoi de pièce d'identité. Les crédits de recherche prépayés à partir de 0,30 $US/1K requêtes n'expirent jamais. Sans KYC — pas de pièce d'identité, pas de selfie, pas de documents. Payer en crypto.
