Google search results scraper and SERP API: result pages as JSON, no API key
Google has no public API for its search results, and the result page is built to be read, not exported: every link goes through a redirect and there is no download button. This page shows how to scrape Google search results into rows: what one result page contains, how to run the scraper from the Apify Console or from code, how to localize and date-filter the results, and what a thousand pages cost.
What you get
The Google Search Results Scraper on Apify takes a list of queries, or full Google search URLs, and returns one record per result page. Field names follow the most used Google search Actor on the Store, so an existing sheet or automation switches by changing the Actor name.
- searchQuery: the term, page number, country, language, device and the date filter in force.
- organicResults:
position,title,url(the real page address, not Google's redirect link),displayedUrl,description,siteName,date,siteLinks,emphasizedKeywords,type(organic or video). - paidResults: text ads with title, destination URL, displayed URL and description. paidProducts: shopping ads with title, price and merchant.
- peopleAlsoAsk: the questions Google shows for the query, with the answer snippet and its source page. relatedQueries: related searches with their Google URLs.
- resultsTotal, Google's approximate count when it shows one, and hasNextPage.
The records are the mobile result pages, which is what most people searching Google see today. Trimmed to one entry per list, a record looks like this:
{
"searchQuery": { "term": "hotels in prague", "page": 1, "countryCode": "us",
"languageCode": "en", "device": "MOBILE", "timeRange": null },
"url": "https://www.google.com/search?q=hotels+in+prague&gl=us&hl=en",
"resultsTotal": 128000000,
"hasNextPage": true,
"organicResults": [
{ "position": 1,
"title": "Hotels in Prague",
"url": "https://www.booking.com/city/cz/prague.html",
"displayedUrl": "https://www.booking.com › city › cz",
"description": "Great savings on hotels in Prague, Czech Republic online ...",
"siteName": "Booking.com",
"date": "Aug 20, 2025",
"siteLinks": [ { "title": "Cheap hotels", "url": "https://www.booking.com/budget/city/cz/prague.html" } ],
"type": "organic" }
],
"paidResults": [ { "position": 1, "title": "Prague Hotels from $39", "url": "https://...", "description": "..." } ],
"paidProducts": [ { "position": 1, "title": "Hotel Kings Court", "price": "$142", "merchant": "Expedia" } ],
"peopleAlsoAsk": [ { "question": "Which area is best to stay in Prague?", "answer": "...", "url": "https://..." } ],
"relatedQueries": [ { "title": "hotels in prague old town", "url": "https://www.google.com/search?q=hotels+in+prague+old+town" } ]
}
How to run it
From the Apify Console
- Open the Store page and press Try for free; the free plan covers small runs.
- Paste your queries, one per line. Set the country and language if the default (US, English) is not what you want, and the number of pages per query.
- Start the run. When it finishes, the Output tab shows the pages and the Export button downloads them as JSON, CSV or Excel.
From code
One call starts the run, waits for it and answers with the records. Replace apify_token with the token from your Apify account settings:
curl -X POST "https://api.apify.com/v2/acts/alfalfa~google-serp-scraper/run-sync-get-dataset-items?token=apify_token" \
-H 'Content-Type: application/json' \
-d '{"queries":"hotels in prague\nbest laptop 2026","maxPagesPerQuery":2,"countryCode":"us","languageCode":"en"}'
For a long keyword list start the run asynchronously, poll it and read the dataset when it finishes; add ?format=csv or xlsx to the dataset URL for a spreadsheet. Schedules, webhooks and the Python and JavaScript clients work as for any Apify Actor; the API overview shows the pattern.
Inputs
| Field | What it does |
|---|---|
queries | One search query per line, or full Google search URLs. Required. |
maxPagesPerQuery | Result pages per query, 1 to 100 (10 results each). Default 1. Stops earlier when Google has no more pages. |
countryCode | Two-letter country the results are localized to (Google's gl): us, gb, de, cz. Empty means Google's default. |
languageCode | Two-letter language of the results (Google's hl): en, de, cs. Defaults to the country's main language, or English. |
locationUule | Encoded place for local results (Google's uule). Optional. |
timeRange | any, hour, day, week, month or year: Google's Any time filter. |
dateFrom, dateTo | A fixed period, YYYY-MM-DD. One bound is enough. A custom range replaces the time range. |
resolveUrls | On by default: url is the real destination. Off: url is Google's redirect link. |
saveHtml | Adds the full HTML of each result page to the record as html. Large; off by default. |
Uses that pay for themselves
- Rank tracking. A keyword list, one or two pages each, on a daily schedule. Filter
organicResultsby your domain and your competitors' domains and chartpositionover time, per country. - SERP feature research. Which keywords show shopping ads, video results, sitelinks or a People Also Ask block, and which are plain ten blue links. That decides what kind of page can win them.
- Ad monitoring.
paidResultsandpaidProductsshow who bids on your keywords, what their ads say and what their products cost, week after week. - Keyword ideas.
peopleAlsoAskandrelatedQueriesfor a seed list are the questions and phrasings Google itself associates with a topic, ready for a content plan. - Localized results. The same keywords in
gb,deandfr, or in one country with several UULE places, show how the results differ from market to market.
Pricing
$0.45 per 1,000 result pages, the same on the free plan and on every paid plan. A page holds up to ten organic results plus the ads, shopping ads, questions and related searches; all of it, and the resolved URLs, is included in the page price.
| Budget | Result pages | For example |
|---|---|---|
| $0.45 | 1,000 | 1,000 keywords, first page each, once |
| $1.35 | 3,000 | 1,000 keywords, three pages each |
| $4.50 | 10,000 | 500 keywords in four countries, five pages each |
| $13.50 | 30,000 | 1,000 keywords, first page, every day for a month |
Final price. The per-page price is everything you pay: platform usage is included, there is no start fee and no per-run minimum. Some listings on the Store show a lower number and add platform usage on top; here the number on the listing is the number on your bill.
Use it from n8n, Make, Zapier or an AI agent
The scraper is an Apify Actor, so it is available through the Apify nodes in n8n and Make, the Apify app in Zapier, and as an MCP tool for AI agents at https://mcp.apify.com/?tools=alfalfa/google-serp-scraper. The input is the same JSON as in the curl call above and the result is the dataset: rows for a sheet, a table or a prompt. An agent that needs fresh search results gets a full result page, with real URLs, in one tool call.
Questions people ask
Are the result URLs real page addresses or Google redirect links?
Real page addresses. Google wraps every result in a redirect link; the scraper resolves it, so url holds the destination page. Switch resolveUrls off to keep Google's link when titles and descriptions are all you need. Very rarely a link cannot be resolved; the record then keeps the redirect link, which still leads to the page.
Why are the results the mobile layout?
Google serves different pages to phones and to desktops, and the phone version is the majority experience. It has the same organic results, ads and questions; positions can differ slightly from what a desktop search shows for the same query.
How do I localize results to a country or a city?
Set countryCode (Google's gl) and languageCode (hl): gb with en gives the results a person in the UK sees, de with de the German ones. Queries with local intent ("plumber near me") also depend on the place Google assumes; set locationUule to pin them to a city.
Can I get only results from the past week or a date range?
Yes. timeRange gives the past hour, 24 hours, week, month or year, the same filter as Google's Any time menu. dateFrom and dateTo give a fixed range; one of them is enough for an open-ended one, and a custom range replaces the time range. The filter applies to every page of every query, and each record notes it in searchQuery.
How many pages can I get per query?
Up to 100. For most queries Google stops offering pages long before that; the run stops there and the last record has hasNextPage set to false.
What counts as one result page?
One record in the dataset: a query at one page number with its organic results (up to ten), ads, shopping ads, People Also Ask questions and related searches. A query with three pages requested is three pages. Nothing on the page is charged separately.
Is it legal to scrape Google search results?
The scraper reads pages Google shows to anyone without an account, and no login of yours is involved. How you use the data is your responsibility: check Google's terms, the law where you operate and, where results contain personal data, the privacy rules that apply to you.
Ready-made examples
Three example pages on the Store open with the input already filled in and a sample dataset to look at:
- Google rank tracker for a keyword list: positions per keyword and country, on a schedule.
- Google SERP API alternative: result pages as JSON from one API call.
- People Also Ask questions for a topic: the questions Google associates with a subject.
Open the Google Search Results Scraper Read: Google Maps places as a table