google-search-results: a Python client for SerpApi, on its way out
Google Search Results via SERP API pip Python Package
At a glance
- What is it?
- The google-search-results package wraps the SerpApi service so a Python script can run a Google, Bing or YouTube search and get a parsed dictionary back, with helpers for location lookup, archived results and pagination. Its own README now warns that it will soon be deprecated in favour of serpapi-python.
- Who is it for?
- Adopt serpapi-python rather than this package for new work, because the README for google-search-results states plainly that it will soon be deprecated and recommends migrating to the newer implementation to keep support and access to the latest features. If you already depend on google-search-results, plan the switch now rather than at the deprecation notice, and note that the SerpApi account and key stay the same across both.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 68 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The deprecation warning sits above the whole README
The first thing in the README is a warning block, and it is not a footnote. The package will soon be deprecated in favour of serpapi-python, and the recommendation is to migrate to the newer implementation to ensure continued support and access to the latest features and improvements.
That changes how you should read everything else in the document. The rest of the README is a full description of a working client for the SerpApi service, covering search, the search archive, the account API and the location API, and the individual search classes for Google, Bing, Baidu, Yahoo, DuckDuckGo, eBay, Yandex, Home Depot, Google Scholar, YouTube, Walmart, the Apple App Store and Naver.
The division of labour between the client and the service is stated plainly and is worth understanding before you write any code. The SerpApi backend searches Google using the query, parses the messy HTML responses and returns a standardized JSON response. The GoogleSearch class formats the request, executes a GET http request against the SerpApi service and parses the JSON response into a dictionary.
So the package is a thin client. It does not scrape Google. It formats a request, sends it to a paid service, and turns the reply into Python objects. That is the honest picture of what the dependency does, and it is the reason the library can offer a dozen search engines without maintaining a parser for each.
The package is MIT licensed, the default branch is master, the last push was on 2026-08-18, and the repository has no GitHub releases.
Installing it and running one search
The requirement is Python 3.7 or newer, and installation is a single pip line:
pip install google-search-resultsThe quick start is three objects and one call:
from serpapi import GoogleSearch
search = GoogleSearch({
"q": "coffee",
"location": "Austin,Texas",
"api_key": "<your secret api key>"
})
result = search.get_dict()That example runs a search for coffee using your secret API key, and the result is a dictionary.
The parameter set is the interesting part of the design, because it mirrors what the underlying search engines accept. The README lists the parameters with comments describing their purpose: q for the query, location for the requested location, device for desktop, mobile or tablet, hl for the Google interface language, gl for the Google country, safe for the safe search flag, num for the number of results, start for the pagination offset, api_key, tbm for the vertical to match with values such as nws, isch or shop, tbs for custom search criteria, async to allow an asynchronous request, and output to choose json or html.
The same snippet shows the four ways to consume a result. get_html returns the raw html, get_dict returns a Python dictionary, get_json returns a JSON string via the json package, and get_object returns a dynamic Python object. The parameters are also mutable after construction, since the example overrides an existing parameter with search.params_dict["location"] = "Portland" before running the search.
Where the API key goes, and what it costs
There are two ways to supply the key, and the distinction is between a global setting and a per-search one. Globally:
GoogleSearch.SERP_API_KEY = "Your Private Key"And per search, using the serp_api_key parameter:
query = GoogleSearch({"q": "coffee", "serp_api_key": "Your Private Key"})The global form is convenient for a script that only ever talks to one account, and it is a footgun in a shared process, since the class attribute applies to every search from that point on. The per-search form is the one to reach for in a multi-tenant service where different users have different accounts.
Neither form removes the underlying constraint. This is a metered commercial service, and every call you make is a request against your SerpApi account. The Search Archive API is what softens that, because the search results are stored in a temporary cache and the previous search can be retrieved from the cache for free. The example shows how to pull the search id out of the metadata of a result and then fetch that same search back:
archived_search_result = GoogleSearch({}).get_search_archive(search_id, 'json')
print(archived_search_result.get("search_metadata").get("id"))For anything that runs on a schedule, or in a retry loop, or in a pipeline that re-runs the same queries, that archive is the difference between a bill and a free rerun, and it is the single most useful thing in this README for anyone building on the library.
Location lookup, and the other search verticals
The Location API is Google only, and it exists because the location parameter is a string that has to match what the search engine expects. The call asks for locations matching a name and takes a count:
from serpapi import GoogleSearch
search = GoogleSearch({})
location_list = search.get_location("Austin", 3)
print(location_list)The README says this prints the first three locations matching Austin, and shows Texas, Texas and Rochester in the example output. The returned records are dicts with fields such as canonical_name, country_code, google_id, gps coordinates, a keys list, a name, a reach figure and a target_type. In other words, the location string is resolved into a geographic record that the search then uses, and the ambiguity is resolved by the ids rather than by the display name.
The other verticals are separate classes rather than parameters, which keeps each engine's quirks in its own place. The README lists Bing via BingSearch, Baidu via BaiduSearch, Yahoo via YahooSearch, DuckDuckGo via DuckDuckGoSearch, eBay via EbaySearch, Yandex via YandexSearch, Home Depot via HomeDepotSearch, Google Scholar via GoogleScholarSearch, YouTube via YoutubeSearch, Walmart via WalmartSearch, the Apple App Store via AppleAppStoreSearch, and Naver via NaverSearch.
The README also points at a playground for generating code and a script builder for getting started, and the full documentation for the search API lives on the SerpApi site. For a generic call rather than a specific engine, there is a section on searching with SerpApiClient.
The build and test tooling is the older half of the repository
The package metadata comes from a setup.py rather than a pyproject.toml, and it holds some things that have not been updated. The distribution name is google_search_results with version 2.4.2, while the install command in the README uses the hyphenated google-search-results, which is the normalised form pip accepts. The classifiers list Python 3.5 through 3.9, and python_requires is set to 3.5 or newer, while the README says 3.7 or newer. The two statements disagree, and the README is the newer one.
The runtime dependency is requests, and the pinned requirements.txt lists certifi, chardet, idna, requests and urllib3 at fixed versions, along with the package itself installed in editable mode. Those pins are old enough to date the file.
The Makefile is where the development loop shows. Linting runs flake8 twice, first with a select list that stops the build on Python syntax errors and undefined names, then with exit-zero so the remaining findings are warnings. Tests run under pytest with the pytest-parallel plugin, and the example target runs a single async test. The build target produces a source distribution with setup.py, the check target runs twine check on it, and the release target uploads it with twine. There is an oobt target that installs the built tarball and runs a script from the oobt directory, which is an out-of-band test of the packaged artifact rather than the source tree.
The repository root also carries a README.rst alongside README.md, a MANIFEST.in, a .flake8 configuration, a testwrapper.py and a tests directory. The project states a preference for RSpec and continuous integration with test driven development, and says the test directory includes specification and examples.
Where this package is the wrong choice
The first wrong case is anything that needs to work beyond the deprecation window. The README tells you the package will be deprecated and recommends the newer implementation, and the release history backs that up. The last push was on 2026-08-18 and there are no GitHub releases on the repository, so there is no tagged artifact to pin to and no stated schedule for a final version. Starting a new integration on this package means starting one you will have to move.
The second is a design that insists on not paying for the service. Every call goes to a hosted API on a metered plan, and this client cannot work offline or against a local HTML scraper. If your requirement is to search without an API bill, this package is the wrong shape entirely, because the paid service is not an implementation detail of the client, it is the mechanism.
The third is a workload that needs the raw response only. If you want the HTML that Google would return, the client still requires a SerpApi account and key, and the output parameter set to html, so you are paying for a service to obtain something a scraper could return for free, at the cost of a terms of service you have to accept.
The fourth is code that needs a maintained dependency tree. A setup.py with python_requires at 3.5, classifiers for Python 3.5, and a requirements.txt pinning requests 2.25.1 and urllib3 1.26.9 is not a package that has been kept current. The current versions of those libraries carry fixes that this pin set does not.
The alternative is straightforward: use serpapi-python, which the README names as the successor, and which presumably keeps the same SerpApi account, the same key and the same underlying service, with a smaller surface to learn.
Editorial conclusion
Adopt serpapi-python rather than this package for new work, because the README for google-search-results states plainly that it will soon be deprecated and recommends migrating to the newer implementation to keep support and access to the latest features. If you already depend on google-search-results, plan the switch now rather than at the deprecation notice, and note that the SerpApi account and key stay the same across both. Before you migrate, check the import surface, since this package installs as google-search-results but its code lives under a serpapi directory and exposes classes such as GoogleSearch, BingSearch and YoutubeSearch, and remember that every search is a metered bill against your account rather than a free API call.
Frequently asked questions
Is the google-search-results Python package deprecated?
The README carries a warning that the package will soon be deprecated in favour of serpapi-python, and recommends migrating to the newer implementation to keep support and access to the latest features. New projects should start with serpapi-python instead.
How do I run a Google search from Python with this package?
Create a GoogleSearch with a dict holding q, location and api_key, then call get_dict for a Python dictionary, get_json for a JSON string, get_object for a dynamic object or get_html for the raw html. The key can be set globally on GoogleSearch.SERP_API_KEY or per search with the serp_api_key parameter.
Which search engines does the google-search-results package support?
There is a class per engine: GoogleSearch, BingSearch, BaiduSearch, YahooSearch, DuckDuckGoSearch, EbaySearch, YandexSearch, HomeDepotSearch, GoogleScholarSearch, YoutubeSearch, WalmartSearch, AppleAppStoreSearch and NaverSearch, plus a generic SerpApiClient for calls that are not tied to one engine.
How do I avoid paying twice for the same SerpApi search?
Use the Search Archive API. Search results are stored in a temporary cache and the previous search can be retrieved from that cache for free, by reading the search id out of the search_metadata of a result and passing it to get_search_archive.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/serpapi-google-search-results-python)Was this useful?