Glasser
← All posts

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.

An amber magnifying glass rests over ceramic invention drawings and gears beside a small globe.

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 taskUseful starting pointExpected review
Discover documents about a technologyA patent-search operationQuery relevance, document identifiers and source links
Examine a document you already knowThe patent's source pageFull text, bibliographic data and the precise document version
Analyze a large patent corpusA documented dataset and query engineDataset 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:

InputPublished use
qA nonempty text query
inventorA nonempty inventor name
assigneeA nonempty assignee name
gl, hlOptional 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

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 fieldWhy retain it
Query and retrieval timestampReproduce the discovery attempt
Provider, endpoint, version and Run IDTrace the request and charge
Publication identifier, including country/kind code when suppliedDistinguish documents more reliably than title alone
Patent source URLReopen the underlying document
Title and relevant snippetExplain why the document entered the candidate set
Inventor and assignee as suppliedPreserve the source wording before normalization
Filing, publication, priority and grant dates when availableKeep different bibliographic events separate
Researcher's relevance noteRecord 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.