Sem KYC — sem documento de identidade, sem selfie, sem documentos. Pague com cripto: BTC, USDT, USDC, ETH, SOL, LTC
Idioma: Português
Obter uma chave de API

Docs · Node.js 18+ · fetch · ESM

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

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.

Última atualização: · 5 min de leitura

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

RuntimeNode.js 18 ou posterior (fetch, AbortSignal.timeout embutidos)
MódulosMódulos ES: arquivos .mjs ou "type": "module" no package.json
Chaveprocess.env.SERPCRYPTO_API_KEY
Tempo limite90 segundos com AbortSignal.timeout(90_000)
Pesquisas em paraleloUm pool dimensionado para concurrency_limit
Tipostypedefs 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].

serp-client.mjs
// 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
// 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
// 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.

A partir de US$ 0,30/1K pesquisas · sem KYC

Obter uma chave de API