Glasser Team10 min read
How to Search Google Patents with Python
Search Google Patents with Python through Glasser. Inspect the endpoint, save a repeatable request, and review source records without guessing response fields.

Choose a Python access path for Google Patents
A Python workflow can search Google Patents through a documented data provider, save the returned records and retain their source links for review. First choose whether you need a query result, a known patent document, or bulk statistical analysis. Each calls for a different access path.
Glasser's Serper patent-search operation accepts a text query, inventor or assignee and retrieves Google Patents results. The Python example below uses that operation through Glasser. Its API contract belongs to Glasser and Serper; the name “Google Patents API” does not make it a Google-operated developer API.
| Research task | Useful starting point | Expected review |
|---|---|---|
| Discover documents about a technology | A patent-search operation | Query relevance, document identifiers and source links |
| Examine a document you already know | The patent's source page | Full text, bibliographic data and the precise document version |
| Analyze a large patent corpus | A documented dataset and query engine | Dataset coverage, update schedule and analysis assumptions |
Google's own Patents Public Datasets announcement describes connected tables in BigQuery for SQL analysis. That differs from requesting one page of ranked search results. Verify the current dataset and its documentation before planning a bulk study.
This guide is based on official public documentation reviewed on October 12, 2026. The Python request and response handling were tested with offline fixtures; no authenticated patent search was executed.
Define your patent query and inspect the endpoint
Start with one reproducible question
Write down the technical concept, the expected vocabulary and the purpose of the search. For example, a researcher could start with solid state battery electrolyte, then review whether the returned documents actually concern the intended electrolyte technology. This is an illustrative research query, not a claim about the documents it will return.
Google Patents' own search interface documents phrases, inventor and assignee fields, classifications and date filters. Use that reference to understand the search task, while checking which inputs your selected API exposes. Google Patents search help
For Glasser's published serper:/patents contract:
| Input | Published use |
|---|---|
q | A nonempty text query |
inventor | A nonempty inventor name |
assignee | A nonempty assignee name |
gl, hl | Optional two-letter country and language codes |
The endpoint description requires at least one of the three query inputs. The sample below supplies q. Its public schema has no page or num property, and the page describes one results page per call. Keep pagination or advanced filters from other providers out of this request. Serper patent endpoint in Glasser
Review price and execution separately
Use Inspect to obtain the supported version, native input schema, execution mode, timeout and price. The endpoint's public page does not publish a stable output schema. The code therefore saves the full Run and leaves patent-field mapping until you inspect an authorized response.
A version identifies the supported contract. Glasser's current reference says it does not lock the price for future Runs; the price at admission applies to the accepted Run. Review the terms near execution, including empty-result charges. Inspect reference
Capture a patent search Run with Python
Save a request plan before executing it
Use Python 3.10 or later with requests installed in a virtual environment. Set GLASSER_API_KEY privately in the server environment and set PATENT_QUERY to your research phrase. The script's local plan contains the request and a generated idempotency key, but never the API credential.
Save this as patent_search.py:
"""One documented Glasser patent request; no automatic retries or polling."""
import json
import os
import sys
import uuid
from pathlib import Path
import requests
BASE = "https://api.glasser.ai/v1"
def api(method, path, body=None, key=None, timeout=40,
request=requests.request):
token = os.environ.get("GLASSER_API_KEY", "").strip()
if not token:
raise ValueError("Set GLASSER_API_KEY in the server environment")
headers = {"Authorization": f"Bearer {token}"}
if key:
headers["Idempotency-Key"] = key
try:
response = request(method, BASE + path, json=body,
headers=headers, timeout=(5, timeout),
allow_redirects=False)
except requests.RequestException:
raise RuntimeError("Transport failed; preserve the saved plan") from None
if response.status_code not in (200, 202):
raise RuntimeError(f"Glasser HTTP {response.status_code}")
try:
data = response.json()
except ValueError:
raise RuntimeError("Response is not valid JSON") from None
if not isinstance(data, dict):
raise RuntimeError("Unexpected response shape")
return data
def prepare(query, path, call=api):
if path.exists():
raise ValueError("Plan exists; use a new file for a new execution")
if not query.strip():
raise ValueError("A patent query is required")
contract = call("POST", "/endpoints/inspect", {
"provider": "serper", "endpoint": "/patents",
})
version = contract.get("endpoint_version")
if type(version) is not int or version < 1:
raise RuntimeError("Inspect did not return an endpoint version")
timeout_ms = contract.get("timeout_ms")
timeout = max(40, (timeout_ms or 0) / 1000 + 10)
plan = {
"idempotency_key": str(uuid.uuid4()),
"request": {"provider": "serper", "endpoint": "/patents",
"endpoint_version": version, "input": {"q": query}},
"timeout_seconds": timeout,
"inspected_contract": contract,
}
with path.open("x", encoding="utf-8") as handle:
json.dump(plan, handle, ensure_ascii=False, indent=2)
return plan
def summarize(run):
status = run.get("status")
if status not in ("QUEUED", "RUNNING", "COMPLETED", "FAILED", "STOPPED"):
raise RuntimeError("Unknown Run status; inspect the saved response")
provider = run.get("provider_response") or {}
http_status = provider.get("http_status")
usable = (status == "COMPLETED" and type(http_status) is int
and 200 <= http_status < 300 and not provider.get("error"))
return {"id": run.get("id"), "status": status,
"provider_http_status": http_status,
"charge_usd": run.get("charge_usd"),
"ready_for_content_review": usable}
def main():
command, filename = sys.argv[1:3]
path = Path(filename)
if command == "inspect":
plan = prepare(os.environ.get("PATENT_QUERY", ""), path)
print(json.dumps(plan["inspected_contract"], indent=2))
return
plan = json.loads(path.read_text(encoding="utf-8"))
if command == "run":
run = api("POST", "/runs", plan["request"],
plan["idempotency_key"], plan["timeout_seconds"])
elif command == "get":
run_id = str(uuid.UUID(sys.argv[3]))
run = api("GET", "/runs/" + run_id)
else:
raise ValueError("Use inspect, run or get")
output = path.with_name(path.stem + "-response.json")
output.write_text(json.dumps(run, ensure_ascii=False, indent=2),
encoding="utf-8")
print(json.dumps(summarize(run), indent=2))
if __name__ == "__main__":
try:
main()
except (ValueError, RuntimeError, OSError, IndexError) as error:
print(str(error), file=sys.stderr)
sys.exit(1)
First run the free inspection step:
python patent_search.py inspect battery-plan.json
Read the saved contract, confirm that your input fits its schema, and review the current price. The script prepares only the documented q input; it is not a general JSON Schema validator. Once you decide to spend on the request, execute the saved plan:
python patent_search.py run battery-plan.json
The response is saved as battery-plan-response.json. If the request times out or its connection is lost, keep the same plan and execution parameters. Re-running the command reuses the saved idempotency key. Use a new plan file only for an intentionally new execution. Glasser Run and retry contract
Read a pending Run without starting another search
If the summary reports QUEUED or RUNNING, use its returned ID:
python patent_search.py get battery-plan.json RETURNED_RUN_UUID
Replace RETURNED_RUN_UUID with the actual ID. This command performs one status read and updates the saved response. The example implements no automatic polling, retries or cancellation.
The local ready_for_content_review flag means the Run completed with a successful provider HTTP status and no reported provider error. It does not establish relevance, completeness, a nonempty result or a fixed patent schema. Examine the saved output next. Get a Run
Turn the response into a traceable research record
Keep the raw response before normalizing fields
The public endpoint describes results containing titles, snippets, publication numbers, inventors, assignees and dates. It does not guarantee JSON key names. Confirm the returned shape and provider documentation before implementing paths such as output.patents; that path is intentionally absent from this example.
After reviewing a real response, map its available values into your own record:
| Suggested record field | Why retain it |
|---|---|
| Query and retrieval timestamp | Reproduce the discovery attempt |
| Provider, endpoint, version and Run ID | Trace the request and charge |
| Publication identifier, including country/kind code when supplied | Distinguish documents more reliably than title alone |
| Patent source URL | Reopen the underlying document |
| Title and relevant snippet | Explain why the document entered the candidate set |
| Inventor and assignee as supplied | Preserve the source wording before normalization |
| Filing, publication, priority and grant dates when available | Keep different bibliographic events separate |
| Researcher's relevance note | Record the reason for including or excluding the document |
These are editorial record-design recommendations. Preserve absent fields as missing, and retain original values when normalizing names or dates. A retrieval timestamp cannot fill a missing filing date.
Review the document behind the result
Open the source and check the exact publication, relevant passages and available bibliographic fields. A short snippet can omit the context needed to decide whether the document addresses your technical question.
When several records look similar, retain their identifiers until you establish the relationship. Matching titles or assignee names alone are insufficient grounds for collapsing documents into a single invention. Record any family grouping as a separate analysis decision with its evidence.
Handle missing results and incomplete coverage
Change one query condition at a time
An empty result describes this query and retrieval path. It does not establish the absence of relevant patent literature. Check status and provider errors first; then review the vocabulary, language, inventor or assignee spelling and any restrictions you applied.
Keep a short query log with the reason for each change. For example, broadening a technical phrase and removing an assignee condition are different experiments. Recording them separately makes later comparisons understandable.
Google's coverage documentation describes the sources available in its patent search. Coverage, translations and document availability need review for your research scope. One provider result page should not be treated as an exhaustive corpus.
Resolve execution failures before interpreting the research
COMPLETED means a provider response is available; examine its HTTP status and error. FAILED calls for reading the Run's failure information. Read charge_usd independently, since the execution state alone does not establish the charge. Glasser Run lifecycle
The script saves the response before interpreting it, so an unfamiliar status remains available for diagnosis. A missing or unusable response must not become a fabricated empty patent list. If you need more than the published single-page operation, inspect available patent data operations for a documented route that fits your scope.
Use the resulting shortlist for research and source review. Legal decisions about a patent require the underlying records and appropriate professional analysis; this retrieval workflow does not perform that analysis.
Frequently asked questions
Is this an official Google Patents API client?
The code calls Glasser's documented API and selects its Serper patent-search operation. Google Patents is the searched source; Glasser and Serper define the request and delivery contract used here.
Can I retrieve every matching patent by increasing a limit?
The published Glasser Serper schema used here exposes neither a result-count field nor a page field. Inspect the current contract or select an operation designed for deeper retrieval before building a pagination loop.
Can I search by inventor or assignee?
The public operation accepts those inputs. Adapt the plan only after reviewing the inspected schema, and create a new intended execution with a new idempotency key when you change its input.
Does an endpoint version keep the same price?
Glasser's current API reference says new Runs use the price at admission, even when the endpoint version stays the same. Review the current price before execution and retain the final charge with the Run.
When should I use a patent dataset instead?
A dataset is a better candidate when the task requires large-scale SQL analysis across a defined corpus. Check its current coverage, update cadence and query costs; this article's single-query capture does not validate those requirements.
Related posts
View more
8 min read
How to Use a Google Image Search API with Python
Use Python to retrieve Google image results. Check existing-customer access, compare the Glasser path, and retain image URLs, source pages and limits.

8 min read
Free Web Search APIs: Which Should Your AI Agent Use?
Choose a free search API for your AI agent. Compare APIs that return links, page content, or Google results, and estimate the cost after free usage.
Make your agent
work with real data.
Search, inspect, and run data APIs through one Glasser key. Turn your next question into a result you can use.
Get started with Glasser