You can scrape Google search results by sending your queries to a ready-made Actor. You get each results page back as structured JSON: organic results with their positions, titles, URLs and snippets, plus People Also Ask and related searches. The fastest way is the Scrape.ly Store: type a query, pick a country, run it, and export the page as JSON, CSV or Excel.
This guide shows the fields you get and how to run a search with no code. It also covers curl, Python, JavaScript and AI agents, how pricing per results page works, the limits, and what Google's own terms say. It uses a real run from 22 October 2026: one query, one page, 3.5 seconds.
What data you can get from Google Search
One thing to know first: each dataset item is one Google results page, not one result. The organic results sit in a list (organicResults) inside that item, next to the page's other modules. Ten queries with one page each give you 10 items.
| Field | What it holds |
|---|---|
searchQuery.term | The query you sent |
searchQuery.page | Results page number (1 is the first page) |
searchQuery.countryCode, searchQuery.languageCode | The country (gl) and interface language (hl) sent to Google |
url | The Google results URL that was fetched |
organicResults[].position | Rank on the page. It counts on across pages, so page 2 starts after page 1's last result |
organicResults[].title | Result title |
organicResults[].url | Destination URL |
organicResults[].displayedUrl | The breadcrumb URL Google shows under the title |
organicResults[].description | The snippet |
organicResults[].date | The date Google shows, when there is one |
peopleAlsoAsk | People Also Ask questions, with title, URL, answer and date when present |
relatedQueries | Related searches, each with a title and a Google URL |
hasNextPage | Whether Google has another results page |
paidResults, aiOverview, resultsTotal | Ads, the AI overview and the total results count. Browser mode only |
The default fast search mode doesn't fill paidResults, aiOverview, resultsTotal or saved HTML, and on organic rows it skips websiteTitle and emphasizedKeywords. Only browser mode fills those.
How to scrape Google search results without code
- Open the Google Search Scraper in the Scrape.ly Store and sign in.
- Pick the preset Search Google, 10 results. It fills in the input below.
- Check the input. This is the exact JSON we ran:
{
"queries": "web scraping",
"maxPagesPerQuery": 1,
"countryCode": "us",
"languageCode": "en",
"resultsPerPage": 10
}- Click Start. Our run finished in 3.5 seconds.
- Open the dataset and export it as JSON, CSV or Excel. Pick a view first: Organic results, Search pages (everything), People also ask or Paid results.
The input fields that matter most:
queries(required): one Google search per line. Put several lines in one run to check many keywords at once.maxPagesPerQuery: how many results pages to fetch per query. The default is 1. A query stops early when Google has no more results.countryCodeandlanguageCode: the country (gl, defaultus) and interface language (hl, defaulten). Rankings differ by country, so set these to match the market you track.resultsPerPage: how many results each item holds. The default is 10. Google pages hold 10, so in fast search mode other sizes are filled from consecutive Google pages, and each one is charged as a results page.- Operators:
site,wordsInTitle,wordsInText,wordsInUrl,fileTypes,forceExactMatchand date filters such asquickDateRangeadd Google's search operators for you.
Ads and AI overviews are opt-in. The input schema says fast search mode doesn't return ads or AI overviews, so Include ads (includeAds) and Wait for live AI overviews (liveAiOverview) use browser mode.
How to scrape Google search results with Python and the API
Get your API token from Settings → API & Integrations in the dashboard and export it as SCRAPELY_TOKEN. The Actors API docs list every endpoint.
curl. One page takes a few seconds, well under the 45-second limit of the synchronous endpoint. This call returns the dataset items as a JSON array (add ?format=csv for CSV):
curl -X POST "https://api.scrape.ly/v2/actors/querystone~google-search-scraper/run-sync-get-dataset-items" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": "web scraping", "maxPagesPerQuery": 1, "countryCode": "us", "languageCode": "en", "resultsPerPage": 10}'Python. Install the client with pip install scrapely-client-python. call() waits for the run however long it takes, which matters once you send long query lists. See the Python client docs.
import os
from scrapely_client import ScrapelyClient
client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")
run = client.actor("querystone/google-search-scraper").call(
run_input={"queries": "web scraping", "maxPagesPerQuery": 1, "countryCode": "us", "languageCode": "en", "resultsPerPage": 10}
)
print(run.status) # SUCCEEDED, FAILED, ABORTED or TIMED-OUT
for page in client.dataset(run.default_dataset_id).iterate_items():
for result in page["organicResults"]:
print(result["position"], result["title"], result["url"])Note the two loops: the outer one walks results pages (dataset items), the inner one walks the organic results on each page.
JavaScript. Install with npm install scrapely-client. See the JavaScript client docs.
import { ScrapelyClient } from 'scrapely-client';
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });
const run = await client.actor('querystone/google-search-scraper').call({
queries: 'web scraping',
maxPagesPerQuery: 1,
countryCode: 'us',
languageCode: 'en',
resultsPerPage: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0].organicResults);AI agents (MCP). Scrape.ly runs a hosted MCP server at https://api.scrape.ly/mcp. In Cursor, add it to ~/.cursor/mcp.json:
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}In Claude Code, run claude mcp add --transport http scrapely https://api.scrape.ly/mcp, then /mcp to sign in. The agent finds the Actor with search-actors, reads its input with fetch-actor-details, runs it with call-actor and reads the page with get-actor-output. Try: "Use scrapely to run querystone/google-search-scraper for 'web scraping' in the US, one page, and give me a table of position, title and URL." The MCP docs cover OAuth and other clients.
A real run: Search Google, 10 results
We ran the preset on 22 October 2026. It saved 1 dataset item, one results page holding 9 organic results, in 3.482 seconds with 1,024 MB of memory. No pages failed, and the run was charged $0.0033. The first five organic results (the destination URL column is left out for width):
| position | title | displayedUrl | description |
|---|---|---|---|
| 1 | Web scraping | en.wikipedia.org › wiki › Web_scraping | Web scraping, web harvesting, or web data extraction is data scraping… |
| 2 | What is Web Scraping? The Complete Guide for 2025 | scraperapi.com › web-scraping | Web scraping, or web data extraction, is the process of extracting pu… |
| 3 | Web Scraper Cloud \ | Enterprise Web Scraping Platform | webscraper.io | Enterprise web scraping infrastructure for engineering teams, with AP… |
| 4 | What is Web Scraping and How to Use It? | geeksforgeeks.org › blogs › what-is-web-scraping-and-how-to-use-it | Web scraping is an automated method to extract large amounts of data … |
| 5 | Web Scraping | publichealth.columbia.edu › research › population-health-methods › we… | Web scraping (web harvesting or web data extraction) is a computer so… |
The console excerpt:
2026-10-22T15:23:14.486Z [scrapely.actor] INFO actor_started
2026-10-22T15:23:14.486Z [scrapely.actor] INFO Using fast search mode. Pages switch to browser mode only if fast search mode fails.
2026-10-22T15:23:14.493Z [scrapely.actor] INFO queries=1 concurrency=8
2026-10-22T15:23:14.909Z [scrapely.actor] INFO Pushed 1 dataset items, 9 organic results, 0 failed pages in 0.4s. Pages handled in fast search mode: 1, in browser mode: 0. …
2026-10-22T15:23:14.909Z [scrapely.actor] INFO [Status message]: 1 pages, 9 organic results, 0 failed
2026-10-22T15:23:15.512Z [Scrapely] Container state: status=exited exitCode=0 oomKilled=falseAsking for 10 results per page doesn't guarantee 10 organic results: this page held 9. The same item also carried 8 related searches. Positions 1, 4 and 5 are explainer pages (Wikipedia, GeeksforGeeks and Columbia's public health school), while 2 and 3 are scraping vendors.
What it costs
The Actor charges one event: $0.003 per SERP page, which is $3.00 per 1,000 Google results pages. Platform usage (compute and storage) is billed on top.
For this run, 1 page × $0.003 = $0.003 in page fees. The run was charged $0.0033 in total because platform usage added $0.00023 in compute, $0.00005 in key-value store writes and $0.000005 in dataset writes.
You pay per page, not per result. With the default 10 results per page, that's one event per dataset item. Roughly 1,000 organic results take about 100 pages, or $0.30 in event fees. It takes a few more pages when Google shows fewer than 10 organic results, as it did here. In fast search mode, resultsPerPage: 20 fetches 2 Google pages per item, so it's charged 2 events. A page past the last result isn't charged, and failed pages aren't saved or charged.
Limits and common problems
- Fewer than 10 results. Google decides how many organic results a page holds. Count
organicResultsrather than assuming 10. - Some options switch to browser mode. Per the input schema, ads (
includeAds), live AI overviews (liveAiOverview), exact location (locationUule), unfiltered results (includeUnfilteredResults) and saved HTML (saveHtml,saveHtmlToKeyValueStore) use browser mode. - Results depend on where you search from. Set
countryCodeandlanguageCodefor the market you care about.searchLanguagelimits results to pages in one language. - Later pages stop early. The Actor doesn't fetch a later page once a page has no organic results or
hasNextPageis false. - Failed pages don't stop the run. If fast search mode can't return a page, the Actor loads that page in browser mode. A page that still fails is listed in the status message and under
failedInputsin the run'sOUTPUTrecord, and the other queries keep going. - Long query lists and the sync endpoint. One page took 3.5 seconds, but a run with many queries and pages can pass the 45-second limit of
run-sync-get-dataset-items. Then it answers408while the run continues. Use the async flow or a client for big batches.
Is it legal to scrape Google search results?
Google results pages are public, but Google's rules on automated access are specific. Its Terms of Service list "using automated means to access content from any of our services in violation of the machine-readable instructions on our web pages (for example, robots.txt files…)" as abuse. Google's robots.txt disallows /search for all crawlers. So scraping results pages conflicts with Google's terms, even though anyone can see the pages. Titles and snippets belong to the sites that wrote them. Results rarely hold personal data, but some snippets name people. If you store those, privacy laws such as the GDPR and CCPA apply. This is general information, not legal advice. For commercial use, get advice for your case.
Alternatives
- Google's Custom Search JSON API. It returns results from a Programmable Search Engine as JSON, but Google says it is closed to new customers. Existing customers have until January 1, 2027 to move off it. For searching up to 50 domains, Google points to Vertex AI Search. If you only need results from a fixed set of sites, that's the better choice.
- Build it yourself. Python with an HTTP client and a parser, or Playwright with residential proxies, both work, as the Oxylabs and Scrapfly tutorials show. You handle CAPTCHAs, blocks and Google's markup changes yourself. That's reasonable for a small, one-off check.
- Other hosted SERP APIs. Services such as ScrapingBee and Outscraper sell the same kind of results-page data. Compare the price per page and the fields you need.
FAQ
Can you scrape Google search results with Python?
Yes. The Python example above starts a run, waits for it and prints position, title and URL for each organic result. The Actor handles fetching and parsing, so your code only reads JSON.
How much does it cost to scrape Google search results?
$0.003 per results page, or $3.00 per 1,000 pages, plus platform usage. Our one-page run was charged $0.0033 in total.
How do I get more than 10 results per query?
Raise maxPagesPerQuery to fetch more pages, or raise resultsPerPage to put more results in each item. Either way you pay for every Google page fetched. Positions count on across pages, so you can sort all results for a query by position.
Can I scrape Google ads and AI Overviews?
Yes, if you turn them on. The input schema says fast search mode doesn't return ads or AI overviews, so includeAds and liveAiOverview use browser mode. Ads land in paidResults, and the Paid results view lists them.




