Jawaban singkat
Bagaimana cara memakai SERP API di Node.js?
Panggil fetch("https://serpcrypto.com/api/v1/search?" + new URLSearchParams({ q })) dengan header Authorization: Bearer <key> dan baca await res.json(). Node.js 18+ tidak butuh paket. SerpCrypto mengembalikan hasil Google atau Bing sebagai JSON untuk 1 kredit per pencarian yang berhasil, mulai US$0,30/1K pencarian, dan tidak pernah menagih error. Bayar dengan kripto, tanpa KYC.
Setup Node.js sekilas
| Runtime | Node.js 18 atau lebih baru (bawaan fetch, AbortSignal.timeout) |
|---|---|
| Modul | ES modules: file .mjs atau "type": "module" di package.json |
| API key | process.env.SERPCRYPTO_API_KEY |
| Timeout | 90 detik dengan AbortSignal.timeout(90_000) |
| Pencarian paralel | Pool worker yang ukurannya disesuaikan dengan concurrency_limit |
| Types | Typedef JSDoc, dibaca oleh VS Code dan tsc --checkJs |
Bagaimana cara menulis client bertipe kecil?
Letakkan endpoint, header, dan penanganan error dalam satu modul. Baris JSDoc @typedef mendeskripsikan jawabannya, jadi editor bisa melengkapi organic_results secara otomatis dan memeriksa tipe kode Anda tanpa build step. Pengguna TypeScript bisa menyalin bentuk yang sama ke dalam sebuah interface.
Fungsi search melempar Error dengan status HTTP dan code error dari API di dalam pesannya. Kode Anda lalu bisa memutuskan untuk mencoba ulang 429, 502, dan 504 serta berhenti pada kode lainnya, seperti yang dijelaskan di halaman errors].
// 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();
}Bagaimana cara menjalankan pencarian secara paralel tanpa kena 429?
Jalankan sebanyak mungkin worker sesuai yang diizinkan akun Anda, dan biarkan masing-masing mengambil kata kunci berikutnya dari daftar bersama. Pool membaca concurrency_limit dari endpoint free credits, sehingga tidak pernah mengirim lebih banyak pencarian sekaligus daripada yang diterima akun.
Kata kunci yang gagal akan dicatat dan worker lanjut ke berikutnya. Jalankan ulang yang gagal setelahnya: error tidak memakan biaya, jadi pass kedua gratis sampai berhasil.
// 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));Bagaimana cara mengambil beberapa halaman hasil?
Looping pada page dan berhenti begitu pagination.next_page tidak ada. Sekitar 10 hasil organik per halaman, sebagaimana yang disajikan Google sejak berhenti mematuhi num=100 pada September 2025; setiap halaman tambahan dikenai satu kredit lagi. Pemeriksaan tiga halaman untuk satu kata kunci memakan tiga kredit; kata kunci yang hasilnya hanya satu halaman memakan satu kredit.
// 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" }));Bisakah saya memanggil API dari browser atau edge function?
Dari server atau edge function, bisa: Cloudflare Workers, Vercel, dan Deno semuanya menyediakan fetch yang sama. Dari halaman browser, tidak: API key akan terlihat oleh setiap pengunjung. Pasang route server kecil di antaranya yang menyimpan API key dan hanya meneruskan parameter yang Anda izinkan.
Aturan yang sama berlaku untuk aplikasi mobile. Apa pun yang dikirim ke perangkat pengguna bisa dibaca, jadi API key tetap di server Anda.
Bagaimana cara menjaga biaya tetap terprediksi di Node.js?
Hitung panggilan yang Anda lakukan: satu panggilan berhasil adalah satu kredit, dengan tarif US$0,56/1K pencarian pada paket 100.000 pencarian. Periksa credits_remaining sebelum batch besar dan hentikan pool saat mendekati nol daripada menampung rangkaian jawaban 402. Kredit pencarian prabayar tidak pernah kedaluwarsa: pencarian yang belum terpakai tetap ada di akun Anda sampai Anda menggunakannya, jadi sisa yang tidak terpakai disimpan untuk tugas berikutnya.
Pertanyaan Node.js
Apakah ada package npm untuk SerpCrypto?
Tidak. Client di atas hanya sekitar 40 baris JavaScript standar menggunakan fetch, jadi tidak ada milik kami yang perlu diinstal. Salin ke proyek Anda dan sesuaikan.
Apakah ini bisa dipakai dengan CommonJS (require)?
Contoh-contohnya menggunakan ES modules untuk await di level teratas. Di file CommonJS, bungkus panggilannya dalam fungsi async dan gunakan fetch dengan cara yang sama; ia bersifat global di Node.js 18+.
Bagaimana cara memakainya dengan TypeScript?
Salin bentuk JSDoc ke sebuah interface SearchResponse dan gunakan untuk memberi tipe pada hasil res.json(). Blok opsional seperti organic_results? harus tetap opsional, karena sebuah halaman mungkin tidak menampilkannya.
Versi Node.js apa yang saya butuhkan?
Node.js 18 atau lebih baru untuk fetch bawaan. AbortSignal.timeout tersedia mulai Node.js 17.3, jadi 18 mencakup semua yang ada di halaman ini.