Bez KYC — bez dowodu, bez selfie, bez dokumentów. Płatność kryptowalutą: BTC, USDT, USDC, ETH, SOL, LTC
Język: Polski
Pobierz klucz API

Dokumentacja · Node.js 18+ · fetch · ESM

API SERP w Node.js: fetch, pula workerów i paginacja

Bez zależności: Node.js ma wbudowany fetch od wersji 18. Mały klient z typami JSDoc dla edytorów i TypeScript, pula respektująca limit twojego konta i pętla paginacji, która kończy się, gdy wyniki się skończą.

Ostatnia aktualizacja: · 4 min czytania

Szybka odpowiedź

Jak używać API SERP w Node.js?

Wywołaj fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q })) z nagłówkiem Authorization: Bearer <key> i odczytaj await res.json(). Node.js 18+ nie wymaga żadnego pakietu. SerpCrypto zwraca wyniki Google lub Bing jako JSON za 1 kredyt za udane wyszukiwanie, od 0,30 USD/1K wyszukiwań, i nigdy nie nalicza za błędy. Płatność kryptowalutą, bez KYC.

Konfiguracja Node.js w skrócie

Środowisko uruchomienioweNode.js 18 lub nowszy (wbudowany fetch, AbortSignal.timeout)
ModułyModuły ES: pliki .mjs lub "type": "module" w package.json
Kluczprocess.env.SERPCRYPTO_API_KEY
Limit czasu90 sekund z AbortSignal.timeout(90_000)
Równoległe wyszukiwaniaPula o rozmiarze concurrency_limit
TypyTypedefy JSDoc, odczytywane przez VS Code i tsc --checkJs

Jak napisać mały klient z typami?

Umieść endpoint, header i obsługę błędów w jednym module. Wiersze JSDoc @typedef opisują odpowiedź, więc edytory autouzupełniają organic_results i sprawdzają typy w Twoim kodzie bez kroku budowania. Użytkownicy TypeScript mogą skopiować te same kształty do interfejsu.

Funkcja search rzuca Error ze statusem HTTP i komunikatem błędu code z API. Twój kod może wtedy zdecydować o ponowieniu 429, 502 i 504 oraz o zatrzymaniu przy pozostałych, jak wyjaśnia strona błędów].

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

Jak uruchamiać wyszukiwania równolegle bez trafiania na 429?

Uruchom tyle workerów, ile pozwala Twoje konto, i pozwól każdemu pobierać kolejne słowo kluczowe ze współdzielonej listy. Pula odczytuje concurrency_limit z endpointu darmowych kredytów, więc nigdy nie wysyła naraz więcej wyszukiwań, niż akceptuje konto.

Nieudane słowo kluczowe jest zapisywane, a worker przechodzi dalej. Uruchom ponownie nieudane później: błędy nic nie kosztują, więc druga próba jest darmowa, dopóki się nie powiedzie.

batch.mjs: pula workerów
// 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));

Jak pobrać kilka stron wyników?

Iteruj po page i zatrzymaj się, gdy tylko zabraknie pagination.next_page. Około 10 wyników organicznych na stronę, tak jak Google serwuje od czasu, gdy we wrześniu 2025 przestało respektować num=100; każda dodatkowa strona to jeden kredyt więcej. Sprawdzenie trzech stron jednego słowa kluczowego kosztuje trzy kredyty; słowo kluczowe z tylko jedną stroną wyników kosztuje jeden.

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

Czy mogę wywoływać API z przeglądarki lub funkcji edge?

Z serwera lub funkcji edge — tak: Cloudflare Workers, Vercel i Deno zapewniają to samo fetch. Ze strony w przeglądarce — nie: klucz byłby widoczny dla każdego odwiedzającego. Wstaw między nimi małą trasę serwerową, która trzyma klucz i przekazuje tylko dozwolone parametry.

Ta sama zasada dotyczy aplikacji mobilnych. Wszystko, co trafia na urządzenie użytkownika, można odczytać, więc klucze zostają na Twoich serwerach.

Jak utrzymać przewidywalne koszty w Node.js?

Licz wykonywane wywołania: jedno udane wywołanie to jeden kredyt, po 0,56 USD/1K wyszukiwań w packu 100 000 wyszukiwań. Sprawdź credits_remaining przed dużym batchem i zatrzymaj pulę, gdy zbliża się do zera, zamiast zbierać serię odpowiedzi 402. Prepaid kredyty wyszukiwania nigdy nie wygasają: niewykorzystane wyszukiwania pozostają na Twoim koncie, dopóki ich nie wykorzystasz, więc niewykorzystana reszta zostaje na następne zadanie.

Pytania o Node.js

Czy istnieje pakiet npm dla SerpCrypto?

Nie. Powyższy klient to około 40 linii standardowego JavaScriptu korzystającego z fetch, więc nie ma niczego naszego do instalacji. Skopiuj go do swojego projektu i dostosuj.

Czy to działa z CommonJS (require)?

Przykłady używają modułów ES do await na najwyższym poziomie. W pliku CommonJS opakuj wywołania w funkcję async i używaj fetch w ten sam sposób; jest globalne w Node.js 18+.

Jak używać tego z TypeScript?

Skopiuj kształty JSDoc do interface SearchResponse i typuj nim wynik res.json(). Opcjonalne bloki, takie jak organic_results?, muszą pozostać opcjonalne, ponieważ strona może ich nie pokazywać.

Jakiej wersji Node.js potrzebuję?

Node.js 18 lub nowszego dla wbudowanego fetch. AbortSignal.timeout jest dostępne od Node.js 17.3, więc 18 obejmuje wszystko z tej strony.

Od 0,30 USD/1K wyszukiwań · bez KYC

Pobierz klucz API