# Node.js'te SERP API: fetch, bir worker pool ve sayfalama

> Node.js 18+ üzerinden yerleşik fetch ile SerpCrypto SERP API'sini çağırın: tipli bir client, eşzamanlılık sınırınızın altında worker pool ve sayfalama döngüsü.

- URL: https://serpcrypto.com/tr/docs/node/
- Son güncelleme: 2026-10-22
- Yayıncı: SerpCrypto (https://serpcrypto.com)

Bağımlılık yok: Node.js, 18. sürümden beri `fetch` sunuyor. Editörler ve TypeScript için JSDoc tipli küçük bir client, hesabınızın sınırına uyan bir pool ve sonuçlar tükendiğinde duran bir sayfalama döngüsü.

**Hızlı yanıt — Node.js'te bir SERP API'yi nasıl kullanırım?**

`Authorization: Bearer <key>` header'ıyla `fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q }))` çağırın ve `await res.json()` okuyun. Node.js 18+ hiçbir paket gerektirmez. **SerpCrypto**, başarılı arama başına 1 kredi karşılığında Google veya Bing sonuçlarını JSON olarak döndürür, $0,30/1K arama itibarıyla başlar ve hatalar için asla ücret almaz. Kripto ile ödeme, KYC olmadan.

## Bir bakışta Node.js kurulumu

| Özellik | Değer |
| --- | --- |
| Çalışma zamanı | Node.js 18 veya üzeri (yerleşik `fetch`, `AbortSignal.timeout`) |
| Modüller | ES modülleri: `.mjs` dosyaları veya package.json içinde `"type": "module"` |
| Anahtar | `process.env.SERPCRYPTO_API_KEY` |
| Zaman aşımı | `AbortSignal.timeout(90_000)` ile 90 saniye |
| Paralel aramalar | `concurrency_limit` boyutuna göre ayarlanmış bir havuz |
| Türler | VS Code ve `tsc --checkJs` tarafından okunan JSDoc typedef'leri |

## Küçük, tipli bir client nasıl yazarım?

Endpoint'i, header'ı ve hata yönetimini tek bir modülde toplayın. JSDoc `@typedef` satırları yanıtı tanımlar, böylece editörler `organic_results` otomatik tamamlar ve kodunuzu derleme adımı olmadan tip kontrolünden geçirir. TypeScript kullanıcıları aynı şekilleri bir interface'e kopyalayabilir.

`search` fonksiyonu, mesajında HTTP durum kodu ve API'nin hata `code` bilgisini taşıyan bir `Error` fırlatır. Kodunuz ardından `429`, `502` ve `504` için yeniden denemeye, diğerlerinde durmaya karar verebilir; [hatalar sayfası](https://serpcrypto.com/tr/docs/errors/) bunu açıklıyor.

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

## 429'a takılmadan aramaları paralel nasıl çalıştırırım?

Hesabınızın izin verdiği kadar worker başlatın ve her biri paylaşılan listeden sıradaki anahtar kelimeyi alsın. Havuz, ücretsiz kredi endpoint'inden `concurrency_limit` okur, böylece hesabın kabul ettiğinden fazla aramayı aynı anda göndermez.

Başarısız olan anahtar kelime kaydedilir ve worker devam eder. Hataları sonradan yeniden çalıştırın: hatalar ücretsizdir, yani ikinci geçiş başarılı olana kadar ücretsizdir.

*batch.mjs: worker havuzu*

```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));
```

## Birden fazla sonuç sayfasını nasıl çekerim?

`page` üzerinde döngü kurun ve `pagination.next_page` eksik olduğunda durun. Google'ın Eylül 2025'te num=100 değerini dikkate almayı bırakmasından bu yana sunduğu gibi sayfa başına yaklaşık 10 organik sonuç; her ek sayfa bir kredi daha. Bir anahtar kelimenin üç sayfalık kontrolü üç kredi tutar; yalnızca tek sayfa sonucu olan bir anahtar kelime ise bir kredi tutar.

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

## API'yi tarayıcıdan veya edge function'dan çağırabilir miyim?

Bir sunucudan veya edge function'dan evet: Cloudflare Workers, Vercel ve Deno aynı `fetch` sağlar. Bir tarayıcı sayfasından hayır: API anahtarı her ziyaretçiye görünür olur. Araya anahtarı tutan ve yalnızca izin verdiğiniz parametreleri ileten küçük bir sunucu route'u koyun.

Aynı kural mobil uygulamalar için de geçerlidir. Kullanıcının cihazına gönderilen her şey okunabilir, bu yüzden API anahtarları sunucularınızda kalır.

## Node.js'te maliyetleri nasıl öngörülebilir tutarım?

Yaptığınız çağrıları sayın: başarılı bir çağrı bir kredidir, 100.000 arama paketinde $0,56/1K arama fiyatla. Büyük bir toplu işlemden önce `credits_remaining` kontrol edin ve havuzu sıfıra yaklaştığında durdurun; bir dizi `402` yanıtı toplamayın. Ön ödemeli arama kredileri hiçbir zaman sona ermez: kullanılmayan aramalar siz kullanana kadar hesabınızda kalır, böylece kullanılmayan bakiye sonraki iş için saklanır.

## Node.js soruları

### SerpCrypto için bir npm paketi var mı?

Hayır. Yukarıdaki client, `fetch` kullanan yaklaşık 40 satır standart JavaScript'tir, yani bizden kurulacak bir şey yok. Projenize kopyalayın ve uyarlayın.

### CommonJS (require) ile çalışır mı?

Örnekler, üst düzey `await` için ES modülleri kullanır. Bir CommonJS dosyasında çağrıları bir `async` fonksiyonu içine alın ve `fetch` aynı şekilde kullanın; Node.js 18+ sürümünde global'dir.

### TypeScript ile nasıl kullanırım?

JSDoc şekillerini bir `interface SearchResponse` içine kopyalayın ve `res.json()` sonucunu bununla tiplendirin. `organic_results?` gibi isteğe bağlı bloklar isteğe bağlı kalmalıdır, çünkü bir sayfa bunları göstermeyebilir.

### Hangi Node.js sürümüne ihtiyacım var?

Yerleşik `fetch` için Node.js 18 veya üzeri. `AbortSignal.timeout` Node.js 17.3'ten itibaren mevcuttur, yani 18 bu sayfadaki her şeyi kapsar.

---

SerpCrypto: SerpCrypto, Google ve Bing sonuçlarını JSON olarak döndüren, geliştiriciler ve AI agent'lar için bir SERP API'dir; kripto ile ödeme yapılır, kimlik yüklemek gerekmez. $0,30/1K arama ön ödemeli arama kredisinin süresi asla dolmaz. KYC olmadan — kimlik yok, selfie yok, belge yok. Kripto ile ödeme yapın.
