Démarrage rapide
Trois étapes entre un compte vide et votre premier résultat en direct.
- Créez un compte et un jeton dans Jetons API. Le jeton complet n’est affiché qu’une fois : conservez-le dans votre gestionnaire de secrets.
- Ajoutez du crédit en USDT ou USDC sur la page Solde. Une recherche en direct coûte $0.01.
- Envoyez la requête ci-dessous avec votre jeton. La réponse contient les résultats Google actuels pour ce marché.
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":"DE"}'
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: 'DE' }),
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": "DE"},
timeout=100,
)
print(response.json()["organic"])
Une recherche en direct répond généralement en 2–3 secondes ; la première requête vers un marché après une pause est plus longue, car une nouvelle session Google s’y ouvre. Gardez un délai d’attente client d’au moins 100 secondes pour qu’une première requête lente n’échoue jamais de votre côté.
Authentification
Chaque requête vers /v1/search transmet votre jeton dans l’en-tête Authorization :
Authorization: Bearer sl_live_YOUR_TOKEN
- Les jetons commencent par
sl_live_et se créent dans Jetons API. Créez un jeton par application pour pouvoir le révoquer sans toucher aux autres. - Gardez les jetons sur votre serveur. Ne les livrez jamais dans un navigateur, une application mobile ou un dépôt public.
- Un jeton révoqué cesse de fonctionner immédiatement ; l’historique de ses requêtes reste dans votre compte.
| HTTP | Code | Signification |
|---|---|---|
| 401 | unauthorized |
L’en-tête Authorization est absent. |
| 401 | invalid_token |
Le jeton est mal formé, révoqué ou inconnu. |
Recherche
POST https://api.serper.live/v1/search
Lance une recherche Google en direct et renvoie les résultats organiques. La requête et la réponse sont en JSON ; le corps de la requête est limité à 16 Ko.
Corps de la requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
query |
string | oui | De 2 à 120 caractères. Les espaces multiples sont réduits à un seul ; les caractères de contrôle sont rejetés. |
country |
string | oui | Code ISO à deux lettres du marché, par exemple DE. Doit figurer parmi les codes de GET /v1/countries. |
language |
string | non | Langue de l’interface Google (hl), par exemple tr, en ou pt-BR. Par défaut, la langue du pays. |
device |
string | non | desktop (par défaut) ou mobile. Change le profil de navigateur et donc la mise en page des résultats. |
limit |
integer | non | Nombre de résultats organiques, de 1 à 100. 10 par défaut. Chaque bloc de 10 entamé coûte un prix du marché : limit 25 réserve trois prix. |
Réponse
| Champ | Description |
|---|---|
requestId |
UUID de cette requête. Il apparaît dans votre historique des requêtes ; indiquez-le lorsque vous signalez un problème. |
query, country, language, device |
Les valeurs normalisées réellement utilisées. |
fetchedAt |
Horodatage ISO 8601 de la récupération en direct. |
latencyMs |
Durée de la recherche en direct, en millisecondes. |
pages |
Blocs de 10 résultats facturés : au moins un, jamais plus que demandé. |
price, currency |
Coût de cette requête, sous forme de nombre en USD : le prix du marché multiplié par pages. |
organic[] |
Résultats organiques dans l’ordre du classement : position, title, url, domain et snippet. snippet vaut null lorsque Google n’affiche aucune description. |
{
"requestId": "0199860b-2f4e-7a1c-9b3d-5e6f70819a2b",
"query": "best coffee shops",
"country": "DE",
"language": "en",
"device": "desktop",
"fetchedAt": "2026-09-28T14:00:00.000Z",
"latencyMs": 1873,
"price": 0.01,
"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
}
]
}
limit, sans les entrées de navigation propres à Google et sans doublons.Résultats organiques : les champs de organic[]
Chaque élément de organic[] est un résultat organique, dans l’ordre où Google les affiche. Les entrées de navigation propres à Google et les doublons sont écartés, et les résultats sont collectés sur plusieurs pages de résultats jusqu’à atteindre limit.
Les champs sont les mêmes sur ordinateur et sur mobile, et pour chaque marché :
| Champ | Type | Description |
|---|---|---|
position |
integer | Le rang parmi les résultats organiques, de 1 jusqu’à limit (100 au maximum), compté en continu sur les pages de résultats de Google. Seules les entrées organiques sont comptées : c’est le nombre qu’un outil de suivi de positions enregistre. |
title |
string | Le titre du résultat tel qu’il apparaît sur la page. |
url |
string | L’adresse complète du résultat. |
domain |
string | La partie hôte de url, par exemple maps.example.org. Comparez ce champ lorsque vous cherchez un site. |
snippet |
string ou null | La description affichée sous le titre ; null lorsque Google n’en affiche aucune. |
Pays
GET https://api.serper.live/v1/countries
Public, sans jeton. Renvoie les marchés ouverts en ce moment et la langue Google par défaut de chacun ; chaque marché prend en charge desktop et mobile.
curl https://api.serper.live/v1/countries
{
"countries": [
{
"code": "DE",
"defaultLanguage": "de"
},
{
"code": "FR",
"defaultLanguage": "fr"
},
{
"code": "GB",
"defaultLanguage": "en"
},
{
"code": "TR",
"defaultLanguage": "tr"
},
{
"code": "UA",
"defaultLanguage": "uk"
},
{
"code": "US",
"defaultLanguage": "en"
}
]
}
Marchés ouverts en ce moment, avec la langue d’interface Google utilisée lorsque language est omis :
| Marché | Code | Langue par défaut | Prix par requête | Statut |
|---|---|---|---|---|
| Allemagne | DE |
Allemand | $0.01 | En direct |
| France | FR |
Français | $0.01 | En direct |
| Royaume-Uni | GB |
Anglais | $0.01 | En direct |
| Turquie | TR |
Turc | $0.012 | En direct |
| Ukraine | UA |
Ukrainien | $0.01 | En direct |
| États-Unis | US |
Anglais | $0.0125 | En direct |
Ouverts actuellement : Allemagne, France, Royaume-Uni, Turquie, Ukraine et États-Unis. Les nouveaux marchés apparaissent ici et sur la page des tarifs dès leur lancement. Une requête pour un marché fermé renvoie 422 country_unavailable avec la liste des codes disponibles.
Facturation
Votre compte détient un solde prépayé en USD. Avant le lancement de la recherche, chaque requête réserve le prix actuel de son marché pour chaque bloc de 10 résultats entamé : limit 10 ou moins réserve un prix, limit 25 en réserve trois.
- Recherche réussie : le prix est facturé pour chaque bloc de 10 qui a reçu des résultats, au moins un, et le reste de la réservation revient aussitôt sur votre solde.
limit50 avec 12 résultats coûte deux prix, pas cinq. - Recherche échouée, c’est-à-dire toute réponse
408,424ou5xx: la réservation est libérée automatiquement. Vous ne payez jamais un résultat que vous n’avez pas reçu. - Les prix peuvent évoluer, mais le prix réservé pour une requête en cours ne change jamais.
- Crédit insuffisant :
402 insufficient_balance. Rechargez sur la page Solde ; le crédit est disponible quelques minutes après la confirmation du dépôt.
Chaque requête, son statut et son coût figurent dans l’historique des requêtes ; chaque mouvement du solde figure dans le journal de la page Solde.
Erreurs
Les erreurs sont en JSON, avec un code error lisible par une machine, un message lisible par un humain et, dès qu’une requête a été créée, son requestId :
{
"error": "insufficient_balance",
"message": "The balance does not cover one request",
"requestId": "0199860b-2f4e-7a1c-9b3d-5e6f70819a2b"
}
| HTTP | Code | Signification | Réessayer ? |
|---|---|---|---|
| 400 |
invalid_json
|
Le corps n’est pas un JSON valide. | Corriger la requête |
| 401 |
unauthorized
invalid_token
|
Voir Authentification. | Corriger le jeton |
| 402 |
insufficient_balance
|
Le solde ne couvre pas une requête. | Après une recharge |
| 408 |
search_timeout
|
La recherche ne s’est pas terminée en 90 secondes. | Oui |
| 409 |
idempotency_in_progress
idempotency_replay_unavailable
|
Voir Relances sûres. | Selon le code |
| 413 |
payload_too_large
|
Le corps dépasse 16 Ko. | Corriger la requête |
| 422 |
invalid_request
country_unavailable
|
Un champ n’a pas passé la validation (le message le nomme), ou le marché n’est pas ouvert. | Corriger la requête |
| 424 |
proxy_unavailable
captcha_failed
search_failed
|
La recherche en direct a échoué de notre côté. | Oui, après une courte pause |
| 503 |
busy
billing_unavailable
configuration_error
|
Le service est à pleine capacité ou temporairement indisponible. | Oui, avec un délai croissant |
408, 424 ou 5xx n’est jamais facturée. Relancez les 408, 424 et 503 avec un délai exponentiel (backoff), par exemple après 5, 15 et 45 secondes, plutôt qu’en boucle serrée, et avec une nouvelle Idempotency-Key : la même clé rejoue la même erreur pendant 15 minutes au plus au lieu de lancer une nouvelle recherche.Relances sûres
Facultatif. Vous n’en avez besoin que si votre client peut relancer une requête interrompue.
Une recherche en direct dure jusqu’à 90 secondes. Si votre connexion tombe entre-temps, vous ne pouvez pas savoir si la recherche s’est terminée et a été facturée. L’en-tête Idempotency-Key vous permet de relancer sans payer deux fois :
- Même clé : si la première recherche s’est terminée, vous recevez à nouveau la même réponse avec l’en-tête
Idempotent-Replayed: trueet sans second débit ; une recherche échouée rejoue la même erreur. Si elle est encore en cours, la relance l’attend. Ne réutilisez la clé que si vous n’avez pas reçu le résultat, après une coupure de connexion ou un délai d’attente dépassé côté client ; après une réponse408,424ou5xx, envoyez une nouvelle clé. - La clé seule identifie la recherche : une relance avec un corps différent reçoit la réponse de la première requête ; envoyez donc une nouvelle recherche avec une nouvelle clé.
- Les résultats sont conservés 15 minutes au plus. Passé ce délai, une relance avec l’ancienne clé renvoie
409 idempotency_replay_unavailable; envoyez une nouvelle requête avec une nouvelle clé. - Sans l’en-tête, chaque requête est nouvelle et facturée séparément.
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":"DE","limit":10}'
La clé est une chaîne quelconque de 8 à 128 caractères parmi A-Za-z0-9._:-. Un nouvel UUID par requête logique est le choix le plus simple ; gardez-le identique pour toutes les relances de cette requête.
Limites et bon à savoir
query2–120 caractères,limit1–100, corps de requête jusqu’à 16 Ko.- Les recherches s’exécutent en parallèle dans la limite de la capacité du service ; au-delà, vous recevez
503 busy. Relancez avec un délai croissant. - Généralement 2–3 secondes pour 10 résultats et environ une seconde de plus par page supplémentaire ; une recherche toujours en cours après 90 secondes se termine par
408 search_timeout. Réglez le délai d’attente de votre client sur au moins 100 secondes. - Chaque réponse porte un en-tête
X-Request-Id. Conservez-le dans vos logs à côté durequestIddu corps. - Rien n’est mis en cache : deux requêtes identiques sont deux recherches en direct et deux débits. Mettez en cache de votre côté si vous réutilisez les résultats.
Trouver la position d’un domaine
L’API renvoie les résultats organiques jusqu’à limit, le top 10 par défaut ; y trouver un site revient à parcourir organic[] dans votre code. Comparez le domain de chaque entrée avec l’hôte que vous suivez : la position de la première correspondance est le classement pour ce mot-clé, ce pays et cet appareil. L’exemple ci-dessous fait exactement cela, avec la même requête en curl, JavaScript et Python.
Trois règles pour une comparaison fiable :
- Normalisez avant de comparer : passez les deux côtés en minuscules, retirez un
www.initial et comparez uniquement les hôtes, jamais les URL complètes. - Décidez comment comptent les sous-domaines.
blog.example.comest un autre hôte queexample.com; comparez l’hôte exact pour un suivi strict, ou traitez tout hôte qui se termine par.example.comcomme le même site pour un suivi au niveau de la marque. - Aucune correspondance signifie « hors de la plage demandée » pour ce contrôle, pas une erreur. Enregistrez-le comme tel : une requête renvoie au plus
limitrésultats organiques, donc augmentezlimit(jusqu’à 100, un prix par tranche de 10) si vous suivez des positions au-delà du top 10.
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":"DE","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: 'DE', 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": "DE", "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")
La page API de suivi de positions couvre tout le cycle d’un outil de suivi : listes de mots-clés, planification, stockage et coût d’un mois de vérifications.
Utilisation avec des agents IA (MCP)
Le serveur MCP de Serper.live donne aux agents IA comme Claude, OpenAI Codex, Cursor et VS Code Copilot la recherche Google en direct via cette API. Il s’exécute en local avec npx, nécessite Node.js 20 ou une version plus récente et s’authentifie avec le même jeton API dans la variable d’environnement SERPER_LIVE_TOKEN ; les recherches sont facturées exactement comme POST /v1/search.
google_search: résultats organiques en direct pour un mot-clé, un pays, une langue et un appareil, jusqu’à 100 par appel.domain_position: la position d’un domaine pour un mot-clé ; un sous-domaine compte comme le domaine, et toutes les positions sont renvoyées si le site apparaît plusieurs fois.list_countries: les marchés ouverts et la langue Google par défaut de chacun ; gratuit, sans jeton.
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"
Le paquet s’appelle @serper-live/mcp sur npm et io.github.serper-live/serper-live-mcp dans le MCP Registry officiel ; le README du dépôt décrit la configuration pour d’autres clients. Claude Desktop l’installe aussi en un clic depuis le bundle .mcpb et demande lui-même le jeton, sans Node.js.