Introduction

The official Bing Search API is soon to be retired on 11th August 2025 (or has already been retired depending on when you're reading this) and you may be searching for a suitable replacement.

Here at SerpApi, we provide our own Bing Search API that can be easily integrated to minimize disruption to your service once the official APIs have been retired.

In this blog post, I'm going to describe the basic changes you will need to make to make the move to SerpApi's Bing Search API.

Step 1: SerpApi Account

If you don't already have an account with us, your first step is going to be signing up for an account (we offer a free account with 100 free searches per month).

Once you have signed up and verified your account, you will need to take note of your SerpApi API key found on your dashboard so that you can use it in the following steps.

Step 2: Endpoint and Authentication

First we're going to start off by changing the endpoint and the authentication to move from using the official Bing endpoint and Azure subscription key and over to using the SerpApi endpoint and a SerpApi API key.

An overly simplified version of your current setup may look something like so:

# environment
subscription_key = 'AZURE-SUBSCRIPTION-KEY'
endpoint = 'https://api.bing.microsoft.com/v7.0/search'

# search params
query = 'Bing Search API'
mkt = 'en-US'
headers = { 'Ocp-Apim-Subscription-Key': subscription_key }
params = { 'q': query, 'mkt': mkt }

# request
response = requests.get(endpoint, headers=headers, params=params)
response.raise_for_status()

print("\nJSON Response:\n")
pprint(response.json())

First you'll need to change the environment variables we have to use your SerpApi API key and our endpoint:

  # environment
- subscription_key = 'AZURE-SUBSCRIPTION-KEY'
+ subscription_key = 'SERPAPI-API-KEY'
- endpoint = 'https://api.bing.microsoft.com/v7.0/search'
+ endpoint = 'https://serpapi.com/search.json'

Next we're going to authenticate via the api_key query parameter and remove the headers entirely as they're not necessary for any calls to our endpoint.

  # search params
  query = 'Bing Search API'
  mkt = 'en-US'
- headers = { 'Ocp-Apim-Subscription-Key': subscription_key }
- params = { 'q': query, 'mkt': mkt }
+ params = { 'q': query, 'mkt': mkt, 'api_key': subscription_key }

  # request
- response = requests.get(endpoint, headers=headers, params=params)
+ response = requests.get(endpoint, params=params)
  response.raise_for_status()

If your implementation is relatively simple and only uses the q and mkt parameters, then when you make these changes, you should see a full response come back from our endpoint at this stage. The official API's response format differs from our own so there are still changes to make, but we're part way there.

Step 3: Header Functionality

SerpApi does not utilize headers for searches, but the functionality provided by the following official API request headers may be largely reproduced by other means:

  • Accept-Language - Language to use for the interface returned. You can not directly set this in our API, instead we infer it from the mkt code provided
  • Ocp-Apim-Subscription-Key - API key authentication. As described earlier, we use query parameter api_key for authentication
  • Pragma - Toggles cache state, e.g. no-cache. We use query parameter no_cache=true to disable caching, otherwise searches are cached by default
  • User-Agent - User agent to use for the search, can be used to get results on a per device basis. We use query parameter device with options desktop, tablet, and mobile to achieve this
  • X-Search-Location - Location to use for the search, e.g. (lat:55;long:-111;re:22 or disp:Seattle, Washington)
    • For lat and long we use the query parameters lat and lon
    • For disp we use the query parameter location
    • All other value types such as radius or timestamp are not supported by our API

The official API supports a number of headers, the following are entirely unsupported by our API:

  • Accept - Used to specify either application/json or application/ld+json. Using the query parameter output, our API can only be toggled between json or html
  • X-MSEdge-ClientID - Used by Bing to assign traffic on a consistent route
  • X-MSEdge-ClientIP - Used by Bing to infer the user's location

We do not utilize any response headers to convey information about a search result, so the following official API response headers will not be seen when using our API:

  • BingAPIs-Market - Market used by the request
  • BingAPIs-TraceId - ID used by Bing to correlate to their logs
  • Retry-After - Rate limiting information
  • X-MSEdge-ClientID - Assigned/used client ID

Example Header Changes

To illustrate with an example, if you used headers in your script and they looked like this:

headers = {
  'Ocp-Apim-Subscription-Key': 'AZURE-SUBSCRIPTION-KEY',
  'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML; like Gecko) Mobile/10B142 iPhone4;1 BingWeb/3.03.1428.20120423',
  'X-Search-Location': 'lat:55;long:-111;re:22',
  'X-MSEdge-ClientIP': '202.89.233.101',
  'Pragma': 'no-cache',
}
params = {
  'q': 'Bing Search API',
  'mkt': 'en-US',
}

Then you would be able to retain most of that functionality other than the IP address assignment with the following changes:

  headers = {
-   'Ocp-Apim-Subscription-Key': 'AZURE-SUBSCRIPTION-KEY',
-   'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML; like Gecko) Mobile/10B142 iPhone4;1 BingWeb/3.03.1428.20120423',
-   'X-Search-Location': 'lat:55;long:-111;re:22',
-   'X-MSEdge-ClientIP': '202.89.233.101',
-   'Pragma': 'no-cache',
  }
  params = {
    'q': 'Bing Search API',
    'mkt': 'en-US',
+   'lat': '55',
+   'lon': '-111',
+   'device': 'mobile',
+   'no_cache': 'true',
+   'api_key': 'SERPAPI-API-KEY',
  }

Step 4: Query Parameters

The following query parameters behave the same in both the official API and our API, so you don't need to adjust these:

  • q - The search query term
  • mkt - The market for the search results
  • cc - The country for the search results
  • count - The number of results to return
  • safeSearch - The mode to use for safe search

The following query parameter behaves the same, but has a different name in our API:

  • offset - The number of results to skip before returning search results. This is called first in our API

The following query parameters can be supported through alternate means in our API:

  • freshness - Controls the age or date-range of search results. These can be achieved using the filter parameter in our API with the following values:
    • Value Day becomes ex1:"ez1" (past 24 hours)
    • Value Week becomes ex1:"ez2" (past 7 days)
    • Value Month becomes ex1:"ez3" (past month)
    • Year (unsupported by official API) becomes ex1:"ez4" (past year)
    • Single date (e.g. 2019-02-04) becomes ex1:"ez5_17931_17931" (number of days since 1970-01-01)
    • Date range (e.g. 2019-02-04..2019-02-06) becomes similar to ex1:"ez5_17931_17933" (number of days since 1970-01-01)

The remaining query parameters are unsupported in our API but you can achieve a similar result programmatically:

  • answerCount - Number of answer types to include in the search results. You will need to selectively ignore/include result types after receiving a response to achieve this
  • promote - Answer types to promote in the search results. You will need to selectively promote or demote result types after receiving a response to achieve this
  • responseFilter - Answer types to receive to be returned or excluded in the search results. You will need to selectively include/reject result types after receiving a response to achieve this
  • setLang - Language to use for the interface returned. You can not directly set this in our API, instead we infer it from the mkt code provided
  • textDecorations - Whether or not snippets should contain highlighting decorations. Our API will always provide a plain text snippet attribute and a secondary snippet_highlighted_words array attribute where able
  • textFormat - Format of the text decorations (raw or HTML). You will need to manually build the desired format using snippet and the snippet_highlighted_words array if present

Example Query Parameter Changes

Here is an example to help illustrate where a variety of query parameters have been used with the official API:

params = {
  'q': 'Bing Search API',
  'mkt': 'en-US',
  'offset': 10,
  'count': 5,
  'freshness': '2019-02-04',
  'textDecorations': 'false',
  'textFormat': 'raw',
}

All of the above query parameters, with the exception of textDecorations and textFormat can be used as-is or ported to use with our API.

Here are the changes that would need to be made to the example to achieve this:

  params = {
    'q': 'Bing Search API',
    'mkt': 'en-US',
-   'offset': 10,
+   'first': 10,
    'count': 5,
-   'freshness': '2019-02-04',
+   'filters': 'ex1:"ez5_17931_17931"',
-   'textDecorations': 'false',
-   'textFormat': 'raw',
  }

Step 5: Response Format

While the previous steps have all been quite straightforward, the changes to the response format handling will likely be the most involved for you depending on how much of the data you have been using.

Due to the sheer number of different possible response objects available, I'm only going to cover a few of them directly in this blog post.

Web Pages

Returned in the webPages.value key (an array of results) in the official API, our API returns the equivalent in the top level organic_results key (an array of results).

The Bing search URL that would be found under webPages.webSearchUrl in the official API can be found under search_metadata.bing_url in our API.

When available, the estimated number of results that was previously found under webPages.totalEstimatedMatches will be available under search_information.total_results in our API.

Web Page Result Mapping

The following attributes on the web page result objects can be mapped and used without change:

  • name - Name of the web page. Becomes title on our API
  • url - URL of the web page. Becomes link on our API
  • displayUrl - Displayed URL of the web page. Becomes displayed_link on our API
  • snippet - Snippet describing the web page. No change to name.
    • In order to retain highlighting functionality, you must also utilize the snippet_highlighted_words array (when available) from our API to highlight this in your application

The dateLastCrawled and datePublished attributes are not available and have no equivalent, however, the datePublishedDisplayText has a similar property in our result named date.

The date attribute in our API will return the date displayed in the result, though it can be in the form of a formatted date (e.g. Oct 29, 2020) or a relative date (e.g. 3 days ago).

The deepLinks attribute in the official API can be somewhat mapped by reading the sitelinks.inline and sitelinks.expanded attributes which each contain objects with at least the attributes title, link, and tracking_link in them.

Significantly more is available on these organic results when using our API, so don't forget to check out the Bing Organic Results API documentation page.

Returned in the relatedSearches.value key (array of related searches) in the official API, our API returns the equivalent in the top level related_searches key (array of related searches).

The following attributes on the related search result objects can be mapped and used without change:

  • displayText - Display text of the related search. Becomes query on our API, always unformatted
  • text - Unformatted text of the related search. Becomes query on our API
  • webSearchUrl - URL for the Bing search. Becomes link on our API

Images

Returned in the images.value key (array of images) in the official API, our API returns the equivalent in the inline_images.items key (array of images).

The Bing search URL found at images.webSearchUrl in the official API can be found at inline_images.see_more_link in ours.

The images.readLink attribute in the official API which provides the URL for the equivalent API image search can be found at inline_images.serpapi_link in our API.

The isFamilyFriendly attribute in the official API has no equivalent in our API.

Image Result Mapping

The following attributes on the image result objects can be mapped and used without change:

  • name - Name of the image result. Becomes title on our API
  • thumbnailUrl - URL to the image thumbnail. Becomes thumbnail on our API
  • webSearchUrl - URL to view the image in Bing search. Becomes link on our API
  • hostPageUrl - URL the image is found on. Becomes source.link on our API

What's Next

If you were able to make the move using everything we've covered in this blog post, great work, there's nothing left for you to do!

Otherwise if you were utilizing much more of the official Bing Search API than we were able to cover here, then you're going to want to take a look over our Bing Search API documentation and everything we provide to fill the rest of the gaps.

It's also worth taking a look at our Bing Playground and performing a few searches to see it all in action.

That's all for now, I hope this was helpful to get you started on your transition to our Bing Search API!