From 090f816c533eb4621e51b2813ebf24da54f1cc4b Mon Sep 17 00:00:00 2001 From: audrey-serpapi Date: Wed, 14 Oct 2026 16:08:33 -0400 Subject: [PATCH 1/6] edited: quickstart, added: features, response formats, configuration, search asynchronous, more examples, reordered: examples, headers like documentation, removed: 'Markdown output for AI agents' section (as it was already included in the response formats) --- README.md | 508 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 402 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 2af6912..0d27090 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,58 @@ # SerpApi Python Library & Package [![Package](https://img.shields.io/pypi/v/serpapi?color=green)](https://pypi.org/project/serpapi) [![serpapi-python](https://github.com/serpapi/serpapi-python/actions/workflows/ci.yml/badge.svg)](https://github.com/serpapi/serpapi-python/actions/workflows/ci.yml) -Integrate search data into your AI workflow, RAG / fine-tuning, or Python application using this official wrapper for [SerpApi](https://serpapi.com). +Integrate search data into your AI workflow, RAG / fine-tuning, or Python application using this official [SerpApi Python SDK](https://serpapi.com/integrations/python). SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, App Stores, and [more](https://serpapi.com). -Query a vast range of data at scale, including web search results, flight schedules, stock market data, news headlines, and [more](https://serpapi.com). - ## Installation -To install the `serpapi` package, simply run the following command: +Python 3.6 or later is required. + +To install the `serpapi` package, simply run the following command inside your Python virtual environment: ```bash $ pip install serpapi ``` -Please note that this package is separate from the legacy `serpapi` module, which is available on PyPi as `google-search-results`. This package is maintained by SerpApi, and is the recommended way to access the SerpApi service from Python. +> Please note that this package is separate from the legacy `serpapi` module, +> which is available on PyPi as `google-search-results`. +> This package is maintained by SerpApi, and is the recommended way to access the +> SerpApi service from Python. + +## Quickstart + +[Create a SerpApi account](https://serpapi.com/dashboard) to get your API key, then store it in an environment variable: -## Quick start +```bash +export SERPAPI_KEY="your_api_key" +``` + +Environment variables are a secure, safe, and easy way to manage secrets. +Python accesses these variables from `os.environ["SERPAPI_KEY"]`. -Let's start by searching for Coffee on Google: +Run a Google search and access the results as a Python `Dictionary`: ```python import os import serpapi +from pprint import pprint -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google", "q": "coffee" }) -print(results) +pprint(results) ``` The `results` variable now contains a `SerpResults` object, which acts just like a standard dictionary, with some convenient functions added on top. -This example runs a search for "coffee" on Google. It then returns the results as a regular Python Hash. - See the [playground](https://serpapi.com/playground) to generate your own code. - -The SerpApi key can be obtained from [serpapi.com/signup](https://serpapi.com/users/sign_up?plan=free). +This example runs a search for "coffee" on Google. It then returns the results as a regular Python Hash. See the playground to generate your own code. -Environment variables are a secure, safe, and easy way to manage secrets. - Set `export SERPAPI_KEY=` in your shell. - Python accesses these variables from `os.environ["SERPAPI_KEY"]`. -### Error handling +### Error Handling Unsuccessful requests raise `serpapi.HTTPError` or `serpapi.TimeoutError` exceptions. The returned status code will reflect the sort of error that occurred, please refer to [Status and Error Codes Documentation](https://serpapi.com/api-status-and-error-codes) for more details. @@ -72,217 +79,534 @@ except serpapi.TimeoutError as e: # Handle timeout print(f"The request timed out: {e}") ``` +## Features -## Documentation +- **Asynchronous searches** for submitting non-blocking jobs and retrieving completed results from the Search Archive API. +- **Persistent connections and connection pooling** for reusing HTTP connections across searches. +- Search results as **Python dictionaries** with `search`, token-efficient **Markdown** with `md`, or raw **search-engine HTML** with `html`. +- SDK methods for the [Image API](https://serpapi.com/image-api), [Location API](https://serpapi.com/locations-api), [Search Archive API](https://serpapi.com/search-archive-api), and [Account API](https://serpapi.com/account-api). +- **Configurable HTTP timeouts** established by setting `timeout` in the client. -Documentation is [available on Read the Docs](https://serpapi-python.readthedocs.io/en/latest/). +## Response Formats -Change history is [available on GitHub](https://github.com/serpapi/serpapi-python/blob/master/HISTORY.md). +Use `search` and default output (none) for structured results decoded into a `Dictionary`: -### Markdown output for AI agents +```python +results = client.search({ + "engine": "google", + "q": "coffee" +}) +``` -For AI agents and LLM workflows, use `output="md"`. It returns search results with clean headings, links, and tables while using roughly half the tokens of JSON on average. +Use `md` output for a token-efficient Markdown String optimized for LLMs and AI agents: ```python markdown = client.search({ "engine": "google", "q": "coffee", - "output": "md", + "output": "md" +}) +``` + +Use `html` output when you need the raw search-engine response: +```python +raw_html = client.search({ + "engine": "google", + "q": "coffee", + "output": "html" +}) +``` + +Archived results are also available as Markdown with +`client.search_archive(search_id=search_id, output="md")`. + +Learn more about [SerpApi Markdown output](https://serpapi.com/markdown-output). + +## Configuration + +Set defaults when creating a client, then override search parameters in individual calls: + +```python +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY"), timeout=120) +results = client.search({ + "engine": "google", + "q": "coffee", +}) +``` +|Option | Default | Description| +|-------|---------|------------| +| `api_key` | None | Your SerpApi API key. Use an environment variable rather than committing it to source control. | +| `engine` | None | The search engine used by default, such as `google` or `google_maps`. | +| `timeout` | `120` | Timeout in seconds for non-persistent HTTP requests. | +| `async` | false | Submits searches without waiting for them to complete. It can be set on the client or per search.| + + +Search-engine-specific parameters can also be supplied when creating the client or calling `search`. Parameters passed to search override client defaults. + +### Search Asynchronous + +Search API features non-blocking search using the option: `async=true`. + +- Non-blocking - `async=true` - a single parent process can handle unlimited concurrent searches. +- Blocking - `async=false` - many processes must be forked and synchronized to handle concurrent searches. This strategy is I/O usage because each client would hold a network connection. + +> **Note:** `async` is a reserved keyword in Python 3.7+, so pass it inside the parameters dictionary (`{"async": True}`) rather than as a keyword argument. + +Here is an example of asynchronous searches using Python: + +```python +import os +import re +import time +from queue import Queue + +import serpapi + +company_list = ["meta", "amazon", "apple", "netflix", "google"] +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) +schedule_search = Queue() +result = None + +for company in company_list: + result = client.search({"engine": "google", "q": company, "async": True}) + if re.search(r"Cached", result["search_metadata"]["status"]): + print(f"{company}: search results found in cache for: {company}") + + schedule_search.put(result["search_metadata"]["id"]) + +print(f"Last search submitted at: {result['search_metadata']['created_at']}") + +print("wait 10s for all requests to be completed") +time.sleep(10) + +print("wait until all searches are cached or success") +while not schedule_search.empty(): + search_id = schedule_search.get() + + search_archived = client.search_archive(search_id=search_id) + + company = search_archived["search_parameters"]["q"] + status = search_archived["search_metadata"]["status"] + + if re.search(r"Cached|Success", status): + print(f"{company}: search results found in archive for: {company}") + continue + + if status == "Error": + print(f"{company}: search failed: {search_archived.get('error')}") + continue + + schedule_search.put(search_id) + time.sleep(1) + +print("done") +``` + +This code batches searches into a [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)). +Each search can take a few seconds to complete, so by the time the first ID is popped, its results are usually already in the archive. Searches that are still processing are put back in the queue and checked again. + +## Basic Examples in Python + +Here are some examples for some of our most popular APIs. You can find the full list of supported engines and parameters in our [documentation](https://serpapi.com/search-engine-apis). + +### Google Shopping + +Scrape Google Shopping results with product names, prices, ratings, and merchant information. + +```python +import serpapi +import os +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +results = client.search({ + "engine": "google_shopping", + "q": "Macbook M4" +}) +shopping_results = results["shopping_results"] +pprint(shopping_results) +``` + +[See documentation](https://serpapi.com/google-shopping-api) + +#### Google Shopping Light + +A [light variant](https://serpapi.com/google-shopping-light-api) engine called `google_shopping_light` is also available for faster, lower-cost shopping searches. + +### Google Images + +Scrape Google Images search results, including image URLs, thumbnails, titles, and source pages. + +```python +import os +import serpapi +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("API_KEY")) +results = client.search({ + 'engine': 'google_images', + 'q': 'coffee', +}) +pprint(results) +``` + +[See documentation](https://serpapi.com/google-images-api) + +#### Google Images Light + +A [light variant](https://serpapi.com/google-images-light-api) engine called `google_images_light` is also available for faster, lower-cost image searches. + +### Google Lens with Image URL or Upload + +Google Lens accepts either a publicly accessible image URL or an uploaded +image. To search by URL, pass the URL directly: + +```python +import os +import serpapi +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +results = client.search({ + "engine": "google_lens", + "url": "https://i.imgur.com/HBrB8p0.png", +}) +pprint(results) +``` + +To search a local image, place a file named `image.png` in your working directory, upload it, and pass its temporary `image_id` to Google Lens: + +```python +upload = client.upload_image("image.png") +results = client.search({ + "engine": "google_lens", + "image_id": upload["image_id"], +}) +``` + +Uploaded images can be JPG/JPEG, PNG, or WebP files up to 500 KB. The returned +`image_id` expires after 10 minutes. + +[See Image API documentation](https://serpapi.com/image-api) · [See Google Lens image upload documentation](https://serpapi.com/google-lens-upload-an-image) + +### Google Trends + +Track search interest over time and compare the popularity of search terms. + +```python +import os +import serpapi +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("API_KEY")) +results = client.search({ + "engine": "google_trends", + "q": "coffee", + "data_type": "TIMESERIES" }) +interest_over_time = results["interest_over_time"] +pprint(interest_over_time) ``` -Markdown works across SerpApi APIs and is returned as a plain Python string. See [Markdown Output for AI Agents](https://serpapi.com/markdown-output.md) for details. +[See Documentation](https://serpapi.com/google-trends-api) -Raw HTML is also available with `output="html"` and is returned as a plain Python string. +### Google Flights -## Basic examples +Search flight routes, schedules, prices, and booking options. + +> Note: The google_flights engine does not use q. +> Specify route and date parameters such as departure_id, arrival_id, outbound_date, and return_date. -### Search Bing ```python +import serpapi import os +from datetime import date, timedelta +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +outbounding = date.today() +returning = outbounding + timedelta(weeks=2) + +results = client.search({ + "engine": "google_flights", + "departure_id": "LAX", + "arrival_id": "AUS", + "outbound_date": outbounding, + "return_date": returning +}) +best_flights = results["best_flights"] +pprint(best_flights) +``` + +[See documentation](https://serpapi.com/google-flights-api) + +### Google AI Mode API + +The Google AI Mode API returns AI-generated answers with structured text blocks, references, images, products, and more. + +```python import serpapi +import os +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +results = client.search({ + "engine": "google_ai_mode", + "q": "best coffee maker" +}) +text_blocks = results["text_blocks"] +pprint(text_blocks) +``` + +[See documentation](https://serpapi.com/google-ai-mode-api) + +### Bing Search + +Scrape Bing web search results, including organic results, ads, related searches, and more. + +```python +import os +import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'bing', 'q': 'coffee' }) +pprint(results) +``` +[See documentation](https://serpapi.com/bing-search-api) + +### DuckDuckGo Search + +Scrape DuckDuckGo search results, including organic results, ads, knowledge graphs, and related searches. + +```python +import os +import serpapi +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("API_KEY")) +results = client.search({ + 'engine': 'duckduckgo', + 'q': 'coffee', +}) +pprint(results) ``` -- API Documentation: [serpapi.com/bing-search-api](https://serpapi.com/bing-search-api) +[See Documentation](https://serpapi.com/duckduckgo-search-api) + +### Baidu Search + +Scrape Baidu search results, including organic results, answer boxes, and related searches. -### Search Baidu ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'baidu', 'q': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/baidu-search-api](https://serpapi.com/baidu-search-api) +[See documentation](https://serpapi.com/baidu-search-api) + +### Amazon Search + +Scrape Amazon product search results, including product names, prices, ratings, reviews, and availability. + +> Note: The `amazon` engine uses the `k` parameter for a keyword search, not `q`. -### Search Yahoo +```python +import serpapi +import os +from pprint import pprint + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +results = client.search({ + "engine": "amazon", + "k": "Coffee", + "amazon_domain": "amazon.com" +}) +organic_results = results["organic_results"] +pprint(organic_results) +``` + +[See documentation](https://serpapi.com/amazon-search-api) + +### Yahoo Search ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'yahoo', 'p': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/yahoo-search-api](https://serpapi.com/yahoo-search-api) + [serpapi.com/yahoo-search-api](https://serpapi.com/yahoo-search-api) -### Search YouTube +### YouTube Search ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'youtube', 'search_query': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/youtube-search-api](https://serpapi.com/youtube-search-api) + [serpapi.com/youtube-search-api](https://serpapi.com/youtube-search-api) ### Search Walmart ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'walmart', 'query': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/walmart-search-api](https://serpapi.com/walmart-search-api) + [serpapi.com/walmart-search-api](https://serpapi.com/walmart-search-api) ### Search eBay ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'ebay', '_nkw': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/ebay-search-api](https://serpapi.com/ebay-search-api) + [serpapi.com/ebay-search-api](https://serpapi.com/ebay-search-api) ### Search Naver ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'naver', 'query': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/naver-search-api](https://serpapi.com/naver-search-api) + [serpapi.com/naver-search-api](https://serpapi.com/naver-search-api) ### Search Home Depot ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'home_depot', 'q': 'chair', }) +pprint(results) ``` -- API Documentation: [serpapi.com/home-depot-search-api](https://serpapi.com/home-depot-search-api) + [serpapi.com/home-depot-search-api](https://serpapi.com/home-depot-search-api) ### Search Apple App Store ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'apple_app_store', 'term': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/apple-app-store](https://serpapi.com/apple-app-store) - -### Search DuckDuckGo -```python -import os -import serpapi - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'duckduckgo', - 'q': 'coffee', -}) -``` -- API Documentation: [serpapi.com/duckduckgo-search-api](https://serpapi.com/duckduckgo-search-api) +[See documentation](https://serpapi.com/apple-app-store) ### Search Google ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'google', 'q': 'coffee' }) +pprint(results) ``` -- API Documentation: [serpapi.com/search-api](https://serpapi.com/search-api) + [See documentation](https://serpapi.com/search-api) ### Search Google Scholar ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'google_scholar', 'q': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-scholar-api](https://serpapi.com/google-scholar-api) + [See documentation](https://serpapi.com/google-scholar-api) ### Search Google Autocomplete ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'google_autocomplete', 'q': 'coffee', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-autocomplete-api](https://serpapi.com/google-autocomplete-api) + [See documentation](https://serpapi.com/google-autocomplete-api) ### Search Google Immersive Product ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'google_immersive_product', 'page_token': 'eyJlaSI6Im5ZVmxaOXVVTDY2X3A4NFBqTnZELUFjIiwicHJvZHVjdGlkIjoiIiwiY2F0YWxvZ2lkIjoiNTE1NDU2NTc1NTc5MzcxMDY3NSIsImhlYWRsaW5lT2ZmZXJEb2NpZCI6IjI1MDkyMjcwMDUzMjk2NzQwODMiLCJpbWFnZURvY2lkIjoiMTYzOTg5MjU0MDcwMDU4MDA1NTQiLCJyZHMiOiJQQ18zNDg4MDE0MTg3ODgxNzc5NjU0fFBST0RfUENfMzQ4ODAxNDE4Nzg4MTc3OTY1NCIsInF1ZXJ5IjoibGcrdHYiLCJncGNpZCI6IjM0ODgwMTQxODc4ODE3Nzk2NTQiLCJtaWQiOiI1NzY0NjI3ODM3Nzc5MTUzMTMiLCJwdnQiOiJoZyIsInV1bGUiOm51bGx9=', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-immersive-product-api](https://serpapi.com/google-immersive-product-api) + [See documentation](https://serpapi.com/google-immersive-product-api) ### Search Google Reverse Image ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ @@ -290,44 +614,16 @@ results = client.search({ 'image_url': 'https://i.imgur.com/5bGzZi7.jpg', 'max_results': '1', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-reverse-image](https://serpapi.com/google-reverse-image) - -### Search Google Lens by image URL or upload - -Google Lens accepts either a publicly accessible image URL or an uploaded -image. To search by URL, pass the URL directly: - -```python -import os -import serpapi - -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) -results = client.search({ - "engine": "google_lens", - "url": "https://i.imgur.com/HBrB8p0.png", -}) -``` + [See documentation](https://serpapi.com/google-reverse-image) -To search a local image, place a file named `image.png` in your working directory, upload it, and pass its temporary `image_id` to Google Lens: - -```python -upload = client.upload_image("image.png") -results = client.search({ - "engine": "google_lens", - "image_id": upload["image_id"], -}) -``` - -Uploaded images can be JPG/JPEG, PNG, or WebP files up to 500 KB. The returned -`image_id` expires after 10 minutes. - -- API Documentation: [Google Lens image uploads](https://serpapi.com/google-lens-upload-an-image), [Image API](https://serpapi.com/image-api) ### Search Google Local Services ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ @@ -335,14 +631,15 @@ results = client.search({ 'q': 'electrician', 'data_cid': '6745062158417646970', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-local-services-api](https://serpapi.com/google-local-services-api) + [See documentation](https://serpapi.com/google-local-services-api) ### Search Google Maps ```python import os import serpapi - +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ @@ -351,27 +648,30 @@ results = client.search({ 'll': '@40.7455096,-74.0083012,15.1z', 'type': 'search', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-maps-api](https://serpapi.com/google-maps-api) + [See documentation](https://serpapi.com/google-maps-api) ### Search Google Jobs ```python import os import serpapi - +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ 'engine': 'google_jobs', 'q': 'software engineer', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-jobs-api](https://serpapi.com/google-jobs-api) + [See documentation](https://serpapi.com/google-jobs-api) ### Search Google Play ```python import os import serpapi +from pprint import pprint client = serpapi.Client(api_key=os.getenv("API_KEY")) results = client.search({ @@ -379,22 +679,16 @@ results = client.search({ 'q': 'kite', 'store': 'apps', }) +pprint(results) ``` -- API Documentation: [serpapi.com/google-play-api](https://serpapi.com/google-play-api) + [See documentation](https://serpapi.com/google-play-api) -### Search Google Images -```python -import os -import serpapi -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_images', - 'tbm': 'isch', - 'q': 'coffee', -}) -``` -- API Documentation: [serpapi.com/google-images-api](https://serpapi.com/google-images-api) +## Documentation + +Documentation is [available on Read the Docs](https://serpapi-python.readthedocs.io/en/latest/). + +Change history is [available on GitHub](https://github.com/serpapi/serpapi-python/blob/master/HISTORY.md). ## License @@ -402,4 +696,6 @@ MIT License. ## Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and publishing instructions. +Contributions are welcome. Make sure to read our [contributing guide](CONTRIBUTING.md). + +© 2026 [SerpApi](https://serpapi.com/) \ No newline at end of file From d5a2eda511598ea1660b3e246706d6c03710e4ea Mon Sep 17 00:00:00 2001 From: audrey-serpapi Date: Wed, 14 Oct 2026 16:54:09 -0400 Subject: [PATCH 2/6] remove persistent connection --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 0d27090..ad9e402 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,6 @@ except serpapi.TimeoutError as e: ## Features - **Asynchronous searches** for submitting non-blocking jobs and retrieving completed results from the Search Archive API. -- **Persistent connections and connection pooling** for reusing HTTP connections across searches. - Search results as **Python dictionaries** with `search`, token-efficient **Markdown** with `md`, or raw **search-engine HTML** with `html`. - SDK methods for the [Image API](https://serpapi.com/image-api), [Location API](https://serpapi.com/locations-api), [Search Archive API](https://serpapi.com/search-archive-api), and [Account API](https://serpapi.com/account-api). - **Configurable HTTP timeouts** established by setting `timeout` in the client. From 85cc63348d22eaeb4d1c33026e49b1a7eed071a0 Mon Sep 17 00:00:00 2001 From: audrey-serpapi Date: Thu, 15 Oct 2026 15:38:41 -0400 Subject: [PATCH 3/6] keep persistent and standardize examples --- README.md | 247 +----------------------------------------------------- 1 file changed, 1 insertion(+), 246 deletions(-) diff --git a/README.md b/README.md index ad9e402..0d7ff6d 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ except serpapi.TimeoutError as e: ## Features - **Asynchronous searches** for submitting non-blocking jobs and retrieving completed results from the Search Archive API. +- **Persistent connections and connection pooling** for reusing HTTP connections across searches. - Search results as **Python dictionaries** with `search`, token-efficient **Markdown** with `md`, or raw **search-engine HTML** with `html`. - SDK methods for the [Image API](https://serpapi.com/image-api), [Location API](https://serpapi.com/locations-api), [Search Archive API](https://serpapi.com/search-archive-api), and [Account API](https://serpapi.com/account-api). - **Configurable HTTP timeouts** established by setting `timeout` in the client. @@ -436,252 +437,6 @@ pprint(organic_results) [See documentation](https://serpapi.com/amazon-search-api) -### Yahoo Search -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'yahoo', - 'p': 'coffee', -}) -pprint(results) -``` - [serpapi.com/yahoo-search-api](https://serpapi.com/yahoo-search-api) - -### YouTube Search -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'youtube', - 'search_query': 'coffee', -}) -pprint(results) -``` - [serpapi.com/youtube-search-api](https://serpapi.com/youtube-search-api) - -### Search Walmart -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'walmart', - 'query': 'coffee', -}) -pprint(results) -``` - [serpapi.com/walmart-search-api](https://serpapi.com/walmart-search-api) - -### Search eBay -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'ebay', - '_nkw': 'coffee', -}) -pprint(results) -``` - [serpapi.com/ebay-search-api](https://serpapi.com/ebay-search-api) - -### Search Naver -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'naver', - 'query': 'coffee', -}) -pprint(results) -``` - [serpapi.com/naver-search-api](https://serpapi.com/naver-search-api) - -### Search Home Depot -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'home_depot', - 'q': 'chair', -}) -pprint(results) -``` - [serpapi.com/home-depot-search-api](https://serpapi.com/home-depot-search-api) - -### Search Apple App Store -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'apple_app_store', - 'term': 'coffee', -}) -pprint(results) -``` -[See documentation](https://serpapi.com/apple-app-store) - -### Search Google -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google', - 'q': 'coffee' -}) -pprint(results) -``` - [See documentation](https://serpapi.com/search-api) - -### Search Google Scholar -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_scholar', - 'q': 'coffee', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-scholar-api) - -### Search Google Autocomplete -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_autocomplete', - 'q': 'coffee', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-autocomplete-api) - -### Search Google Immersive Product -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_immersive_product', - 'page_token': 'eyJlaSI6Im5ZVmxaOXVVTDY2X3A4NFBqTnZELUFjIiwicHJvZHVjdGlkIjoiIiwiY2F0YWxvZ2lkIjoiNTE1NDU2NTc1NTc5MzcxMDY3NSIsImhlYWRsaW5lT2ZmZXJEb2NpZCI6IjI1MDkyMjcwMDUzMjk2NzQwODMiLCJpbWFnZURvY2lkIjoiMTYzOTg5MjU0MDcwMDU4MDA1NTQiLCJyZHMiOiJQQ18zNDg4MDE0MTg3ODgxNzc5NjU0fFBST0RfUENfMzQ4ODAxNDE4Nzg4MTc3OTY1NCIsInF1ZXJ5IjoibGcrdHYiLCJncGNpZCI6IjM0ODgwMTQxODc4ODE3Nzk2NTQiLCJtaWQiOiI1NzY0NjI3ODM3Nzc5MTUzMTMiLCJwdnQiOiJoZyIsInV1bGUiOm51bGx9=', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-immersive-product-api) - -### Search Google Reverse Image -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_reverse_image', - 'image_url': 'https://i.imgur.com/5bGzZi7.jpg', - 'max_results': '1', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-reverse-image) - - -### Search Google Local Services -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_local_services', - 'q': 'electrician', - 'data_cid': '6745062158417646970', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-local-services-api) - -### Search Google Maps -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_maps', - 'q': 'pizza', - 'll': '@40.7455096,-74.0083012,15.1z', - 'type': 'search', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-maps-api) - -### Search Google Jobs -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_jobs', - 'q': 'software engineer', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-jobs-api) - -### Search Google Play -```python -import os -import serpapi -from pprint import pprint - -client = serpapi.Client(api_key=os.getenv("API_KEY")) -results = client.search({ - 'engine': 'google_play', - 'q': 'kite', - 'store': 'apps', -}) -pprint(results) -``` - [See documentation](https://serpapi.com/google-play-api) - ## Documentation From e7e950ff1ec8aa40f7ed49c51592d9945095cf6b Mon Sep 17 00:00:00 2001 From: audrey-serpapi Date: Fri, 16 Oct 2026 15:59:06 -0400 Subject: [PATCH 4/6] enforced sentence case, light versions in bold, no $, same key, standard indentation, standard import order, correct links, technical corrections --- README.md | 210 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 116 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index 0d7ff6d..b1f6de6 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Python 3.6 or later is required. To install the `serpapi` package, simply run the following command inside your Python virtual environment: ```bash -$ pip install serpapi +pip install serpapi ``` > Please note that this package is separate from the legacy `serpapi` module, @@ -22,83 +22,85 @@ $ pip install serpapi ## Quickstart -[Create a SerpApi account](https://serpapi.com/dashboard) to get your API key, then store it in an environment variable: +[Create a SerpApi account](https://serpapi.com/users/sign_up?plan=free) to get your API key, then store it in an environment variable: ```bash export SERPAPI_KEY="your_api_key" ``` -Environment variables are a secure, safe, and easy way to manage secrets. -Python accesses these variables from `os.environ["SERPAPI_KEY"]`. +Environment variables keep secrets out of your source code. +Python accesses these variables from `os.getenv("SERPAPI_KEY")`. -Run a Google search and access the results as a Python `Dictionary`: +Run a Google search and access the results as a Python `dict`: ```python import os -import serpapi from pprint import pprint -client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - "engine": "google", - "q": "coffee" + "engine": "google", + "q": "coffee" }) pprint(results) ``` -The `results` variable now contains a `SerpResults` object, which acts just like a standard dictionary, with some convenient functions added on top. +The `results` variable now contains a `SerpResults` object, which acts just like a `dict`, with some convenient functions added on top. -This example runs a search for "coffee" on Google. It then returns the results as a regular Python Hash. See the playground to generate your own code. +This example runs a search for "coffee" on Google. See the [playground](https://serpapi.com/playground) to generate your own code. - -### Error Handling +### Error handling Unsuccessful requests raise `serpapi.HTTPError` or `serpapi.TimeoutError` exceptions. The returned status code will reflect the sort of error that occurred, please refer to [Status and Error Codes Documentation](https://serpapi.com/api-status-and-error-codes) for more details. ```python import os + import serpapi # A default timeout can be set here. -client = serpapi.Client(api_key=os.getenv("API_KEY"), timeout=10) +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY"), timeout=10) try: results = client.search({ - 'engine': 'google', - 'q': 'coffee', + "engine": "google", + "q": "coffee", }) except serpapi.HTTPError as e: if e.status_code == 401: # Invalid API key print(e.error) # "Invalid API key. Your API key should be here: https://serpapi.com/manage-api-key" elif e.status_code == 400: # Missing required parameter pass - elif e.status_code == 429: # Exceeds the hourly throughput limit OR account run out of searches + elif e.status_code == 429: # Exceeds the hourly throughput limit OR the account has run out of searches pass except serpapi.TimeoutError as e: # Handle timeout print(f"The request timed out: {e}") ``` + ## Features - **Asynchronous searches** for submitting non-blocking jobs and retrieving completed results from the Search Archive API. - **Persistent connections and connection pooling** for reusing HTTP connections across searches. -- Search results as **Python dictionaries** with `search`, token-efficient **Markdown** with `md`, or raw **search-engine HTML** with `html`. +- Search results as **Python dict** with `search`, token-efficient **Markdown** with `md`, or raw **search-engine HTML** with `html`. - SDK methods for the [Image API](https://serpapi.com/image-api), [Location API](https://serpapi.com/locations-api), [Search Archive API](https://serpapi.com/search-archive-api), and [Account API](https://serpapi.com/account-api). - **Configurable HTTP timeouts** established by setting `timeout` in the client. -## Response Formats +## Response formats -Use `search` and default output (none) for structured results decoded into a `Dictionary`: +Use `search` and default output (none) for structured results decoded into a `dict`: -```python +```python results = client.search({ - "engine": "google", - "q": "coffee" + "engine": "google", + "q": "coffee" }) ``` -Use `md` output for a token-efficient Markdown String optimized for LLMs and AI agents: +Use `md` output for a token-efficient Markdown string optimized for LLMs and AI agents: ```python markdown = client.search({ @@ -109,6 +111,7 @@ markdown = client.search({ ``` Use `html` output when you need the raw search-engine response: + ```python raw_html = client.search({ "engine": "google", @@ -124,31 +127,38 @@ Learn more about [SerpApi Markdown output](https://serpapi.com/markdown-output). ## Configuration -Set defaults when creating a client, then override search parameters in individual calls: +The client is configured with your API key (and an optional timeout parameter) when you create it: ```python -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY"), timeout=120) -results = client.search({ - "engine": "google", - "q": "coffee", -}) +import os + +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) ``` -|Option | Default | Description| -|-------|---------|------------| -| `api_key` | None | Your SerpApi API key. Use an environment variable rather than committing it to source control. | -| `engine` | None | The search engine used by default, such as `google` or `google_maps`. | -| `timeout` | `120` | Timeout in seconds for non-persistent HTTP requests. | -| `async` | false | Submits searches without waiting for them to complete. It can be set on the client or per search.| +| Option | Default | Description | +|--------|---------|-------------| +| `api_key` | `None` | Your SerpApi API key. Use an environment variable rather than committing it to source control. | +| `timeout` | `None` | Timeout in seconds for each HTTP request. By default no timeout is set, so a request can wait indefinitely. | + +Everything else is passed with each call: -Search-engine-specific parameters can also be supplied when creating the client or calling `search`. Parameters passed to search override client defaults. +| Parameter | Where it goes | Example | +|-----------|---------------|---------| +| `engine`, `q`, and other engine-specific parameters | The dictionary passed to `client.search()` | `{"engine": "google", "q": "coffee"}` | +| `async` | The dictionary passed to `client.search()` | `{"engine": "google", "q": "coffee", "async": True}` | +| `output` | The dictionary passed to `client.search()` | `{"engine": "google", "q": "coffee", "output": "md"}` | +| `search_id`, `output` | Keyword arguments to `client.search_archive()` | `client.search_archive(search_id=search_id, output="md")` | -### Search Asynchronous +The client has no default `engine` or `async` setting, so include them in every search. -Search API features non-blocking search using the option: `async=true`. +### Search asynchronously -- Non-blocking - `async=true` - a single parent process can handle unlimited concurrent searches. -- Blocking - `async=false` - many processes must be forked and synchronized to handle concurrent searches. This strategy is I/O usage because each client would hold a network connection. +Use `{"async": True}` to submit searches without waiting for them to complete. + +- **Non-blocking** (`{"async": True}`): a single process can submit many searches and collect the results later from the Search Archive API. The code is more complex because you have to track search IDs and check their status. +- **Blocking** (`{"async": False}`, the default): each call waits for its results before returning, which keeps the code simple. > **Note:** `async` is a reserved keyword in Python 3.7+, so pass it inside the parameters dictionary (`{"async": True}`) rather than as a keyword argument. @@ -163,7 +173,7 @@ from queue import Queue import serpapi company_list = ["meta", "amazon", "apple", "netflix", "google"] -client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) schedule_search = Queue() result = None @@ -205,23 +215,24 @@ print("done") This code batches searches into a [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)). Each search can take a few seconds to complete, so by the time the first ID is popped, its results are usually already in the archive. Searches that are still processing are put back in the queue and checked again. -## Basic Examples in Python +## Basic examples in Python -Here are some examples for some of our most popular APIs. You can find the full list of supported engines and parameters in our [documentation](https://serpapi.com/search-engine-apis). +Here are some examples of our most popular APIs. You can find the full list of supported engines and parameters in our [documentation](https://serpapi.com/search-engine-apis). ### Google Shopping Scrape Google Shopping results with product names, prices, ratings, and merchant information. ```python -import serpapi import os from pprint import pprint +import serpapi + client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - "engine": "google_shopping", - "q": "Macbook M4" + "engine": "google_shopping", + "q": "Macbook M4" }) shopping_results = results["shopping_results"] pprint(shopping_results) @@ -229,7 +240,7 @@ pprint(shopping_results) [See documentation](https://serpapi.com/google-shopping-api) -#### Google Shopping Light +**Google Shopping Light** A [light variant](https://serpapi.com/google-shopping-light-api) engine called `google_shopping_light` is also available for faster, lower-cost shopping searches. @@ -239,33 +250,35 @@ Scrape Google Images search results, including image URLs, thumbnails, titles, a ```python import os -import serpapi from pprint import pprint -client = serpapi.Client(api_key=os.getenv("API_KEY")) +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - 'engine': 'google_images', - 'q': 'coffee', + "engine": "google_images", + "q": "coffee", }) pprint(results) ``` [See documentation](https://serpapi.com/google-images-api) -#### Google Images Light +**Google Images Light** A [light variant](https://serpapi.com/google-images-light-api) engine called `google_images_light` is also available for faster, lower-cost image searches. -### Google Lens with Image URL or Upload +### Google Lens with image URL or upload Google Lens accepts either a publicly accessible image URL or an uploaded image. To search by URL, pass the URL directly: ```python import os -import serpapi from pprint import pprint +import serpapi + client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ "engine": "google_lens", @@ -295,44 +308,46 @@ Track search interest over time and compare the popularity of search terms. ```python import os -import serpapi from pprint import pprint -client = serpapi.Client(api_key=os.getenv("API_KEY")) +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - "engine": "google_trends", - "q": "coffee", - "data_type": "TIMESERIES" + "engine": "google_trends", + "q": "coffee", + "data_type": "TIMESERIES" }) interest_over_time = results["interest_over_time"] pprint(interest_over_time) ``` -[See Documentation](https://serpapi.com/google-trends-api) +[See documentation](https://serpapi.com/google-trends-api) ### Google Flights Search flight routes, schedules, prices, and booking options. -> Note: The google_flights engine does not use q. -> Specify route and date parameters such as departure_id, arrival_id, outbound_date, and return_date. +> Note: The `google_flights` engine does not use `q`. +> Specify route and date parameters such as `departure_id`, `arrival_id`, `outbound_date`, and `return_date`. ```python -import serpapi import os from datetime import date, timedelta from pprint import pprint +import serpapi + client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) outbounding = date.today() returning = outbounding + timedelta(weeks=2) results = client.search({ - "engine": "google_flights", - "departure_id": "LAX", - "arrival_id": "AUS", - "outbound_date": outbounding, - "return_date": returning + "engine": "google_flights", + "departure_id": "LAX", + "arrival_id": "AUS", + "outbound_date": outbounding, + "return_date": returning }) best_flights = results["best_flights"] pprint(best_flights) @@ -345,14 +360,15 @@ pprint(best_flights) The Google AI Mode API returns AI-generated answers with structured text blocks, references, images, products, and more. ```python -import serpapi import os from pprint import pprint +import serpapi + client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) -results = client.search({ - "engine": "google_ai_mode", - "q": "best coffee maker" +results = client.search({ + "engine": "google_ai_mode", + "q": "best coffee maker" }) text_blocks = results["text_blocks"] pprint(text_blocks) @@ -360,58 +376,64 @@ pprint(text_blocks) [See documentation](https://serpapi.com/google-ai-mode-api) -### Bing Search +### Search Bing Scrape Bing web search results, including organic results, ads, related searches, and more. ```python import os -import serpapi from pprint import pprint -client = serpapi.Client(api_key=os.getenv("API_KEY")) +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - 'engine': 'bing', - 'q': 'coffee' + "engine": "bing", + "q": "coffee" }) pprint(results) ``` + [See documentation](https://serpapi.com/bing-search-api) -### DuckDuckGo Search +### Search DuckDuckGo Scrape DuckDuckGo search results, including organic results, ads, knowledge graphs, and related searches. ```python import os -import serpapi from pprint import pprint -client = serpapi.Client(api_key=os.getenv("API_KEY")) +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - 'engine': 'duckduckgo', - 'q': 'coffee', + "engine": "duckduckgo", + "q": "coffee", }) pprint(results) ``` -[See Documentation](https://serpapi.com/duckduckgo-search-api) -### Baidu Search +[See documentation](https://serpapi.com/duckduckgo-search-api) + +### Search Baidu Scrape Baidu search results, including organic results, answer boxes, and related searches. ```python import os -import serpapi from pprint import pprint -client = serpapi.Client(api_key=os.getenv("API_KEY")) +import serpapi + +client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - 'engine': 'baidu', - 'q': 'coffee', + "engine": "baidu", + "q": "coffee", }) pprint(results) ``` + [See documentation](https://serpapi.com/baidu-search-api) ### Amazon Search @@ -421,15 +443,16 @@ Scrape Amazon product search results, including product names, prices, ratings, > Note: The `amazon` engine uses the `k` parameter for a keyword search, not `q`. ```python -import serpapi import os from pprint import pprint +import serpapi + client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) results = client.search({ - "engine": "amazon", - "k": "Coffee", - "amazon_domain": "amazon.com" + "engine": "amazon", + "k": "Coffee", + "amazon_domain": "amazon.com" }) organic_results = results["organic_results"] pprint(organic_results) @@ -437,7 +460,6 @@ pprint(organic_results) [See documentation](https://serpapi.com/amazon-search-api) - ## Documentation Documentation is [available on Read the Docs](https://serpapi-python.readthedocs.io/en/latest/). From c20e70ce58658be24d3bc74dd31d57ecdddb1163 Mon Sep 17 00:00:00 2001 From: audrey-serpapi Date: Thu, 29 Oct 2026 17:11:38 -0400 Subject: [PATCH 5/6] title fix, asynchronous header fix, search header fixes, example header update, markdown output keyword add, reword default output, playground and integration page links add --- README.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b1f6de6..c2d72d1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SerpApi Python Library & Package +# SerpApi Python Library [![Package](https://img.shields.io/pypi/v/serpapi?color=green)](https://pypi.org/project/serpapi) [![serpapi-python](https://github.com/serpapi/serpapi-python/actions/workflows/ci.yml/badge.svg)](https://github.com/serpapi/serpapi-python/actions/workflows/ci.yml) Integrate search data into your AI workflow, RAG / fine-tuning, or Python application using this official [SerpApi Python SDK](https://serpapi.com/integrations/python). @@ -85,13 +85,13 @@ except serpapi.TimeoutError as e: - **Asynchronous searches** for submitting non-blocking jobs and retrieving completed results from the Search Archive API. - **Persistent connections and connection pooling** for reusing HTTP connections across searches. -- Search results as **Python dict** with `search`, token-efficient **Markdown** with `md`, or raw **search-engine HTML** with `html`. +- Search results as **Python dict** by default, token-efficient **Markdown** with `"output": "md"`, or raw **search-engine HTML** with `"output": "html"`. - SDK methods for the [Image API](https://serpapi.com/image-api), [Location API](https://serpapi.com/locations-api), [Search Archive API](https://serpapi.com/search-archive-api), and [Account API](https://serpapi.com/account-api). - **Configurable HTTP timeouts** established by setting `timeout` in the client. ## Response formats -Use `search` and default output (none) for structured results decoded into a `dict`: +Use `search` without `output` for structured results decoded into a `dict`: ```python results = client.search({ @@ -153,7 +153,7 @@ Everything else is passed with each call: The client has no default `engine` or `async` setting, so include them in every search. -### Search asynchronously +### Asynchronous searches Use `{"async": True}` to submit searches without waiting for them to complete. @@ -215,7 +215,7 @@ print("done") This code batches searches into a [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)). Each search can take a few seconds to complete, so by the time the first ID is popped, its results are usually already in the archive. Searches that are still processing are put back in the queue and checked again. -## Basic examples in Python +## Examples Here are some examples of our most popular APIs. You can find the full list of supported engines and parameters in our [documentation](https://serpapi.com/search-engine-apis). @@ -376,7 +376,7 @@ pprint(text_blocks) [See documentation](https://serpapi.com/google-ai-mode-api) -### Search Bing +### Bing Search Scrape Bing web search results, including organic results, ads, related searches, and more. @@ -396,7 +396,7 @@ pprint(results) [See documentation](https://serpapi.com/bing-search-api) -### Search DuckDuckGo +### DuckDuckGo Search Scrape DuckDuckGo search results, including organic results, ads, knowledge graphs, and related searches. @@ -416,7 +416,7 @@ pprint(results) [See documentation](https://serpapi.com/duckduckgo-search-api) -### Search Baidu +### Baidu Search Scrape Baidu search results, including organic results, answer boxes, and related searches. @@ -466,6 +466,13 @@ Documentation is [available on Read the Docs](https://serpapi-python.readthedocs Change history is [available on GitHub](https://github.com/serpapi/serpapi-python/blob/master/HISTORY.md). +Browse the [SerpApi documentation](https://serpapi.com/search-api) to find supported APIs and parameters, or use the [Playground](https://serpapi.com/playground) to build a request and generate Python code. + +Additional SDK resources: + +- [Python SDK integration page](https://serpapi.com/integrations/python) +- [SerpApi status](https://serpapi.com/api-metrics) + ## License MIT License. From 2d022db7b33620d509ee3fac8a6cdfd8afa85419 Mon Sep 17 00:00:00 2001 From: Adarsh Divakaran Date: Sat, 31 Oct 2026 23:44:41 +0530 Subject: [PATCH 6/6] docs: simplify README and clarify SDK usage AI assistance: GPT-6 Astra (xhigh) in Codex implemented the user-directed edits and ran documentation checks. Claude Opus 5.5 (xhigh) reviewed earlier drafts. Keep configuration focused on client defaults, compare output formats, and shorten async and Extract examples. Improve onboarding, migration, and agent resources, and bound polling in the async search guide. Co-authored-by: Codex --- README.md | 278 ++++++++---------------- docs/user_guide/async-search-archive.md | 31 ++- 2 files changed, 109 insertions(+), 200 deletions(-) diff --git a/README.md b/README.md index b1b8f4d..aa061f2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ Integrate search data into your AI workflow, RAG / fine-tuning, or Python application using this official [SerpApi Python SDK](https://serpapi.com/integrations/python). -SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, App Stores, and [more](https://serpapi.com). +SerpApi supports Google, Google Maps, Google Shopping, Baidu, Yandex, Yahoo, eBay, app stores, and [more](https://serpapi.com). + +> See the [full Python SDK documentation](https://serpapi-python.readthedocs.io/en/latest/) for setup, usage guides, and API reference. ## Installation @@ -15,13 +17,6 @@ To install the `serpapi` package, simply run the following command inside your P pip install serpapi ``` -> Please note that this package is separate from the legacy `serpapi` module, -> which is available on PyPi as `google-search-results`. -> This package is maintained by SerpApi, and is the recommended way to access the -> SerpApi service from Python. - -Both packages use `import serpapi`, so install only one in your environment. See the [migration guide](https://serpapi-python.readthedocs.io/en/latest/user_guide/migrating-from-google-search-results.html) when updating code that uses `google-search-results`. - ## Quickstart [Create a SerpApi account](https://serpapi.com/users/sign_up?plan=free) to get your API key, then store it in an environment variable: @@ -30,29 +25,27 @@ Both packages use `import serpapi`, so install only one in your environment. See export SERPAPI_KEY="your_api_key" ``` -Environment variables keep secrets out of your source code. -Python accesses these variables from `os.getenv("SERPAPI_KEY")`. +Environment variables keep secrets out of your source code. Read the API key with `os.environ["SERPAPI_KEY"]`. Python raises `KeyError` if the variable is missing. Run a Google search and access the structured results: ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google", "q": "coffee" }) -pprint(results) +print(results) ``` The `results` variable contains a dict-like `SerpResults` object. Read fields with `results["organic_results"]` or `results.get("organic_results", [])`. -This example runs a search for "coffee" on Google. See the [playground](https://serpapi.com/playground) to generate your own code. +This example runs a search for "coffee" on Google. See the [Playground](https://serpapi.com/playground) to generate your own code. For Windows setup and instructions to save and run the example, see the [getting-started guide](https://serpapi-python.readthedocs.io/en/latest/user_guide/getting-started.html). @@ -66,7 +59,7 @@ import os import serpapi # A default timeout can be set here. -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY"), timeout=10) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=10) try: results = client.search({ @@ -84,7 +77,7 @@ if "error" in results: raise RuntimeError(results["error"]) ``` -A successful HTTP response can still contain an `error` field, such as when a search returns no results. Check it before reading result fields. See [Errors and Timeouts](https://serpapi-python.readthedocs.io/en/latest/user_guide/errors-and-timeouts.html) for more examples. +A successful HTTP response can still contain an `error` field, such as when a search returns no results. Check it before reading result fields. See [Errors and timeouts](https://serpapi-python.readthedocs.io/en/latest/user_guide/errors-and-timeouts.html) for more examples. ## Features @@ -95,9 +88,19 @@ A successful HTTP response can still contain an `error` field, such as when a se - **Content extraction** with `client.extract()` for reading pages, discovering URLs, and crawling websites. - **Configurable HTTP timeouts** established by setting `timeout` in the client. +## Migrating from google-search-results + +If you use the legacy `google-search-results` package, follow the [migration guide](https://serpapi-python.readthedocs.io/en/latest/user_guide/migrating-from-google-search-results.html) to update your code. Both packages use `import serpapi`, so install only one in your environment. + ## Response formats -Use `search` without `output` for structured results returned as a dict-like `SerpResults` object: +| Output | Use it for | Returns | +|--------|------------|---------| +| `json` (default) | Reading fields, filtering, or storing results | Dict-like `SerpResults` | +| `md` | Passing content directly to an LLM | Markdown `str` | +| `html` | Inspecting or processing raw HTML | HTML `str` | + +Omit `output` or set `output="json"` for JSON: ```python results = client.search({ @@ -112,7 +115,7 @@ Use `results.as_dict()` when another library needs a plain `dict`, including bef data = results.as_dict() ``` -Use `md` output for a token-efficient Markdown string optimized for LLMs and AI agents: +Set `output="md"` for Markdown: ```python markdown = client.search({ @@ -122,7 +125,7 @@ markdown = client.search({ }) ``` -Use `html` output when you need the raw search-engine response as a string: +Set `output="html"` for HTML: ```python raw_html = client.search({ @@ -135,178 +138,60 @@ raw_html = client.search({ Archived results are also available as Markdown with `client.search_archive(search_id=search_id, output="md")`. -Learn more about [SerpApi Markdown output](https://serpapi.com/markdown-output). +Learn more about [SerpApi Markdown Output](https://serpapi.com/markdown-output). ## Configuration -The client is configured with your API key (and an optional timeout parameter) when you create it: - -```python -import os - -import serpapi - -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) -``` - | Option | Default | Description | |--------|---------|-------------| -| `api_key` | `None` | Your SerpApi API key. Use an environment variable rather than committing it to source control. | -| `timeout` | `None` | Connection and read timeout in seconds for each HTTP request. By default no timeout is set, so a request can wait indefinitely. | - -Everything else is passed with each call: - -| Parameter | Where it goes | Example | -|-----------|---------------|---------| -| `engine`, `q`, and other engine-specific parameters | The dictionary passed to `client.search()` | `{"engine": "google", "q": "coffee"}` | -| `async` | The dictionary passed to `client.search()` | `{"engine": "google", "q": "coffee", "async": True}` | -| `output` | The dictionary passed to `client.search()` | `{"engine": "google", "q": "coffee", "output": "md"}` | -| `search_id`, `output` | Keyword arguments to `client.search_archive()` | `client.search_archive(search_id=search_id, output="md")` | -| `url`, `mode`, `output` | A dictionary or keyword arguments to `client.extract()` | `client.extract(url="https://serpapi.com/", output="md")` | +| `api_key` | `None` | Your SerpApi API key. | +| `timeout` | `None` | Connection and read timeout in seconds. No timeout is set by default. | ### Asynchronous searches -Searches wait for their results by default (`async` is `false`). Use `{"async": True}` to submit server-side search jobs and collect their results later from the Search Archive API. Each Python SDK call still waits for its HTTP response and cannot be awaited with `asyncio`. +Searches wait for their results by default. Use `{"async": True}` to submit a search job on SerpApi and retrieve its results later from the Search Archive API. + +SerpApi's `async` parameter is separate from Python `asyncio`. The SDK methods are synchronous: each call blocks until its HTTP response arrives and cannot be used with `await`. > **Note:** `async` is a reserved keyword in Python 3.7+, so pass it inside the parameters dictionary (`{"async": True}`) rather than as a keyword argument. -Here is an example of asynchronous searches using Python: +Submit a search and check its status later: ```python -import os -import re -import time -from queue import Queue - -import serpapi - -company_list = ["meta", "amazon", "apple", "netflix", "google"] -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY"), timeout=30) -schedule_search = Queue() -result = None - -for company in company_list: - result = client.search({"engine": "google", "q": company, "async": True}) - if re.search(r"Cached", result["search_metadata"]["status"]): - print(f"{company}: search results found in cache for: {company}") - - schedule_search.put(result["search_metadata"]["id"]) - -print(f"Last search submitted at: {result['search_metadata']['created_at']}") - -deadline = time.monotonic() + 120 -print("wait 10s for all requests to be completed") -time.sleep(10) - -print("wait until all searches are cached or success") -while not schedule_search.empty(): - remaining = deadline - time.monotonic() - if remaining <= 0: - raise TimeoutError("Polling timed out before all searches completed.") - - search_id = schedule_search.get() - search_archived = client.search_archive( - search_id=search_id, timeout=min(30, remaining) - ) - - company = search_archived["search_parameters"]["q"] - status = search_archived["search_metadata"]["status"] - - if re.search(r"Cached|Success", status): - print(f"{company}: search results found in archive for: {company}") - continue - - if status == "Error": - print(f"{company}: search failed: {search_archived.get('error')}") - continue - - schedule_search.put(search_id) - time.sleep(1) +submitted = client.search({ + "engine": "google", + "q": "coffee", + "async": True, +}) +search_id = submitted["search_metadata"]["id"] -print("done") +# Retrieve later; the search may still be processing. +results = client.search_archive(search_id=search_id) +print(results["search_metadata"]["status"]) ``` -This code batches searches into a [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)). -Each search can take a few seconds to complete, so by the time the first ID is popped, its results are usually already in the archive. Searches that are still processing are put back in the queue and checked again. - -The client uses a 30-second HTTP timeout. A separate 120-second polling deadline, checked between requests, stops retries with a `TimeoutError` if searches remain unfinished. +If the search is still processing, retrieve it again later. See the [async search guide](https://serpapi-python.readthedocs.io/en/latest/user_guide/async-search-archive.html) for polling with HTTP timeouts and a deadline. ## Examples Here are some examples of our most popular APIs. You can find the full list of supported engines and parameters in our [documentation](https://serpapi.com/search-engine-apis). -### Extract API - -Read content from a public URL with `client.extract()`. It supports single-page scraping, URL discovery, and crawling, and sets `engine="extract"` automatically. - -Set `output="md"` to get the page's main content as a Markdown string for an AI agent or other text processing: - -```python -import os - -import serpapi - -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY"), timeout=60) -markdown = client.extract(url="https://serpapi.com/", output="md") -print(markdown) -``` - -JSON is the default output format. It returns a dict-like `SerpResults` object with page information, structured data, links, and Markdown: - -```python -results = client.extract(url="https://serpapi.com/") -print(results["page_information"]["title"]) -print(results["markdown"]) -``` - -Use `output="html"` to get the retrieved HTML as a string: - -```python -html = client.extract(url="https://serpapi.com/", output="html") -``` - -Use `mode="map"` to discover URLs. Map mode includes sitemap URLs by default. This example sets `include_sitemap=False` to use only the page's links: - -```python -results = client.extract(url="https://serpapi.com/", mode="map", include_sitemap=False) -for entry in results["urls"]: - print(entry["url"]) -``` - -Use `mode="crawl"` to follow links and extract multiple pages: - -```python -results = client.extract( - url="https://serpapi.com/", mode="crawl", max_pages=2, max_depth=1, timeout=180 -) -for page in results["pages"]: - print(page["url"]) - print(page["markdown"]) -``` - -Crawl mode can consume one search credit per successfully extracted page, including the starting page. Set `max_pages` to limit the number of pages. - -The `timeout` keyword sets the SDK's HTTP timeout in seconds. To set the Extract API's fetch timeout in milliseconds, put it in the parameter dictionary: `client.extract({"url": "https://serpapi.com/", "timeout": 30000}, timeout=60)`. - -[See documentation](https://serpapi.com/extract-api) or the [Python Extract API guide](https://github.com/serpapi/serpapi-python/blob/master/docs/user_guide/extract.md) for more options. - ### Google Shopping Scrape Google Shopping results with product names, prices, ratings, and merchant information. ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google_shopping", "q": "Macbook M4" }) shopping_results = results["shopping_results"] -pprint(shopping_results) +print(shopping_results) ``` [See documentation](https://serpapi.com/google-shopping-api) @@ -321,16 +206,15 @@ Scrape Google Images search results, including image URLs, thumbnails, titles, a ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google_images", "q": "coffee", }) -pprint(results) +print(results) ``` [See documentation](https://serpapi.com/google-images-api) @@ -339,6 +223,26 @@ pprint(results) A [light variant](https://serpapi.com/google-images-light-api) engine called `google_images_light` is also available for faster, lower-cost image searches. +### Extract API + +Extract page content from a public URL as Markdown for an LLM: + +```python +import os + +import serpapi + +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"], timeout=60) +markdown = client.extract(url="https://serpapi.com/", output="md") +print(markdown) +``` + +Omit `output` or set `output="json"` for a dict-like `SerpResults` object with structured page data and Markdown. Use `output="html"` for HTML as a string. + +For URL discovery and crawling, see [Map Mode](https://github.com/serpapi/serpapi-python/blob/master/docs/user_guide/extract.md#discover-urls) and [Crawl Mode](https://github.com/serpapi/serpapi-python/blob/master/docs/user_guide/extract.md#crawl-multiple-pages) in the Python guide. + +[See documentation](https://serpapi.com/extract-api) + ### Google Lens with image URL or upload Google Lens accepts either a publicly accessible image URL or an uploaded @@ -346,16 +250,15 @@ image. To search by URL, pass the URL directly: ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google_lens", "url": "https://i.imgur.com/HBrB8p0.png", }) -pprint(results) +print(results) ``` To search a local image, place a file named `image.png` in your working directory, upload it, and pass its temporary `image_id` to Google Lens: @@ -379,18 +282,17 @@ Track search interest over time and compare the popularity of search terms. ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google_trends", "q": "coffee", "data_type": "TIMESERIES" }) interest_over_time = results["interest_over_time"] -pprint(interest_over_time) +print(interest_over_time) ``` [See documentation](https://serpapi.com/google-trends-api) @@ -405,11 +307,10 @@ Search flight routes, schedules, prices, and booking options. ```python import os from datetime import date, timedelta -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) outbounding = date.today() + timedelta(days=30) returning = outbounding + timedelta(weeks=2) @@ -421,7 +322,7 @@ results = client.search({ "return_date": returning.isoformat() }) flights = results.get("best_flights") or results.get("other_flights", []) -pprint(flights) +print(flights) ``` [See documentation](https://serpapi.com/google-flights-api) @@ -432,17 +333,16 @@ The Google AI Mode API returns AI-generated answers with structured text blocks, ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "google_ai_mode", "q": "best coffee maker" }) text_blocks = results["text_blocks"] -pprint(text_blocks) +print(text_blocks) ``` [See documentation](https://serpapi.com/google-ai-mode-api) @@ -453,16 +353,15 @@ Scrape Bing web search results, including organic results, ads, related searches ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "bing", "q": "coffee" }) -pprint(results) +print(results) ``` [See documentation](https://serpapi.com/bing-search-api) @@ -473,16 +372,15 @@ Scrape DuckDuckGo search results, including organic results, ads, knowledge grap ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "duckduckgo", "q": "coffee", }) -pprint(results) +print(results) ``` [See documentation](https://serpapi.com/duckduckgo-search-api) @@ -493,16 +391,15 @@ Scrape Baidu search results, including organic results, answer boxes, and relate ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "baidu", "q": "coffee", }) -pprint(results) +print(results) ``` [See documentation](https://serpapi.com/baidu-search-api) @@ -515,36 +412,35 @@ Scrape Amazon product search results, including product names, prices, ratings, ```python import os -from pprint import pprint import serpapi -client = serpapi.Client(api_key=os.getenv("SERPAPI_KEY")) +client = serpapi.Client(api_key=os.environ["SERPAPI_KEY"]) results = client.search({ "engine": "amazon", "k": "Coffee", "amazon_domain": "amazon.com" }) organic_results = results["organic_results"] -pprint(organic_results) +print(organic_results) ``` [See documentation](https://serpapi.com/amazon-search-api) -## Documentation +## More resources -Documentation is [available on Read the Docs](https://serpapi-python.readthedocs.io/en/latest/). +- [Python SDK documentation](https://serpapi-python.readthedocs.io/en/latest/) for setup, usage, and examples +- [SerpApi documentation](https://serpapi.com/search-api) for supported APIs and parameters +- [SerpApi status](https://serpapi.com/api-metrics) for API success rates and response times -Change history is [available on GitHub](https://github.com/serpapi/serpapi-python/blob/master/HISTORY.md). +### Playground -Browse the [SerpApi documentation](https://serpapi.com/search-api) to find supported APIs and parameters, or use the [Playground](https://serpapi.com/playground) to build a request and generate Python code. +Build and test your request in the **[Playground](https://serpapi.com/playground)**, then generate Python code. -Additional SDK resources: +### For agents -- [Python SDK integration page](https://serpapi.com/integrations/python) -- [AI agent guide](https://serpapi-python.readthedocs.io/en/latest/ai-agents.html) +- [AI agent guide](https://serpapi-python.readthedocs.io/en/latest/ai-agents.html) for using the Python SDK with AI agents - [SerpApi llms.txt](https://serpapi.com/llms.txt) for links to each API's Markdown parameter reference -- [SerpApi status](https://serpapi.com/api-metrics) ## License diff --git a/docs/user_guide/async-search-archive.md b/docs/user_guide/async-search-archive.md index f669653..206cbd8 100644 --- a/docs/user_guide/async-search-archive.md +++ b/docs/user_guide/async-search-archive.md @@ -7,9 +7,9 @@ description: "Submit searches now and retrieve their results later with the Sear An asynchronous search lets you submit a request now and collect the results later. Set the API's `async` parameter to `true` to receive a search ID, then use that ID with the Search Archive API. Each Python client call still waits for an HTTP response. These methods do not use Python's `asyncio` or `await`. -Create a client as shown in [Client Usage](client-usage.md#create-a-client) before running the examples. +Create a client as shown in the [client usage guide](client-usage.md#create-a-client) before running the examples. -## Submit an Async Search +## Submit an async search `async` is a reserved word in Python. Put it in a dictionary and use `**` to pass that dictionary's entries as keyword arguments: @@ -19,40 +19,53 @@ submitted = client.search( q="coffee", location="Austin, Texas", **{"async": True}, + timeout=30, ) search_id = submitted["search_metadata"]["id"] print(search_id) ``` -## Retrieve the Search +## Retrieve the search ```python -archived = client.search_archive(search_id=search_id) +archived = client.search_archive(search_id=search_id, timeout=30) status = archived.get("search_metadata", {}).get("status") print(status) ``` -Check the status before reading the results. If the search is still processing, wait and call `search_archive()` again. This loop checks every two seconds until the search succeeds or reports an error: +## Poll for completion + +Check the status before reading the results. If the search is still processing, wait and call `search_archive()` again. This example checks every two seconds, with an HTTP timeout of up to 30 seconds per request and a 120-second polling deadline: ```python import time +deadline = time.monotonic() + 120 + while True: - archived = client.search_archive(search_id=search_id) + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError("Polling timed out before the search completed.") + + archived = client.search_archive( + search_id=search_id, timeout=min(30, remaining) + ) status = archived.get("search_metadata", {}).get("status") - if status == "Success": + if status in ("Success", "Cached"): break if status == "Error": raise RuntimeError(archived.get("error", "Search failed")) - time.sleep(2) + time.sleep(min(2, max(0, deadline - time.monotonic()))) ``` -## When to Use Async Searches +The deadline is checked between requests. If the search remains unfinished, the loop raises Python's built-in `TimeoutError`. The HTTP timeout limits connection and read waits for each request; it does not stop repeated successful responses that say the search is still processing. + +## When to use async searches Use asynchronous searches when one part of your program submits searches and another collects the results later. For example, a scheduled job could submit a batch of searches for another worker to process.