TL;DR:
- Scrapeless Google Search API exposes search results as JSON. The returned organic-result fields can feed SEO tooling, research exports, and source selection.
- Store the search settings alongside every response. A query, country, language, and observation time give a result the context needed for comparison.
- Check task state before exporting rows. HTTP 201 means the task is still processing, rather than that a search returned no results.
A search export is easier to debug when each row can be traced back to an input. Otherwise, a changed URL leaves an awkward question: did the result change, or did the request use a different market?
The updated Scrapeless Google Search API accepts a search request and returns structured JSON. Collection-side proxy and CAPTCHA handling are managed by the service. Your code owns the request settings, response interpretation, and any storage or reporting built afterward.
The implementation below keeps those responsibilities visible. It submits a small request, saves the input with the response, and creates a CSV only when the task has returned usable organic-result data.
What the Google Search API Returns
The organic web results appear in a top-level organic_results array when that field is present. Its items can contain a position, title, link, and snippet. Search metadata, pagination, and additional result modules can accompany those rows, depending on the search.
Save the payload before flattening it. A CSV represents a selected set of columns; nested search modules need their own mapping. The JSON data model keeps objects, arrays, primitive values, and null distinct, so preserving the original data leaves room for a different export later.
The snippet field belongs to the search result. It should not be used as a substitute for the destination page's complete text. A pipeline that needs evidence from that page has another acquisition and review step after source discovery.
Prepare a Small First Request
You need an account with Google Search API access, a Scrapeless API key, and a Python environment that can send HTTP requests. Put the key in SCRAPELESS_API_KEY through your shell or local secret manager. Do not write it into the script or commit it with an example project.
Install requests in that environment. The script's CSV, JSON, path, and date handling use Python's standard library. Save the complete example as google_search_export.py and execute python3 google_search_export.py once the key is available.
Its first input is deliberately small: coffee, with gl=us and hl=en. Look at the resulting JSON before adding more keywords. A local export that works for one observed response is a better starting point than a large collection job whose shape you have never inspected.
Calling the service requires your account key. The HTTP portion follows the current request reference and is included as an integration prerequisite, rather than as evidence of a live account run performed for this article.
Choose Country, Language, and Input Mode
The input object describes several independent search dimensions. gl is the country setting; hl is the language setting. location describes the search origin, and google_domain selects the Google domain. The currently supported device option is desktop.
There are also two construction rules in the Google Search API parameter model:
- Build a parameter-based request around
q, or supply a complete Google Searchurl. Supplyingurlcauses the other input parameters to be ignored. - Supply
locationoruule, but never both in the same request.
Persist the actual input object rather than reconstructing it from a filename. This makes an accidental setting change visible when comparing runs. Keeping country and language consistent defines the intended comparison; it does not make a dynamic search result identical each time or recreate an individual user's signed-in history.
The query can use site:, inurl:, and intitle: to focus discovery. Do not interpret the output of a site-restricted search as a complete count of pages indexed for a domain. It is a search sample with its own retrieval limits.
Request JSON and Export Organic Results
Send a POST request to https://api.scrapeless.com/api/v1/scraper/request with actor set to scraper.google.search. Authentication uses x-api-token. The following script records the input, HTTP status, response, and client receipt time before creating its selected CSV view.
Note: A Scrapeless API key is required for the network request, which has not been executed with a live account for this article. HTTP 201 responses are saved for inspection; task-result retrieval is outside this script.
import csv
import json
import os
from datetime import datetime, timezone
from pathlib import Path
import requests
def spreadsheet_text(value):
text = "" if value is None else str(value)
if text.lstrip().startswith(("=", "+", "-", "@")) or text.startswith(("\t", "\r")):
return "'" + text
return text
def export_results(payload, context, received_at, output_path):
results = payload.get("organic_results")
if not isinstance(results, list):
print("No usable organic_results array; inspect the saved JSON.")
return
fields = ["q", "gl", "hl", "received_at", "position", "title", "link", "snippet"]
with output_path.open("w", encoding="utf-8", newline="") as stream:
writer = csv.DictWriter(stream, fieldnames=fields)
writer.writeheader()
for item in results:
if not isinstance(item, dict):
raise ValueError("Unexpected organic result item; inspect the saved JSON.")
row = {name: item.get(name) for name in ("position", "title", "link", "snippet")}
row.update(context, received_at=received_at)
writer.writerow({name: spreadsheet_text(row.get(name)) for name in fields})
print(f"Exported {len(results)} organic results to {output_path}")
def main():
context = {"q": "coffee", "gl": "us", "hl": "en"}
response = requests.post(
"https://api.scrapeless.com/api/v1/scraper/request",
headers={"x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={"actor": "scraper.google.search", "input": context},
timeout=120,
)
response.raise_for_status()
received_at = datetime.now(timezone.utc).isoformat()
run_id = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ")
payload = response.json()
record = {"input": context, "received_at": received_at,
"http_status": response.status_code, "response": payload}
output = Path(f"google-search-{run_id}.json")
output.write_text(json.dumps(record, ensure_ascii=False, indent=2), encoding="utf-8")
if response.status_code == 201:
print(f"Task pending. Inspect taskId in {output}; no CSV was created.")
return
if response.status_code != 200 or not isinstance(payload, dict):
raise ValueError(f"Unexpected response; inspect {output}")
export_results(payload, context, received_at, output.with_suffix(".csv"))
if __name__ == "__main__":
main()
The timeout of 120 is an example client limit, not a measured service latency or SLA. The received_at value is created by the client after receiving a response. It describes receipt time, rather than a Google-generated collection timestamp.
The standard CSV writer takes care of quoting and delimiters. A small helper prefixes text with common formula-opening characters for spreadsheet inspection. That transformation is one reason the raw JSON remains the primary record. Review your spreadsheet application's text-import settings when opening third-party values.
The example's CSV stores the three input dimensions it actually uses: q, gl, and hl. Add columns for location, google_domain, or start if you add those settings. They are already retained in the full input saved in JSON.
Interpret the Response Before Building a Report
Branch on the task state before treating the body as a finished result. HTTP 200 carries the task data. HTTP 201 says processing is ongoing and returns a taskId, so the script records the response and ends without producing a CSV.
Even after a successful data response, an empty array and a missing organic_results field deserve different treatment. A response may carry other modules. The code reports the absence of a usable array and leaves the saved payload available for inspection instead of silently calling it a zero-result search.
Keep the returned position value as supplied. Before calculating a rank across multiple pages, confirm the numbering behavior for the requests you are making. start is the pagination offset, and response pagination information can help you move forward, but this does not promise access to every result in Google.
Put Structured Search Data to Work
The API provides search data; your application adds the workflow around it. For analysis, treat a result, its search context, and its observation time as one unit rather than three unrelated pieces of data.
- SEO snapshots: collect a chosen keyword list with fixed settings and compare matching observations later. Your code or infrastructure supplies scheduling, persistence, and comparison logic.
- Brand and competitor research: group the returned domains and review titles for those queries. This describes the selected sample, without measuring complete web coverage or traffic to a domain.
- AI source discovery: hand candidate titles, URLs, and snippets to a source-selection stage. Obtain full pages independently when the task requires evidence, then validate claims against their sources.
A small research export can be enough for a first delivery. Give a content team a reading list with its query and market, or feed an existing report from a repeatable file. Both are easier to maintain when the export explains how its rows were obtained.
Use the workflow for public information you are permitted to collect and use. Keep credentials protected, retain only the data needed for the task, and review the conditions governing its later reuse.
Conclusion
A working integration needs more than a successful JSON parse. It needs a saved input, an explicit task-state check, and a clear handoff from search discovery to analysis. Start with the single-query script and read the complete saved payload before expanding it.
Use the updated Google Search API request workflow when adapting the request to your application.
FAQ
Q: Is this an API provided by Google?
The service described here is Scrapeless Google Search API. It retrieves Google Search data through Scrapeless and does not imply an official Google partnership.
Q: Do you need to manage a browser or proxy?
Collection infrastructure is managed on the service side. The client sends an HTTP request and handles the data it receives.
Q: Does the API include historical ranking data?
This workflow builds a history from observations you save yourself. It does not provide an existing archive of past rankings.
Q: Can the same API search for images?
Google Image searches are supported, with tbm=isch listed in the parameter reference. Inspect their response independently because the CSV in this example maps organic web results.
Q: Does a search snippet contain the full page?
The snippet is a search-result excerpt. Obtain the destination page separately when the task needs the full source content.
Q: What should happen when the request returns HTTP 201?
Store the taskId and keep the task pending. Follow the documented task-result process before handling it as completed search data.

Top comments (0)