# API de SERP em Node.js: fetch, um worker pool e paginação

> Chame a API de SERP do SerpCrypto no Node.js 18+ com fetch embutido: client tipado, worker pool no limite de concorrência e loop de paginação.

- URL: https://serpcrypto.com/pt/docs/node/
- Última atualização: 2026-10-22
- Editor: SerpCrypto (https://serpcrypto.com)

Sem dependências: o Node.js tem `fetch` desde a versão 18. Um client pequeno com tipos JSDoc para editores e TypeScript, um pool que respeita o limite da sua conta e um loop de paginação que para quando os resultados acabam.

**Resposta rápida — Como uso uma API de SERP em Node.js?**

Chame `fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q }))` com o header `Authorization: Bearer <key>` e leia `await res.json()`. O Node.js 18+ não precisa de pacote. **SerpCrypto** retorna resultados do Google ou do Bing em JSON por 1 crédito por pesquisa bem-sucedida, a partir de US$ 0,30/1K pesquisas, e nunca cobra erros. Pagamento em cripto, sem KYC.

## Configuração do Node.js em resumo

| Atributo | Valor |
| --- | --- |
| Runtime | Node.js 18 ou posterior (`fetch`, `AbortSignal.timeout` embutidos) |
| Módulos | Módulos ES: arquivos `.mjs` ou `"type": "module"` no package.json |
| Chave | `process.env.SERPCRYPTO_API_KEY` |
| Tempo limite | 90 segundos com `AbortSignal.timeout(90_000)` |
| Pesquisas em paralelo | Um pool dimensionado para `concurrency_limit` |
| Tipos | typedefs JSDoc, lidos pelo VS Code e pelo `tsc --checkJs` |

## Como escrevo um pequeno cliente tipado?

Coloque o endpoint, o header e o tratamento de erros em um único módulo. As linhas `@typedef` do JSDoc descrevem a resposta, então os editores autocompletam `organic_results` e verificam os tipos do seu código sem etapa de build. Quem usa TypeScript pode copiar as mesmas formas para uma interface.

A função `search` lança um `Error` com o status HTTP e o `code` de erro da API na mensagem. Seu código pode então decidir repetir em `429`, `502` e `504` e parar nos demais, como explica a [página de erros](https://serpcrypto.com/pt/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();
}
```

## Como executo pesquisas em paralelo sem tomar 429?

Inicie tantos workers quanto sua conta permitir e deixe cada um pegar a próxima palavra-chave de uma lista compartilhada. O pool lê `concurrency_limit` do endpoint de créditos gratuitos, então nunca envia mais pesquisas ao mesmo tempo do que a conta aceita.

Uma palavra-chave que falha é registrada e o worker segue em frente. Reprocesse as falhas depois: erros não custam nada, então uma segunda passada é gratuita até dar certo.

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

## Como busco várias páginas de resultados?

Percorra `page` e pare assim que `pagination.next_page` estiver ausente. Cerca de 10 resultados orgânicos por página, como o Google vem entregando desde que deixou de respeitar num=100 em setembro de 2025; cada página extra é mais um crédito. Uma verificação de três páginas de uma palavra-chave custa três créditos; uma palavra-chave com apenas uma página de resultados custa um.

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

## Posso chamar a API a partir de um navegador ou de uma edge function?

De um servidor ou de uma edge function, sim: Cloudflare Workers, Vercel e Deno oferecem o mesmo `fetch`. De uma página no navegador, não: a chave ficaria visível para todos os visitantes. Coloque no meio uma pequena rota de servidor que guarda a chave e encaminha apenas os parâmetros que você permitir.

A mesma regra vale para apps mobile. Tudo o que vai para o dispositivo do usuário pode ser lido, então as chaves ficam nos seus servidores.

## Como mantenho os custos previsíveis em Node.js?

Conte as chamadas que faz: uma chamada bem-sucedida é um crédito, a US$ 0,56/1K pesquisas no pack 100.000 pesquisas. Verifique `credits_remaining` antes de um lote grande e pare o pool quando estiver perto de zero, em vez de acumular uma série de respostas `402`. Os créditos de pesquisa pré-pagos nunca expiram: as pesquisas não utilizadas ficam na sua conta até você usá-las, então o restante não usado fica para o próximo job.

## Perguntas sobre Node.js

### Existe um pacote npm do SerpCrypto?

Não. O cliente acima tem cerca de 40 linhas de JavaScript padrão usando `fetch`, então não há nada nosso para instalar. Copie para o seu projeto e adapte.

### Isso funciona com CommonJS (require)?

Os exemplos usam módulos ES para `await` no topo. Em um arquivo CommonJS, envolva as chamadas em uma função `async` e use `fetch` da mesma forma; ele é global no Node.js 18+.

### Como uso com TypeScript?

Copie as formas do JSDoc para uma `interface SearchResponse` e tipar o resultado de `res.json()` com ela. Blocos opcionais como `organic_results?` devem continuar opcionais, porque uma página pode não exibi-los.

### Qual versão do Node.js eu preciso?

Node.js 18 ou superior para o `fetch` nativo. `AbortSignal.timeout` está disponível a partir do Node.js 17.3, então o 18 cobre tudo nesta página.

---

SerpCrypto: O SerpCrypto é uma API de SERP para desenvolvedores e agentes de IA que retorna resultados de pesquisa do Google e do Bing em JSON, pago com cripto e sem envio de documento de identidade. Os créditos de pesquisa pré-pagos a partir de US$ 0,30/1K pesquisas nunca expiram. Sem KYC — sem documento, sem selfie, sem documentos. Pague com cripto.
