How to scrape Google search results

Two ways to scrape Google search results: build a headless browser stack yourself, or call an API that already did that work. This guide covers both, with working code in curl, Python, and Node, plus the real data that comes back.

3,000 free queries / month, no card p50 ~1.2s web responses Pay only when results return
TWO ROUTES

DIY headless browser, or one API call

Google stopped serving results to plain HTTP clients. The page needs JavaScript to render, bot checks guard it, and suspicious IPs get a block page instead of results. That leaves two real routes, and the right one depends on how much plumbing you want to own.

Build it yourselfCall an API
SetupHeadless Chrome, stealth patches, a proxy account, parser code. Days before the first clean resultOne HTTPS GET. Minutes
IPs and blocksYour problem. Datacenter IPs hit the block page fast, so you buy and rotate residential or ISP proxiesOur problem. You never see a block page
ParsingYou write selectors against scrambled class names that change without noticeStable JSON, same field names every time
Cost shapeProxy and server bills arrive whether your queries worked or not1 credit per query that returns results. Failures and empties cost nothing
MaintenanceOngoing. When Google changes markup, your pipeline goes dark until you patch itOurs
Best forScraping is your core product and you want control of every layerYou want the data, without owning the plumbing
THE TRADE-OFFS

What building it yourself takes

If you go DIY, here are the four layers you end up building. We know because we built all four, and they now run behind our API.

  1. A real browser. Google requires JavaScript to render results, so plain requests get a blank shell or a bot check. You run headless Chrome through Playwright or Puppeteer, with stealth patches so it does not announce itself.
  2. Clean IPs. Datacenter addresses get blocked fast. You buy residential or ISP proxies, then write rotation logic for the day an IP gets throttled anyway.
  3. A parser. Result markup uses scrambled class names that change without notice. Your selectors work today and return empty arrays some Tuesday next month.
  4. Babysitting. Each layer above breaks on its own schedule. The maintenance is the real product.

For a handful of queries a day from your own machine, a small script genuinely works. The short version looks like this:

# DIY starter: Playwright, Python. Fine at tiny scale. from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto("https://www.google.com/search?q=best+crm+software") titles = page.eval_on_selector_all("a h3", "els => els.map(e => e.textContent)") print(titles) browser.close()

Run that a few hundred times in an hour and you will meet the block page. At that point you start buying proxies and writing rotation logic, and the project stops being a script and starts being infrastructure.

THE API ROUTE

One call in curl, Python, or Node

The other route is one HTTPS GET. Auth is your key in the x-api-key header. The browser pool, the clean IPs, and the parsing run on our side, and you are only charged when a query returns results.

# curl curl "https://crustapi.com/v1/search?type=web&q=best%20crm%20software" \ -H "x-api-key: YOUR_KEY"
# Python 3 import requests r = requests.get( "https://crustapi.com/v1/search", params={"type": "web", "q": "best crm software"}, headers={"x-api-key": "YOUR_KEY"}, ) for row in r.json()["organic"]: print(row["position"], row["title"], row["link"])
// Node 18+ const params = new URLSearchParams({ type: "web", q: "best crm software" }); const res = await fetch("https://crustapi.com/v1/search?" + params, { headers: { "x-api-key": "YOUR_KEY" }, }); const data = await res.json(); for (const row of data.organic) console.log(row.position, row.title, row.link);

Useful parameters: gl for country, hl for language, page for deeper pages, location for city-level results. The full list is in the docs, and you can run queries in the playground without writing code.

WHAT COMES BACK

The data that comes back

Every result comes back in a stable, serper-compatible shape: ranked organic results with positions, plus knowledge graph, people-also-ask, and related searches when Google shows them. Here are the top organic rows as CSV, then the same response as JSON. Trimmed for space:

CSV view
position,title,link,snippet 1,"Tesla: Electric Cars, Solar & Clean Energy","https://www.tesla.com/","Tesla is building a world of amazing abundance with AI, electric cars, solar…" 2,"Inventory","https://www.tesla.com/inventory/new",""
JSON view
{ "searchParameters": { "q": "tesla", "gl": "us", "hl": "en", "page": 1, "type": "web" }, "knowledgeGraph": { "title": "Tesla", "description": "Tesla, Inc. is an American multinational automotive and clean energy company…", "descriptionSource": "Wikipedia" }, "organic": [ { "title": "Tesla: Electric Cars, Solar & Clean Energy", "link": "https://www.tesla.com/", "snippet": "Tesla is building a world of amazing abundance with AI, electric cars, solar…", "sitelinks": [ { "title": "Shop", "link": "https://shop.tesla.com/" }, ], "position": 1 }, { "title": "Inventory", "link": "https://www.tesla.com/inventory/new", "position": 2 } ], "peopleAlsoAsk": [ { "question": "Why are people not buying Tesla anymore?" }, ], "relatedSearches": [ { "query": "Tesla Model 3" }, { "query": "Tesla Model Y" }, ] }

Published median for web search is about 1.2 seconds. The shape stays put, so the parser you write today keeps working.

PULLED LIVE FROM THE API, JULY 17, 2026

12 search types, one endpoint

Swap type=web for any other Google surface on the same endpoint, same key, same billing. Here is a real autocomplete call we ran while writing this page:

curl "https://crustapi.com/v1/search?type=autocomplete&q=how%20to%20scrape%20google" -H "x-api-key: YOUR_KEY" { "suggestions": [ { "value": "how to scrape google maps" }, { "value": "how to scrape google reviews" }, { "value": "how to scrape google maps for free" }, { "value": "how to scrape google scholar" }, { "value": "how to scrape google maps reviews" }, ] }
Ranked organicweb Full business recordsmaps Lean local resultsplaces Source + datenews Prices + ratingsshopping ~97 per creditimages Duration + channelvideos Papers + citationsscholar Filings + PDFspatents Suggestionsautocomplete Page text as JSONwebpage ~0.3s responsesreviews

One note on emails: Google results and Maps records do not include email addresses. Maps gives you name, address, phone, website, rating, reviews, categories, and hours. Verified emails come from our LinkedIn people search endpoints, which are separate.

Deeper dives: Google Maps scraper API · Google Reviews API · the official Google Search API, compared

PRICING

One credit per query that works

Free tier is 3,000 queries a month with no card. Prepaid packs after that, and credits never expire: 25k for $49 · 100k for $149 · 500k for $549 · 2.5M for $1,999, all self-serve, ex-tax. A query that returns results costs 1 credit. A query that fails or comes back empty costs nothing.

Run your first queries free
3,000 queries a month. No card, no contract.
Get started →
FAIR PLAY

When DIY is the better pick: scraping is your core product and you want control of every layer, you only need a handful of queries a day from your own machine, or you are doing it to learn how the plumbing works. Those are real cases. And if you are shopping hosted APIs, Serper and SerpApi are both solid products. We keep side-by-side comparisons: CrustAPI vs Serper and CrustAPI vs SerpApi.

BEFORE YOU ASK

Common questions

WORKS WITH YOUR STACK

Run one query and read the JSON

3,000 free queries a month covers a real project. Skip the proxy shopping and see what comes back.

Get 3,000 free credits
No credit card required