← Back to blog

Google Search API in PHP: Complete Tutorial (2026)

Call a Google Search API in PHP with cURL or Guzzle: auth, parsing organic results, pagination. Copy-paste code, from $0.75 per 1k searches.

1 min read

Query Google from PHP and get structured results, using serp.cheap. One endpoint: POST https://api.serp.cheap/v1/search with an X-API-Key header. Sanity-check your key from the shell first:

curl -s https://api.serp.cheap/v1/search \
  -H "X-API-Key: $SERP_CHEAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"q":"best electric cars 2026","gl":"us"}'

All PHP examples below read the key from the SERP_CHEAP_API_KEY environment variable — keep it out of source control and client output.

Native cURL (no dependencies)

<?php
$apiKey = getenv("SERP_CHEAP_API_KEY");
if ($apiKey === false) {
    fwrite(STDERR, "SERP_CHEAP_API_KEY is not set\n");
    exit(1);
}

$ch = curl_init("https://api.serp.cheap/v1/search");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ["X-API-Key: $apiKey", "Content-Type: application/json"],
    CURLOPT_POSTFIELDS => json_encode(["q" => "best electric cars 2026", "gl" => "us", "page" => 1]),
]);
$res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($res === false || $code !== 200) {
    throw new RuntimeException("Search failed: HTTP $code");
}
$data = json_decode($res, true);
foreach ($data["organic"] as $r) {
    printf("#%d %s — %s\n", $r["position"], $r["title"], $r["link"]);
}

Output:

#1 Best Electric Cars of 2026, Ranked — https://www.example.com/ev/best-electric-cars-2026
#2 Top 10 EVs Worth Buying This Year — https://www.example.org/reviews/top-evs
#3 Electric car buyer's guide (2026) — https://blog.example.net/ev-buyers-guide
...

Each entry also carries snippet, date, and sitelinks when Google shows them, and the response includes a knowledgeGraph object when a Knowledge Graph panel is present.

With Guzzle

<?php
require "vendor/autoload.php";

use GuzzleHttp\Client;

$client = new Client(["base_uri" => "https://api.serp.cheap/"]);
$res = $client->post("v1/search", [
    "headers" => ["X-API-Key" => getenv("SERP_CHEAP_API_KEY")],
    "json"    => ["q" => "serp api php", "gl" => "us"],
]);
$data = json_decode((string) $res->getBody(), true);
echo "cost: {$data['stats']['cost']} credits\n";

Guzzle throws on non-2xx responses by default, so failed requests surface as exceptions without extra checks.

Pagination

page is 1-indexed; each page is a separate billed request. Wrap the cURL call from above in a function and loop:

<?php
function serpSearch(array $params): array {
    $apiKey = getenv("SERP_CHEAP_API_KEY");
    if ($apiKey === false) {
        throw new RuntimeException("SERP_CHEAP_API_KEY is not set");
    }
    $ch = curl_init("https://api.serp.cheap/v1/search");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => ["X-API-Key: $apiKey", "Content-Type: application/json"],
        CURLOPT_POSTFIELDS => json_encode($params),
    ]);
    $res = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($res === false || $code !== 200) {
        throw new RuntimeException("Search failed: HTTP $code");
    }
    return json_decode($res, true);
}

$all = [];
for ($page = 1; $page <= 3; $page++) {
    $data = serpSearch(["q" => "best electric cars 2026", "gl" => "us", "page" => $page]);
    if (empty($data["organic"])) {
        break; // no more results
    }
    $all = array_merge($all, $data["organic"]);
}
printf("collected %d results\n", count($all));

Stop as soon as a page comes back empty — every extra page costs credits.

Next

Try serp.cheap

Drop either snippet into your PHP project and you’re querying Google in a few minutes. 100 free searches on signup — no card required; pay-as-you-go from $0.75/1k after that, and credits stay valid for 12 months.

Frequently asked questions

How do I call a Google Search API in PHP?+

POST JSON with cURL or Guzzle. With serp.cheap, send to https://api.serp.cheap/v1/search with an X-API-Key header and a JSON body, then json_decode the response and read the organic array.

cURL or Guzzle?+

Native cURL works with zero dependencies. Guzzle is cleaner for larger apps and makes retries and async easy. Both call the same HTTP endpoint — or skip the wiring with the official PHP SDK (composer require serpcheap/serpcheap), which also ships a Laravel integration.

Get your API key

Cheapest direct, pay by card or crypto, no KYC. Or use a marketplace.