KYC 없이 — 신분증, 셀피, 서류 없음. 암호화폐로 결제: BTC, USDT, USDC, ETH, SOL, LTC
언어: 한국어
API 키 발급

문서 · Node.js 18+ · fetch · ESM

Node.js에서의 SERP API: fetch, worker pool, 페이지네이션

의존성 없음: Node.js에는 버전 18부터 fetch가 내장되어 있습니다. 편집기와 TypeScript용 JSDoc 타입이 있는 작은 클라이언트, 계정 한도를 지키는 pool, 결과가 떨어지면 멈추는 페이지네이션 루프를 제공합니다.

마지막 업데이트: · 4 분 소요

빠른 답변

Node.js에서 SERP API를 어떻게 쓰나요?

헤더 Authorization: Bearer <key>와 함께 fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q }))을 호출하고 await res.json()를 읽으세요. Node.js 18+에서는 패키지가 필요 없습니다. SerpCrypto은 성공한 검색당 1 크레딧으로 Google 또는 Bing 결과를 JSON으로 반환하며, US$0.30/1K 검색부터 시작하고 오류는 절대 청구하지 않습니다. 암호화폐 결제, KYC 없이.

한눈에 보는 Node.js 설정

런타임Node.js 18 이상 (내장 fetch, AbortSignal.timeout)
모듈ES modules: .mjs 파일 또는 package.json의 "type": "module"
키process.env.SERPCRYPTO_API_KEY
타임아웃AbortSignal.timeout(90_000) 기준 90초
병렬 검색concurrency_limit에 맞춘 풀 크기
타입JSDoc typedef로, VS Code와 tsc --checkJs가 읽습니다

작은 타입 지정 클라이언트는 어떻게 작성하나요?

endpoint, header, 에러 처리를 하나의 모듈에 넣습니다. JSDoc @typedef 줄이 응답을 설명하므로, 에디터가 organic_results를 자동완성하고 빌드 단계 없이 코드를 타입 검사합니다. TypeScript 사용자는 동일한 형태를 interface에 복사할 수 있습니다.

search 함수는 HTTP 상태와 API의 에러 code를 메시지에 담아 Error를 던집니다. 그러면 코드에서 429, 502, 504은 재시도하고 나머지는 중단하도록 결정할 수 있습니다. errors 페이지]에서 설명합니다.

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

429를 맞지 않고 검색을 병렬로 실행하려면 어떻게 하나요?

계정이 허용하는 만큼 워커를 시작하고, 각 워커가 공유 목록에서 다음 키워드를 가져가게 하세요. 풀은 무료 크레딧 endpoint에서 concurrency_limit를 읽으므로, 계정이 허용하는 것보다 더 많은 검색을 동시에 보내지 않습니다.

실패한 키워드는 기록되고 워커는 넘어갑니다. 나중에 실패 항목을 다시 실행하세요. 에러는 비용이 들지 않으므로, 성공할 때까지 두 번째 실행은 무료입니다.

batch.mjs: 워커 풀
// 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));

여러 페이지의 결과를 어떻게 가져오나요?

page을 반복하면서 pagination.next_page가 없으면 중단합니다. 페이지당 약 10개의 유기적 결과로, Google이 2025년 9월 num=100을 더 이상 지원하지 않게 된 이후 제공되는 방식입니다. 추가 페이지마다 크레딧이 1개 더 차감됩니다. 한 키워드를 3페이지 확인하는 데 크레딧 3개가 들고, 결과가 1페이지뿐인 키워드는 크레딧 1개가 듭니다.

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

브라우저나 edge function에서 API를 호출할 수 있나요?

서버나 edge function에서는 가능합니다. Cloudflare Workers, Vercel, Deno 모두 동일한 fetch를 제공합니다. 브라우저 페이지에서는 안 됩니다. 키가 모든 방문자에게 노출되기 때문입니다. 키를 보관하고 허용한 파라미터만 전달하는 작은 서버 라우트를 중간에 두세요.

모바일 앱에도 같은 규칙이 적용됩니다. 사용자 기기로 전달된 것은 무엇이든 읽을 수 있으므로 키는 서버에 두세요.

Node.js에서 비용을 예측 가능하게 유지하려면 어떻게 하나요?

호출 수를 세세요. 성공한 호출 1건이 크레딧 1개이고, 검색 100,000회 팩에서 US$0.56/1K 검색입니다. 대량 배치 전에 credits_remaining를 확인하고, 402 응답이 연속으로 쌓이게 두지 말고 0에 가까워지면 풀을 중단하세요. 선불 검색 크레딧은 만료되지 않습니다: 사용하지 않은 검색은 사용할 때까지 계정에 남아 있습니다이므로 사용하지 않은 잔여분은 다음 작업을 위해 유지됩니다.

Node.js 관련 질문

SerpCrypto용 npm 패키지가 있나요?

없습니다. 위 클라이언트는 fetch를 사용하는 약 40줄의 표준 JavaScript이므로 설치할 것이 없습니다. 프로젝트에 복사해서 맞게 수정하세요.

CommonJS(require)에서도 작동하나요?

예제는 최상위 await를 위해 ES modules를 사용합니다. CommonJS 파일에서는 호출을 async 함수로 감싸고 fetch를 같은 방식으로 사용하세요. Node.js 18+에서는 전역입니다.

TypeScript에서 사용하려면 어떻게 하나요?

JSDoc 형태를 interface SearchResponse에 복사하고 res.json()의 결과에 타입을 지정하세요. organic_results? 같은 선택적 블록은 선택적으로 유지해야 합니다. 페이지에 표시되지 않을 수 있기 때문입니다.

어떤 Node.js 버전이 필요한가요?

내장 fetch를 위해서는 Node.js 18 이상이 필요합니다. AbortSignal.timeout은 Node.js 17.3부터 사용할 수 있으므로 18이면 이 페이지의 모든 것을 커버합니다.

US$0.30/1K 검색부터 · KYC 없이

API 키 발급