Hızlı başlangıç
Boş bir hesaptan ilk canlı sonuca üç adımda.
- Hesap oluşturun ve API anahtarları sayfasında bir anahtar alın. Anahtar yalnızca bir kez gösterilir; gizli anahtar deponuzda saklayın.
- İlk 100 aramanız ücretsizdir. Daha fazlası gerektiğinde Bakiye sayfasından kartla ya da USDT veya USDC ile bakiye yükleyin; fiyat ve maliyet hesaplayıcı fiyat sayfasında.
- Aşağıdaki isteği kendi anahtarınızla gönderin. Yanıt, o pazarın güncel Google sonuç kümesidir.
curl -X POST https://api.serper.live/v1/search \
-H "Authorization: Bearer sl_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"best coffee shops","country":"AE"}'
const response = await fetch('https://api.serper.live/v1/search', {
method: 'POST',
headers: {
Authorization: 'Bearer sl_live_YOUR_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'best coffee shops', country: 'AE' }),
signal: AbortSignal.timeout(100000),
});
const result = await response.json();
console.log(result.organic);
import requests
response = requests.post(
"https://api.serper.live/v1/search",
headers={"Authorization": "Bearer sl_live_YOUR_TOKEN"},
json={"query": "best coffee shops", "country": "AE"},
timeout=100,
)
print(response.json()["organic"])
<?php
$context = stream_context_create(['http' => [
'method' => 'POST',
'header' => "Authorization: Bearer sl_live_YOUR_TOKEN\r\nContent-Type: application/json",
'content' => json_encode(['query' => 'best coffee shops', 'country' => 'AE']),
'timeout' => 100,
]]);
$result = json_decode(file_get_contents('https://api.serper.live/v1/search', false, $context), true);
print_r($result['organic']);
Canlı arama genellikle 2–3 saniyede yanıt verir; bir pazara aradan sonra gönderilen ilk sorgu, orada yeni bir Google oturumu açılırken daha uzun sürer. Yavaş bir ilk sorgunun sizin tarafınızda asla başarısız olmaması için istemci zaman aşımını en az 100 saniye tutun.
Kimlik doğrulama
/v1/search adresine giden her istek anahtarınızı Authorization başlığında taşır:
Authorization: Bearer sl_live_YOUR_TOKEN
- Anahtarlar
sl_live_ile başlar ve API anahtarları sayfasında oluşturulur. Her uygulama için ayrı anahtar oluşturun; böylece birini iptal etmek diğerlerini etkilemez. - Anahtarları sunucunuzda tutun. Tarayıcıya, mobil uygulamaya veya herkese açık bir depoya asla koymayın.
- İptal edilen anahtar anında çalışmayı durdurur; isteklerinin geçmişi hesabınızda kalır.
| HTTP | Kod | Anlamı |
|---|---|---|
| 401 | unauthorized |
Authorization başlığı eksik. |
| 401 | invalid_token |
Anahtar hatalı biçimde, iptal edilmiş veya tanınmıyor. |
Arama
POST https://api.serper.live/v1/search
Tek bir canlı Google araması yapar ve organik sonuçları döndürür. İstek ve yanıt JSON'dır; istek gövdesi en fazla 16 KB olabilir.
İstek gövdesi
| Alan | Tür | Zorunlu | Açıklama |
|---|---|---|---|
query |
string | evet | 2–120 karakter. Boşluklar sıkıştırılır; kontrol karakterleri reddedilir. |
country |
string | evet | Pazarın iki harfli ISO kodu, örneğin AE. GET /v1/countries listesindeki kodlardan biri olmalıdır. |
language |
string | hayır | Google arayüz dili (hl), örneğin tr, en veya pt-BR. Varsayılan olarak ülkenin dili kullanılır. |
device |
string | hayır | desktop (varsayılan) veya mobile. Tarayıcı kimliğini ve dolayısıyla sonuç düzenini değiştirir. |
limit |
integer | hayır | Organik sonuç sayısı, 1–100. Varsayılan 10. Başlanan her 10'luk blok bir fiyat ayırır: limit 25 üç fiyat ayırır ve yalnızca sonuç alan bloklar ücretlendirilir. |
Yanıt
| Alan | Açıklama |
|---|---|
requestId |
Bu isteğin UUID değeri. Sorgu geçmişinizde görünür; bir sorun bildirirken bunu iletin. |
query, country, language, device |
Gerçekte kullanılan normalize edilmiş değerler. |
fetchedAt |
Canlı çekimin ISO 8601 zaman damgası. |
latencyMs |
Canlı aramanın milisaniye cinsinden süresi. |
pages |
Sonuç alan 10'luk sonuç blokları: istediğinizden fazla değil, Google hiçbir şey bulamadıysa 0. |
freePages |
Bu blokların kaçının hesabınızın ücretsiz aramalarıyla karşılandığı: bunlar bakiyeden önce kullanılır. |
price, currency |
Bu isteğin USD cinsinden sayı olarak maliyeti: pazar fiyatı çarpı ücretli bloklar (pages eksi freePages). Hiçbir şey bulunamadıysa ya da isteği ücretsiz aramalar karşıladıysa 0. |
organic[] |
Sıralama düzeninde organik sonuçlar: position, title, url, domain ve snippet. Google açıklama göstermiyorsa snippet değeri null olur. |
peopleAlsoAsk[] |
Google'ın "Diğer sorular" ("People also ask") bloğundaki sorular, sayfa sırasına göre düz metin olarak; Google göstermiyorsa boş dizi. |
relatedSearches[] |
Google'ın sonuçların altında önerdiği ilgili aramalar ("People also search for"), tekrarsız düz metin olarak; yoksa boş dizi. |
{
"requestId": "0199860b-2f4e-7a1c-9b3d-5e6f70819a2b",
"query": "best coffee shops",
"country": "AE",
"language": "en",
"device": "desktop",
"fetchedAt": "2026-09-28T14:00:00.000Z",
"latencyMs": 1873,
"pages": 1,
"freePages": 0,
"price": 0.005,
"currency": "USD",
"organic": [
{
"position": 1,
"title": "The 12 best coffee shops in town",
"url": "https://example.com/guides/best-coffee-shops",
"domain": "example.com",
"snippet": "A curated list of specialty coffee shops, updated every month."
},
{
"position": 2,
"title": "Coffee shops near me",
"url": "https://maps.example.org/coffee",
"domain": "maps.example.org",
"snippet": null
}
],
"peopleAlsoAsk": [
"What is the best coffee shop in town?",
"How much does a specialty coffee cost?"
],
"relatedSearches": [
"best coffee shops near me",
"specialty coffee roasters",
"coffee shop with wifi"
]
}
limit değerine ulaşılana kadar sonuç sayfaları boyunca toplanır; Google'ın kendi gezinme öğeleri ve tekrarlar dahil edilmez.Organik sonuçlar: organic[] alanları
organic[] dizisinin her öğesi, Google'ın gösterdiği sırayla tek bir organik sonuçtur. Google'ın kendi gezinme öğeleri ve tekrarlar dışarıda bırakılır; sonuçlar limit değerine ulaşılana kadar sonuç sayfaları boyunca toplanır.
Alanlar masaüstü ile mobil için ve her pazar için aynıdır:
| Alan | Tür | Açıklama |
|---|---|---|
position |
integer | Organik sonuçlar arasındaki sıra, 1'den limit değerine kadar (en fazla 100), Google'ın sonuç sayfaları boyunca kesintisiz sayılır. Yalnızca organik kayıtları sayar; bu yüzden bir sıralama takip aracının sakladığı sayı budur. |
title |
string | Sayfada gösterildiği haliyle sonucun başlığı. |
url |
string | Sonucun tam adresi. |
domain |
string | url alanının host kısmı, örneğin maps.example.org. Bir siteyi ararken bu alanı eşleştirin. |
snippet |
string veya null | Başlığın altında gösterilen açıklama; Google göstermiyorsa null. |
Ülkeler
GET https://api.serper.live/v1/countries
Herkese açıktır, anahtar gerekmez. Şu anda açık pazarları ve her birinin varsayılan Google dilini döndürür; her pazar hem desktop hem mobile destekler.
curl https://api.serper.live/v1/countries
const response = await fetch('https://api.serper.live/v1/countries');
const { countries } = await response.json();
console.log(countries);
import requests
response = requests.get("https://api.serper.live/v1/countries", timeout=10)
print(response.json()["countries"])
<?php
$result = json_decode(file_get_contents('https://api.serper.live/v1/countries'), true);
print_r($result['countries']);
{
"countries": [
{
"code": "AE",
"defaultLanguage": "ar"
},
{
"code": "AR",
"defaultLanguage": "es"
},
{
"code": "AT",
"defaultLanguage": "de"
},
{
"code": "AU",
"defaultLanguage": "en"
},
{
"code": "AZ",
"defaultLanguage": "az"
},
{
"code": "BE",
"defaultLanguage": "nl"
},
{
"code": "BG",
"defaultLanguage": "bg"
},
{
"code": "BR",
"defaultLanguage": "pt"
},
{
"code": "CA",
"defaultLanguage": "en"
},
{
"code": "CH",
"defaultLanguage": "de"
},
{
"code": "CL",
"defaultLanguage": "es"
},
{
"code": "CO",
"defaultLanguage": "es"
},
{
"code": "CZ",
"defaultLanguage": "cs"
},
{
"code": "DE",
"defaultLanguage": "de"
},
{
"code": "DK",
"defaultLanguage": "da"
},
{
"code": "EG",
"defaultLanguage": "ar"
},
{
"code": "ES",
"defaultLanguage": "es"
},
{
"code": "FI",
"defaultLanguage": "fi"
},
{
"code": "FR",
"defaultLanguage": "fr"
},
{
"code": "GB",
"defaultLanguage": "en"
},
{
"code": "GR",
"defaultLanguage": "el"
},
{
"code": "HU",
"defaultLanguage": "hu"
},
{
"code": "ID",
"defaultLanguage": "id"
},
{
"code": "IE",
"defaultLanguage": "en"
},
{
"code": "IN",
"defaultLanguage": "hi"
},
{
"code": "IT",
"defaultLanguage": "it"
},
{
"code": "JP",
"defaultLanguage": "ja"
},
{
"code": "KR",
"defaultLanguage": "ko"
},
{
"code": "KZ",
"defaultLanguage": "ru"
},
{
"code": "MX",
"defaultLanguage": "es"
},
{
"code": "NL",
"defaultLanguage": "nl"
},
{
"code": "NO",
"defaultLanguage": "nb"
},
{
"code": "PE",
"defaultLanguage": "es"
},
{
"code": "PL",
"defaultLanguage": "pl"
},
{
"code": "PT",
"defaultLanguage": "pt"
},
{
"code": "RO",
"defaultLanguage": "ro"
},
{
"code": "SA",
"defaultLanguage": "ar"
},
{
"code": "SE",
"defaultLanguage": "sv"
},
{
"code": "TH",
"defaultLanguage": "th"
},
{
"code": "TR",
"defaultLanguage": "tr"
},
{
"code": "UA",
"defaultLanguage": "uk"
},
{
"code": "US",
"defaultLanguage": "en"
},
{
"code": "VN",
"defaultLanguage": "vi"
},
{
"code": "ZA",
"defaultLanguage": "en"
}
]
}
Yeni pazarlar açıldıkça bu yanıtta ve fiyat sayfasında görünür. Kapalı bir pazar için istek, kullanılabilir kodların listesiyle birlikte 422 country_unavailable döndürür.
Ücretlendirme
Hesabınızda USD cinsinden ön ödemeli bir bakiye bulunur ve hesap 100 ücretsiz aramayla başlar. Her istek, arama başlamadan önce başlanan her 10'luk sonuç bloğu için pazarının güncel fiyatını ayırır: limit 10 veya altı bir fiyat, limit 25 üç fiyat ayırır. Ücretsiz aramalar, para ayrılmadan önce isteğin ilk bloklarını karşılar.
- Başarılı arama: sonuç alan her 10'luk blok için fiyat tahsil edilir; ayrılan tutarın kalanı hemen bakiyenize döner.
limit50 ve 12 sonuç beş değil iki fiyata mal olur; hiçbir şey bulamayan arama hiçbir şeye mal olmaz. - Ücretsiz aramalar: her yeni hesap, 10'luk sonuç bloğu başına bir tane olmak üzere 100 ücretsiz aramayla başlar; istediğiniz pazar ve cihazda geçerlidir. İstek bunları bakiyeden önce kullanır; sonuç almayan bloklar, paranın bakiyeye döndüğü gibi ücretsiz havuza döner. Yanıttaki
freePages, isteğin bu havuzdan kaç blok aldığını söyler. - Başarısız arama, yani
408,424veya herhangi bir5xxyanıtı: ayrılan tutar otomatik olarak serbest bırakılır. Almadığınız bir sonuç için asla ücret ödemezsiniz. - Fiyatlar zamanla değişebilir, ancak çalışan bir istek için ayrılan fiyat asla değişmez.
- Yetersiz bakiye:
402 insufficient_balance. Bakiye sayfasından yükleme yapın; yatırım onaylandıktan sonra bakiye dakikalar içinde kullanılabilir.
Her istek, durumu ve maliyeti Sorgu geçmişi sayfasında listelenir; her bakiye hareketi bakiye sayfasındaki hareket dökümündedir.
Hatalar
Hatalar makine tarafından okunabilir bir error kodu, okunabilir bir message ve istek oluşturulduysa requestId içeren JSON'dır:
{
"error": "insufficient_balance",
"message": "The balance does not cover one request",
"requestId": "0199860b-2f4e-7a1c-9b3d-5e6f70819a2b"
}
| HTTP | Kod | Anlamı | Tekrar? |
|---|---|---|---|
| 400 |
invalid_json
|
Gövde geçerli JSON değil. | İsteği düzeltin |
| 401 |
unauthorized
invalid_token
|
Kimlik doğrulama bölümüne bakın. | Anahtarı düzeltin |
| 402 |
insufficient_balance
|
Bakiye bir isteği karşılamıyor. | Yüklemeden sonra |
| 408 |
search_timeout
|
Arama 90 saniye içinde tamamlanmadı. | Evet |
| 409 |
idempotency_in_progress
idempotency_replay_unavailable
|
Güvenli yeniden denemeler bölümüne bakın. | Koda bağlı |
| 413 |
payload_too_large
|
Gövde 16 KB'yi aşıyor. | İsteği düzeltin |
| 422 |
invalid_request
country_unavailable
|
Bir alan doğrulamadan geçemedi (mesaj alanı belirtir) veya pazar açık değil. | İsteği düzeltin |
| 424 |
proxy_unavailable
captcha_failed
search_failed
|
Canlı arama bizim tarafımızda başarısız oldu. | Evet, kısa bir aradan sonra |
| 503 |
busy
billing_unavailable
configuration_error
|
Hizmet kapasite sınırında veya geçici olarak kullanılamıyor. | Evet, artan aralıklarla |
408, 424 veya 5xx yanıtı ücretlendirilmez. 408, 424 ve 503 için sıkı bir döngü yerine artan aralıklarla, örneğin 5, 15 ve 45 saniye sonra ve yeni bir Idempotency-Key ile yeniden deneyin: aynı anahtar 15 dakikaya kadar yeni bir arama başlatmak yerine aynı hatayı döndürür.Güvenli yeniden denemeler
İsteğe bağlıdır. Yalnızca istemciniz kesilen bir isteği yeniden deneyebiliyorsa gerekir.
Canlı arama 90 saniyeye kadar sürer. Bu sırada bağlantınız koparsa aramanın tamamlanıp ücretlendirildiğini bilemezsiniz. Idempotency-Key başlığı göndermek iki kez ödemeden yeniden denemenizi sağlar:
- Aynı anahtar: ilk arama tamamlandıysa aynı yanıtı
Idempotent-Replayed: truebaşlığıyla ve ikinci bir ücret olmadan alırsınız; başarısız olan bir arama aynı hatayı döndürür. Hâlâ çalışıyorsa yeniden deneme onu bekler. Anahtarı yalnızca sonucu almadığınızda, bağlantı koptuğunda veya istemci zaman aşımında yeniden kullanın; bir408,424veya5xxsonrasında yeni bir anahtar gönderin. - Aramayı yalnızca anahtar tanımlar: farklı gövdeyle yeniden deneme ilk isteğin yanıtını alır; yeni bir arama için yeni bir anahtar gönderin.
- Sonuçlar 15 dakikaya kadar saklanır. Sonrasında eski anahtarla yeniden deneme
409 idempotency_replay_unavailabledöndürür; yeni bir anahtarla yeni istek gönderin. - Başlık olmadan her istek yenidir ve ayrı ücretlendirilir.
curl -X POST https://api.serper.live/v1/search \
-H "Authorization: Bearer sl_live_YOUR_TOKEN" \
-H "Idempotency-Key: 0199860b-2f4e-7a1c-9b3d-5e6f70819a2b" \
-H "Content-Type: application/json" \
-d '{"query":"best coffee shops","country":"AE","limit":10}'
const response = await fetch('https://api.serper.live/v1/search', {
method: 'POST',
headers: {
Authorization: 'Bearer sl_live_YOUR_TOKEN',
'Idempotency-Key': '0199860b-2f4e-7a1c-9b3d-5e6f70819a2b',
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'best coffee shops', country: 'AE', limit: 10 }),
signal: AbortSignal.timeout(100000),
});
const result = await response.json();
import requests
response = requests.post(
"https://api.serper.live/v1/search",
headers={
"Authorization": "Bearer sl_live_YOUR_TOKEN",
"Idempotency-Key": "0199860b-2f4e-7a1c-9b3d-5e6f70819a2b",
},
json={"query": "best coffee shops", "country": "AE", "limit": 10},
timeout=100,
)
result = response.json()
<?php
$context = stream_context_create(['http' => [
'method' => 'POST',
'header' => "Authorization: Bearer sl_live_YOUR_TOKEN\r\nIdempotency-Key: 0199860b-2f4e-7a1c-9b3d-5e6f70819a2b\r\nContent-Type: application/json",
'content' => json_encode(['query' => 'best coffee shops', 'country' => 'AE', 'limit' => 10]),
'timeout' => 100,
]]);
$result = json_decode(file_get_contents('https://api.serper.live/v1/search', false, $context), true);
Anahtar, A-Za-z0-9._:- karakterlerinden oluşan 8–128 uzunluğunda herhangi bir dizedir. Her mantıksal istek için yeni bir UUID en basit seçimdir; o isteğin tüm yeniden denemelerinde aynı kalmalıdır.
Sınırlar ve bilinmesi gerekenler
query2–120 karakter,limit1–100, istek gövdesi en fazla 16 KB.- Aramalar hizmet kapasitesine kadar eşzamanlı çalışır; üzerinde
503 busyalırsınız. Artan aralıklarla yeniden deneyin. - 10 sonuç için genellikle 2–3 saniye, her ek sayfa için yaklaşık bir saniye daha; 90 saniye sonra hâlâ süren arama
408 search_timeoutile biter. İstemci zaman aşımınızı en az 100 saniye yapın. - Her yanıt bir
X-Request-Idbaşlığı taşır. GövdedekirequestIdile birlikte günlüklerinizde saklayın. - Hiçbir şey önbelleğe alınmaz: iki özdeş istek iki canlı arama ve iki ücrettir. Sonuçları yeniden kullanacaksanız kendi tarafınızda önbelleğe alın.
Bir alan adının sırasını bulma
API, limit değerine kadar organik sonuçları döndürür, varsayılan olarak ilk 10; içinde tek bir siteyi bulmak, kodunuzda organic[] üzerinde bir döngüdür. Her kaydın domain değerini izlediğiniz host adıyla karşılaştırın; ilk eşleşmenin position değeri, o anahtar kelime, ülke ve cihaz için sıradır. Aşağıdaki örnek tam olarak bunu yapar: aynı istek curl, JavaScript ve Python ile.
Karşılaştırmanın doğru kalması için üç kural:
- Karşılaştırmadan önce normalleştirin: iki tarafı da küçük harfe çevirin, baştaki
www.kısmını atın ve yalnızca host adlarını karşılaştırın, tam URL'leri asla. - Alt alan adlarının nasıl sayılacağına karar verin.
blog.example.com,example.comadresinden farklı bir host adıdır; katı bir takip aracı için host adını birebir eşleştirin, marka düzeyinde bir araç içinse.example.comile biten her host adını aynı site sayın. - Eşleşme olmaması, bu kontrol için istenen aralığın dışında demektir, hata değil. Öyle de kaydedin: bir istek en fazla
limitkadar organik sonuç döndürür; ilk 10'un ötesindeki sıraları izliyorsanızlimitdeğerini yükseltin (en fazla 100, her 10 için bir fiyat).
curl -s -X POST https://api.serper.live/v1/search \
-H "Authorization: Bearer sl_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"best coffee shops","country":"AE","device":"desktop"}' \
| jq '.organic[] | select(.domain == "example.com") | .position'
const response = await fetch('https://api.serper.live/v1/search', {
method: 'POST',
headers: {
Authorization: 'Bearer sl_live_YOUR_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: 'best coffee shops', country: 'AE', device: 'desktop' }),
signal: AbortSignal.timeout(100000),
});
const { organic } = await response.json();
const hit = organic.find(row => row.domain === 'example.com');
console.log(hit ? hit.position : 'outside the top 10');
import requests
response = requests.post(
"https://api.serper.live/v1/search",
headers={"Authorization": "Bearer sl_live_YOUR_TOKEN"},
json={"query": "best coffee shops", "country": "AE", "device": "desktop"},
timeout=100,
)
organic = response.json()["organic"]
position = next((row["position"] for row in organic if row["domain"] == "example.com"), None)
print(position or "outside the top 10")
<?php
$context = stream_context_create(['http' => [
'method' => 'POST',
'header' => "Authorization: Bearer sl_live_YOUR_TOKEN\r\nContent-Type: application/json",
'content' => json_encode(['query' => 'best coffee shops', 'country' => 'AE', 'device' => 'desktop']),
'timeout' => 100,
]]);
$result = json_decode(file_get_contents('https://api.serper.live/v1/search', false, $context), true);
$hit = array_find($result['organic'], fn(array $row) => $row['domain'] === 'example.com');
echo $hit['position'] ?? 'outside the top 10';
Sıralama takip API sayfası bir takip aracının tam döngüsünü anlatır: anahtar kelime listeleri, zamanlama, depolama ve bir aylık kontrolün maliyeti.
Yapay zekâ ajanlarıyla kullanın (MCP)
Serper.live MCP sunucusu, Claude, OpenAI Codex, Cursor ve VS Code Copilot gibi yapay zekâ ajanlarına bu API üzerinden canlı Google araması sağlar. npx ile yerelde çalışır, Node.js 20 veya üstünü gerektirir ve SERPER_LIVE_TOKEN ortam değişkenindeki aynı API anahtarıyla kimlik doğrular; aramalar POST /v1/search ile aynı şekilde ücretlendirilir.
google_search: bir anahtar kelime, ülke, dil ve cihaz için canlı organik sonuçlar, çağrı başına en fazla 100.domain_position: bir alan adının bir anahtar kelimede kaçıncı sırada olduğu; alt alan adı alan adının kendisi sayılır ve site birden fazla kez görünürse her sırası döndürülür.list_countries: açık pazarlar ve her birinin varsayılan Google dili; ücretsiz, anahtar gerekmez.
claude mcp add serper-live -e SERPER_LIVE_TOKEN=sl_live_YOUR_TOKEN -- npx -y @serper-live/mcp
{
"mcpServers": {
"serper-live": {
"command": "npx",
"args": [
"-y",
"@serper-live/mcp"
],
"env": {
"SERPER_LIVE_TOKEN": "sl_live_YOUR_TOKEN"
}
}
}
}
{
"inputs": [
{
"type": "promptString",
"id": "serper-live-token",
"description": "Serper.live API token",
"password": true
}
],
"servers": {
"serper-live": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@serper-live/mcp"
],
"env": {
"SERPER_LIVE_TOKEN": "${input:serper-live-token}"
}
}
}
}
[mcp_servers.serper-live]
command = "npx"
args = ["-y", "@serper-live/mcp"]
[mcp_servers.serper-live.env]
SERPER_LIVE_TOKEN = "sl_live_YOUR_TOKEN"
Paket npm'de @serper-live/mcp, resmî MCP Registry'de io.github.serper-live/serper-live-mcp adıyla yer alır; depodaki README diğer istemciler için kurulumu anlatır. Claude Desktop onu .mcpb paketinden tek tıkla da kurar ve API anahtarını kendisi sorar; Node.js gerekmez.