---------------------------------------------------------------------- This is the API documentation for the serpapi library. ---------------------------------------------------------------------- ## Search Client Main entry points for making requests and working with responses. Client(*, api_key=None, timeout=None) A class that handles API requests to SerpApi in a user-friendly manner. Store your API key in an environment variable, then create a client with ``serpapi.Client(api_key=os.environ["SERPAPI_KEY"])``. :param api_key: The API Key to use for SerpApi.com. :param timeout: The default timeout to use for requests. SerpResults(data, *, client) A dictionary-like object that represents the results of a SerpApi request. An instance of this class is returned if the response is a valid JSON object. It can be used like a dictionary, but also has some additional methods. ## Exceptions Errors raised by the client for API, HTTP, connection, and timeout failures. SerpApiError Base class for exceptions in this module. APIKeyNotProvided API key is not provided. SearchIDNotProvided Search ID is not provided. HTTPError(original_exception) HTTP Error. HTTPConnectionError(original_exception) Connection Error. TimeoutError(*args: 'Any', **kwargs: 'Any') -> 'None' Timeout Error. ---------------------------------------------------------------------- This is the User Guide documentation for the package. ---------------------------------------------------------------------- ## Basics # Getting Started SerpApi Python is the official Python client for [SerpApi](https://serpapi.com). It wraps SerpApi HTTP endpoints with a small Python API while keeping request parameters close to the underlying API. Use this page to install the package, configure your API key, and make a first Google Search request. ## Installation :::{.panel-tabset} ## pip ```bash pip install serpapi ``` ## uv project ```bash uv add serpapi ``` ## uv environment ```bash uv pip install serpapi ``` ::: Python 3.6 or newer is required by the package. Create or sign in to your SerpApi account, copy your API key from the [dashboard](https://serpapi.com/manage-api-key), and set it in the environment: :::{.panel-tabset} ## macOS / Linux ```bash export SERPAPI_KEY="secret_api_key" ``` ## Windows ```powershell $env:SERPAPI_KEY = "secret_api_key" ``` ::: ## First Search ```python import os import serpapi client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) results = client.search( engine="google", q="coffee shops", location="Austin, Texas", hl="en", gl="us", ) first_result = results["organic_results"][0] print(first_result["title"]) print(first_result["link"]) ``` `client.search()` returns a `SerpResults` object for JSON responses. It behaves like a dictionary and adds helpers such as `as_dict()`, `next_page()`, and `yield_pages()`. ## What the Parameters Mean The example above sends a Google Search request: | Parameter | Purpose | | --- | --- | | `engine` | Selects the SerpApi engine. `google` is Google Search. | | `q` | Search query. | | `location` | Search location used by SerpApi. | | `hl` | Interface language. | | `gl` | Country for Google results. | SerpApi supports many engines and engine-specific parameters. The authoritative list lives in the [SerpApi API documentation](https://serpapi.com/search-api). The [SerpApi Playground](https://serpapi.com/playground) is the fastest way to build and test a request before moving it into Python. ## When to Use the Client Use `serpapi.Client` for application code, scripts that make more than one request, pagination, and concurrent workloads. The client stores the API key, timeout, and HTTP session configuration in one place. The module-level helpers are useful for quick experiments: ```python import serpapi results = serpapi.search( api_key="secret_api_key", engine="google", q="coffee", ) ``` For production code, prefer a client instance: ```python client = serpapi.Client(api_key="secret_api_key", timeout=20) results = client.search(engine="google", q="coffee") ``` ## Next Steps - Read [Client Usage](client-usage.md) for response helpers, request options, and archive helpers. - Read [Pagination](pagination.md) when collecting more than one page of results. - Try [Google Across Countries](../docs/examples/google-across-countries.md) for a practical localization example. # Client Usage The primary interface is `serpapi.Client`. A client keeps the API key, timeout, and HTTP session configuration together, which is useful for applications and scripts that make more than one request. ## Create a Client ```python import os import serpapi client = serpapi.Client( api_key=os.environ["SERPAPI_KEY"], timeout=20, ) ``` `timeout` becomes the default request timeout for searches, archive lookups, account calls, and locations calls made by this client. ## Search Pass engine parameters as keyword arguments: ```python results = client.search(engine="google", q="coffee") ``` You can also pass a dictionary when parameters are already stored in one: ```python params = { "engine": "google", "q": "coffee", } results = client.search(params) ``` Dictionary parameters and keyword arguments can be mixed. Keyword arguments update the dictionary, which is useful when you start from a saved parameter set: ```python params = {"engine": "google", "q": "coffee"} results = client.search(params, location="Austin, Texas") ``` ## Module Helpers For quick scripts, the package exposes module-level helpers: ```python import serpapi results = serpapi.search( api_key="secret_api_key", engine="google", q="coffee", ) ``` The helpers use a shared client under the hood. For applications, tests, pagination, and concurrent workloads, prefer creating your own `serpapi.Client`. ## Search Archive Use `search_archive()` when you have a SerpApi search ID: ```python search_id = results["search_metadata"]["id"] archived = client.search_archive(search_id=search_id) ``` If `search_id` is missing, the client raises `serpapi.SearchIDNotProvided`. ## Account and Locations ```python account = client.account() locations = client.locations(q="Austin", limit=3) ``` `account()` returns account information for the configured API key. `locations()` returns supported Google locations that match the query; see [Account and Locations](account-and-locations.md) for the local guide and example. ## Request Options `search()`, `search_archive()`, `account()`, and `locations()` pass these keyword arguments to the underlying `requests` call: | Option | Use | | --- | --- | | `timeout` | Override the client timeout for one request. | | `proxies` | Send the request through a proxy. | | `verify` | Control TLS certificate verification. | | `stream` | Stream the HTTP response. | | `cert` | Use a client certificate. | Example: ```python results = client.search( engine="google", q="coffee", timeout=10, ) ``` See [Request Options](request-options.md) for proxy, TLS, certificate, and per-request timeout examples. ## Response Objects JSON search responses are returned as `serpapi.SerpResults`. It behaves like a dictionary: ```python first = results["organic_results"][0] print(first.get("title")) print(first.get("link")) ``` Use `as_dict()` when another library needs a plain dictionary: ```python payload = results.as_dict() ``` If you request `output=html`, the response is plain text instead of `SerpResults`: ```python html = client.search(engine="google", q="coffee", output="html") print(html[:500]) ``` ## Pagination Helpers For one additional page, call `next_page()`: ```python next_results = results.next_page() ``` To iterate through all available pages, use `yield_pages()`: ```python for page_number, page in enumerate(results.yield_pages(max_pages=10), start=1): current = page.get("serpapi_pagination", {}).get("current", page_number) print(current) ``` See [Pagination](pagination.md) for fuller pagination examples and Google `start` offsets. ## Error Handling The client raises SerpApi-specific exceptions for common failure modes: ```python import serpapi try: results = client.search(engine="google", q="coffee") except serpapi.TimeoutError: print("The request timed out.") except serpapi.HTTPConnectionError: print("Could not connect to SerpApi.") except serpapi.HTTPError as exc: print(exc.status_code, exc.error) ``` See [Errors and Timeouts](errors-and-timeouts.md) for status handling guidance. ## User Guide # Parameters and Engines SerpApi Python forwards search parameters to the SerpApi HTTP API. The package does not keep a separate engine schema, so new engines and engine parameters can be used as soon as they are supported by SerpApi. ## Full Engine and Parameter Reference Use these SerpApi resources as the source of truth: - [SerpApi Search API documentation](https://serpapi.com/search-api) lists supported engines and engine-specific parameters. - [SerpApi Playground](https://serpapi.com/playground) lets you test a search and copy the exact parameters into Python. - [Account and Locations](account-and-locations.md) shows how to find valid `location` values from Python. The Search API docs include engines such as Google Search, Google Maps, Google Images, Google Shopping, Google Scholar, Google Jobs, Bing, DuckDuckGo, Yahoo, Yandex, Baidu, YouTube, eBay, Walmart, Naver, Apple App Store, Home Depot, and many more. Check the docs for the current full list. ## Passing Parameters Pass engine parameters as keyword arguments: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", hl="en", gl="us", ) ``` You can also pass a dictionary when you already have parameters in one: ```python params = { "engine": "google", "q": "coffee", "location": "Austin, Texas", "hl": "en", "gl": "us", } results = client.search(params) ``` ## Common Google Parameters These are common Google Search parameters. Other engines have their own parameter names. | Parameter | Purpose | | --- | --- | | `engine` | Search engine. Use `google` for Google Search. | | `q` | Search query. | | `location` | Geographic location for the search. | | `google_domain` | Google domain, such as `google.com` or `google.co.in`. | | `gl` | Country code for the search. | | `hl` | Interface language. | | `start` | Result offset for pagination. | | `device` | Device type, such as desktop or mobile. | | `output` | Response format, usually `json` or `html`. | | `async` | Submit a server-side async search. | | `no_cache` | Force SerpApi to fetch fresh results. | | `zero_trace` | Request zero data retention behavior when enabled for your account. | | `json_restrictor` | Return only selected JSON fields from the API response. | For the full supported list and the exact meaning of each parameter, use the [SerpApi Search API documentation](https://serpapi.com/search-api). ## Engine-Specific Names Different engines use different query parameter names. For example: ```python google = client.search(engine="google", q="coffee") ebay = client.search(engine="ebay", _nkw="coffee grinder") youtube = client.search(engine="youtube", search_query="coffee brewing") walmart = client.search(engine="walmart", query="coffee") ``` When in doubt, open the engine in the [SerpApi Playground](https://serpapi.com/playground), set up the search, and copy the generated parameters. # Pagination Many SerpApi responses include pagination metadata. SerpApi Python exposes this through `SerpResults.next_page_url`, `next_page()`, and `yield_pages()`. ## Fetch One More Page ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", ) next_results = results.next_page() if next_results: for item in next_results.get("organic_results", []): print(item.get("title")) ``` `next_page()` returns `None` when the response does not include a next page URL. ## Iterate Through Pages Use `yield_pages()` when you want the current page plus following pages: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", ) for page in results.yield_pages(max_pages=5): for item in page.get("organic_results", []): print(item.get("position"), item.get("title")) ``` Always set `max_pages` deliberately. Search result pages can change over time and some queries expose many pages. ## Google `start` Offsets Google Search also supports explicit result offsets: ```python for start in [0, 10, 20]: page = client.search( engine="google", q="coffee", location="Austin, Texas", start=start, ) print("Offset:", start) for item in page.get("organic_results", []): print(item.get("title")) ``` Use this style when you need deterministic offsets or when you want to parallelize independent pages. ## Store Only What You Need Search responses can be large. For long crawls or scheduled jobs, extract and store only the fields your application needs: ```python records = [] for page in results.yield_pages(max_pages=3): for item in page.get("organic_results", []): records.append({ "title": item.get("title"), "link": item.get("link"), "snippet": item.get("snippet"), }) ``` ## Pagination Parameters Vary by Engine `start` is common for Google Search, but other engines may use different pagination parameters. Check the relevant engine page in the [SerpApi Search API documentation](https://serpapi.com/search-api) or build the request in the [SerpApi Playground](https://serpapi.com/playground). # Errors and Timeouts SerpApi Python wraps common failure modes in package-specific exceptions while preserving useful details from `requests`. ## HTTP Errors Non-200 responses raise `serpapi.HTTPError`: ```python import serpapi try: results = client.search(engine="google", q="coffee") except serpapi.HTTPError as exc: print("Status:", exc.status_code) print("Error:", exc.error) ``` `exc.status_code` contains the HTTP status code when available. `exc.error` contains the `error` field from SerpApi's JSON response when available. See [SerpApi API status and error codes](https://serpapi.com/api-status-and-error-codes) for status guidance. ## Connection Errors and Timeouts ```python try: results = client.search(engine="google", q="coffee", timeout=10) except serpapi.TimeoutError: print("The request timed out.") except serpapi.HTTPConnectionError: print("Could not connect to SerpApi.") ``` Set a default timeout on the client: ```python client = serpapi.Client(api_key="secret_api_key", timeout=20) ``` Override it for one request: ```python results = client.search( engine="google", q="coffee", timeout=5, ) ``` ## Missing Search IDs `search_archive()` requires a `search_id`: ```python try: archived = client.search_archive() except serpapi.SearchIDNotProvided: print("Provide search_id from search_metadata.id.") ``` ## API-Level Errors in JSON Some API responses may include an `error` field in JSON. If your workflow continues after a response is returned, check for that field before using result arrays: ```python results = client.search(engine="google", q="coffee") if "error" in results: raise RuntimeError(results["error"]) ``` # Account and Locations The client includes helpers for SerpApi account metadata and Google locations. ## Account Use `account()` to inspect information for the configured API key: ```python import os import serpapi client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) account = client.account() print(account) ``` This is useful in diagnostics, internal tooling, and setup checks. ## Locations Use `locations()` to find supported Google locations: ```python locations = client.locations(q="Austin", limit=5) for location in locations: print(location.get("name"), location.get("canonical_name")) ``` Then pass the selected location to a search: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas, United States", ) ``` The [SerpApi Locations API documentation](https://serpapi.com/locations-api) has the full endpoint behavior. ## Migration # Migrating from google-search-results SerpApi has two Python libraries that use similar import names. For new projects and active integrations, use the recommended `serpapi` package. ## Recommended Package The new and recommended client is [`serpapi` on PyPI](https://pypi.org/project/serpapi/). Install it with: ```bash pip install serpapi ``` Use `serpapi.Client`: ```python import os import serpapi YOUR_API_KEY = os.environ["SERPAPI_KEY"] client = serpapi.Client(api_key=YOUR_API_KEY) results = client.search(engine="google", q="coffee") print(results) ``` This is the package used throughout the current documentation. ## Deprecated Package The old Python SDK is [`google-search-results` on PyPI](https://pypi.org/project/google-search-results/). It is deprecated for new integrations. It was installed with: ```bash pip install google-search-results ``` Older code often looks like this: ```python from serpapi import GoogleSearch search = GoogleSearch({ "q": "coffee", "location": "Austin,Texas", "api_key": "", }) result = search.get_dict() ``` Do not add this package to new projects. ## Update Your Dependencies Remove `google-search-results` from your dependency files, such as `requirements.txt`, `pyproject.toml`, `setup.py`, `Pipfile`, or Poetry dependency configuration. Then add `serpapi` instead: ```bash pip install serpapi ``` Avoid installing both packages in the same environment. They can share the `serpapi` import namespace, which makes migration harder to reason about. ## Update Your Code Replace `GoogleSearch(...).get_dict()` with `serpapi.Client(...).search(...)`. Old: ```python from serpapi import GoogleSearch search = GoogleSearch({ "q": "coffee", "location": "Austin,Texas", "api_key": "", }) result = search.get_dict() ``` New: ```python import os import serpapi client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search( engine="google", q="coffee", location="Austin, Texas", ) ``` Search parameters use the same SerpApi names, so most request parameter usage can move over directly. Prefer passing them as keyword arguments in new code; dictionaries are still accepted when migration code already has parameters in a mapping. ## Migration Checklist - Remove `google-search-results` from requirements and dependency files. - Install `serpapi` with `pip install serpapi`. - Replace `from serpapi import GoogleSearch` with `import serpapi`. - Replace `GoogleSearch(params).get_dict()` with `serpapi.Client(api_key=...).search(engine=..., q=..., ...)`. - Keep using the [SerpApi Playground](https://serpapi.com/playground) and the [SerpApi API documentation](https://serpapi.com/search-api) to confirm engine parameters. ## Advanced Usage # Async Search Archive SerpApi supports server-side async searches. This is different from Python `asyncio`: you submit a search with `async=true`, receive a search ID, and retrieve the completed search later with the Search Archive API. ## Submit an Async Search ```python submitted = client.search( engine="google", q="coffee", location="Austin, Texas", **{"async": True}, ) search_id = submitted["search_metadata"]["id"] print(search_id) ``` ## Retrieve the Search ```python archived = client.search_archive(search_id=search_id) status = archived.get("search_metadata", {}).get("status") print(status) ``` If the search is still queued or processing, wait and call `search_archive()` again: ```python import time while True: archived = client.search_archive(search_id=search_id) status = archived.get("search_metadata", {}).get("status") if status == "Success": break if status == "Error": raise RuntimeError(archived.get("error", "Search failed")) time.sleep(2) ``` ## When to Use Async Searches Async searches are useful when you want to submit work quickly and collect results later, especially from job queues, scheduled workers, or data pipelines. Do not combine `async=true` with `no_cache=true`. Use the [SerpApi Search Archive API documentation](https://serpapi.com/search-archive-api) for retention windows and status details. # Threading SerpApi requests are network-bound, so threads are often a simple way to run independent searches concurrently. ## ThreadPoolExecutor Example ```python import os import serpapi from concurrent.futures import ThreadPoolExecutor, as_completed API_KEY = os.environ["SERPAPI_KEY"] def search_country(country): client = serpapi.Client(api_key=API_KEY, timeout=20) results = client.search( engine="google", q="best coffee beans", gl=country, hl="en", ) return country, results.get("organic_results", []) countries = ["us", "gb", "ca", "au", "in"] with ThreadPoolExecutor(max_workers=5) as executor: futures = [executor.submit(search_country, country) for country in countries] for future in as_completed(futures): country, organic_results = future.result() first = organic_results[0] if organic_results else {} print(country, first.get("title")) ``` ## Practical Guidance - Keep `max_workers` modest and tune it for your quota, latency, and downstream processing. - Handle exceptions per future so one failed request does not hide all other results. - Create a client inside each worker when you want clear isolation between threads. - Use explicit timeouts so blocked network calls do not stall the whole batch. ## Handling Per-Request Errors ```python with ThreadPoolExecutor(max_workers=5) as executor: future_to_country = { executor.submit(search_country, country): country for country in countries } for future in as_completed(future_to_country): country = future_to_country[future] try: country, organic_results = future.result() except serpapi.SerpApiError as exc: print("Failed:", country, exc) continue print("Finished:", country, len(organic_results)) ``` # Multiprocessing Use multiprocessing when each search has heavy CPU-bound post-processing, when you need process isolation, or when your worker code already runs in a process pool. For simple network-bound searches, threads are usually lighter. ## ProcessPoolExecutor Example ```python import os import serpapi from concurrent.futures import ProcessPoolExecutor, as_completed def search_country(country): client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) results = client.search( engine="google", q="best coffee beans", gl=country, hl="en", ) organic_results = results.get("organic_results", []) return { "country": country, "count": len(organic_results), "first_title": organic_results[0].get("title") if organic_results else None, } if __name__ == "__main__": countries = ["us", "gb", "ca", "au", "in"] with ProcessPoolExecutor(max_workers=4) as executor: futures = [executor.submit(search_country, country) for country in countries] for future in as_completed(futures): print(future.result()) ``` The `if __name__ == "__main__"` guard is important for multiprocessing, especially on macOS and Windows. ## Practical Guidance - Create the `serpapi.Client` inside the worker process. - Return plain serializable data such as dictionaries, lists, strings, and numbers. - Avoid passing open sessions, response objects, or client instances between processes. - Set explicit timeouts. - Prefer threading for simple concurrent HTTP requests unless CPU-heavy work makes multiprocessing worthwhile. ## Combining Pagination and Processes For Google Search, independent `start` offsets can be distributed across workers: ```python def search_offset(start): client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=20) results = client.search( engine="google", q="coffee", location="Austin, Texas", start=start, ) return results.get("organic_results", []) ``` Check the relevant engine docs before parallelizing offsets because pagination parameters vary by engine. # Zero Trace and Data Retention SerpApi exposes request parameters for data retention and cache behavior. The Python client passes these parameters through to the API. ## Zero Trace When enabled for your account, pass `zero_trace=true` to request zero data retention behavior for a search: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", zero_trace=True, ) ``` Use this for workloads that require stricter data handling. Zero trace availability and behavior are account-dependent, so confirm details in the [SerpApi Search API documentation](https://serpapi.com/search-api) and your plan. ## Cache Controls Use `no_cache=true` when you want SerpApi to fetch fresh results instead of using cached results: ```python results = client.search( engine="google", q="coffee", no_cache=True, ) ``` `no_cache=true` and `async=true` should not be used together. ## Choosing Between Modes | Need | Parameter | | --- | --- | | Fresh live results | `no_cache=true` | | Submit now and fetch later | `async=true` plus `search_archive()` | | Zero data retention behavior | `zero_trace=true` when enabled for your account | See [Async Search Archive](async-search-archive.md) for async search usage. # JSON Restrictor JSON Restrictor is a SerpApi request parameter that limits the JSON response to selected fields before the response is returned to your Python code. Use it for AI workflows, RAG ingestion, reports, and production jobs that only need a narrow subset of a large engine response. SerpApi supports `json_restrictor` for all engines. The Python client forwards the selector string with the rest of your search parameters. See the [SerpApi JSON Restrictor documentation](https://serpapi.com/json-restrictor) for the full selector reference. ## Select a Top-Level Section Return only `organic_results`: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", json_restrictor="organic_results", ) for result in results.get("organic_results", []): print(result.get("title")) ``` ## Select Fields From Each Result Use `[]` to apply a selector to every item in an array. Use a subquery to keep multiple fields from each object: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", json_restrictor="organic_results[].{title, link, snippet}", ) for result in results.get("organic_results", []): print(result["title"], result["link"]) ``` The response still uses the normal SerpApi JSON shape, but each matching result only contains the selected fields. ## Select One Item or a Slice Use an array index when you only need one item: ```python results = client.search( engine="google", q="coffee", json_restrictor="organic_results[0]", ) first_result = results["organic_results"][0] print(first_result["title"]) ``` Use a half-open array slice when you need a fixed number of items: ```python results = client.search( engine="google", q="coffee", json_restrictor="organic_results[0:3]", ) ``` `organic_results[0:3]` keeps indexes `0`, `1`, and `2`. ## Combine Multiple Selectors Separate selectors with commas when your workflow needs more than one part of the response: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", json_restrictor="local_map, organic_results[0]", ) print(results.get("local_map", {}).get("gps_coordinates")) print(results["organic_results"][0]["title"]) ``` ## Nested Fields Selectors can keep nested values while dropping the surrounding fields you do not use: ```python results = client.search( engine="google", q="coffee", json_restrictor="organic_results[].{title, sitelinks.inline[].link}", ) ``` This is useful when downstream code only needs a compact list of titles and related links. ## Common Selector Patterns | Need | `json_restrictor` | | --- | --- | | One top-level section | `organic_results` | | First organic result | `organic_results[0]` | | First three organic results | `organic_results[0:3]` | | One field from every result | `organic_results[].title` | | Multiple fields from every result | `organic_results[].{title, snippet}` | | Nested fields | `organic_results[].{title, sitelinks.inline[].link}` | | Multiple response sections | `local_map, organic_results[0]` | ## Practical Guidance - Start without `json_restrictor`, inspect the response shape, then add selectors for the fields your workflow actually needs. - Keep selectors close to the engine response you tested. Different engines expose different result sections and field names. - If you plan to call `next_page()` or `yield_pages()`, include `serpapi_pagination` in the selector so the client can find the next-page URL. - If you need a search ID, status, or archive metadata, include `search_metadata`. For paginated collection, keep both the fields you want and the pagination metadata: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", json_restrictor="organic_results[].{title, link}, serpapi_pagination", ) for page in results.yield_pages(max_pages=3): for result in page.get("organic_results", []): print(result["title"], result["link"]) ``` # Request Options SerpApi Python separates SerpApi query parameters from options passed to the underlying `requests` library. SerpApi parameters, such as `engine`, `q`, `location`, `hl`, `gl`, `no_cache`, and `json_restrictor`, are sent to SerpApi as API request parameters. Request options, such as `timeout` and `proxies`, configure the local HTTP request made by the Python client. ## Supported Request Options The client passes these keyword arguments to `requests.Session.request()`: | Option | Use | | --- | --- | | `timeout` | Override the client timeout for one request. | | `proxies` | Send the request through HTTP or HTTPS proxies. | | `verify` | Control TLS certificate verification. | | `stream` | Ask `requests` to stream the HTTP response. | | `cert` | Use a client certificate. | These options are supported by `search()`, `search_archive()`, `account()`, and `locations()`. ## Per-Request Timeout Set a default timeout when creating the client: ```python client = serpapi.Client(api_key="secret_api_key", timeout=20) ``` Override it for a single request: ```python results = client.search( engine="google", q="coffee", timeout=5, ) ``` `timeout=5` is passed to `requests`; it is not sent to SerpApi as a search parameter. ## Proxies Pass a `requests`-style proxies dictionary: ```python results = client.search( engine="google", q="coffee", proxies={ "https": "http://proxy.example.com:8080", }, ) ``` Keep proxy credentials in environment variables or your secret manager rather than hardcoding them in source files. ## TLS Verification By default, `requests` verifies TLS certificates. You can pass a custom CA bundle path: ```python results = client.search( engine="google", q="coffee", verify="/path/to/ca-bundle.pem", ) ``` Only disable verification for controlled local debugging: ```python results = client.search( engine="google", q="coffee", verify=False, ) ``` Do not use `verify=False` in production code. ## Client Certificates Pass a client certificate path, or a `(cert, key)` tuple, using `cert`: ```python results = client.search( engine="google", q="coffee", cert=("/path/to/client-cert.pem", "/path/to/client-key.pem"), ) ``` ## Combining Search Parameters and Request Options Request options can be used alongside normal SerpApi parameters: ```python results = client.search( engine="google", q="coffee", location="Austin, Texas", hl="en", gl="us", json_restrictor="organic_results[].{title, link}", timeout=10, ) ``` The client handles this in two steps: - `timeout`, `proxies`, `verify`, `stream`, and `cert` are passed to `requests`. - All remaining keyword arguments are sent to SerpApi as API parameters. If you pass a parameter dictionary and keyword arguments together, the remaining keyword arguments update the dictionary before the request is sent: ```python params = {"engine": "google", "q": "coffee"} results = client.search(params, location="Austin, Texas", timeout=10) ``` In this example, `location` is added to the SerpApi request parameters, while `timeout` is passed to `requests`. When you want to keep the original dictionary unchanged, pass a copy: ```python params = {"engine": "google", "q": "coffee"} results = client.search(params.copy(), location="Austin, Texas") ```