Bing Search API in Python: A 2026 Tutorial
Microsoft retired the official Bing Web Search API in 2025, so if you want Bing results as JSON in 2026, you use a SERP API instead of a first-party Microsoft product. Serpent API exposes Bing as one of its five public engines: set engine=bing, and the same endpoint that returns Google, Yahoo, DuckDuckGo, or Brave returns Bing's web results with the same response shape.
This tutorial walks through the practical path in Python: a real requests fetch, an async httpx variant, and how to read the honest response shape — json.results.organic with position, title, and url on every result. If you want the wider context on what changed with Microsoft's API, our Bing Search API replacements guide covers the retirement and the alternatives side by side.
TL;DR: One GET to https://apiserpent.com/api/search?q=QUERY&engine=bing with an X-API-Key header returns Bing results as JSON. Iterate json.results.organic for position/title/url. Works with requests or httpx, paginates with pages, targets countries with country. Web results from $0.03/1K at Scale, 10 shared free calls for new accounts, no subscription.
The engine parameter
Every Serpent search takes an engine parameter. Bing is engine=bing, and it is one of five supported values alongside google, yahoo, ddg, and brave. Bing and Yahoo are separate public engine values with the same pricing category, so switching engines is a one-parameter change rather than a different endpoint.
Because Bing is a full engine rather than a special route, it supports the same search surface as the others: web results with snippets, People Also Ask boxes, video results, shopping product listings, ads, and related searches — each parsed into JSON fields when they appear for a query. There are also dedicated /api/news, /api/images, and /api/videos endpoints for Bing, all billed under the same flat catalog.
A minimal requests example
Install requests if you have not already, then copy this. It sends the query, reads the JSON, and prints each organic result's position, title, and URL:
import requests
params = {
"q": "best running shoes 2026",
"engine": "bing",
"country": "us",
"num": 10,
}
headers = {"X-API-Key": "YOUR_API_KEY"}
resp = requests.get("https://apiserpent.com/api/search", params=params, headers=headers)
data = resp.json()
for result in data["results"]["organic"]:
print(result["position"], result["title"], result["url"])
That is the whole integration. There is no OAuth flow, no per-engine SDK, and no subscription to manage — the API key goes in the X-API-Key header, and the response is plain JSON. The same call returns Yahoo or DuckDuckGo with engine=yahoo or engine=ddg.
What the response looks like
The response wraps everything under a results object. The organic array holds the blue-link results; each item has a position, title, url, and snippet. Here is the shape for a single result:
{
"searchParameters": { "q": "best running shoes 2026", "engine": "bing", "country": "us" },
"results": {
"organic": [
{
"position": 1,
"title": "Best Running Shoes 2026: 12 Expert Picks",
"url": "https://example.com/best-running-shoes-2026",
"snippet": "We tested 40+ pairs of running shoes across every category..."
}
]
},
"credits": { "used": 1, "remaining": 99 }
}
Other keys appear conditionally. On a commercial query you may see results.shoppingResults with product names and prices, or results.videos with durations and thumbnails. peopleAlsoAsk and relatedSearches are common on informational queries. Treat them as present-when-available rather than guaranteed — the stable contract is the organic array.
Iterating organic results
For rank tracking and SEO tooling, the loop you want is over organic. A compact version that collects the top ten URLs:
urls = [
(r["position"], r["url"])
for r in data["results"]["organic"]
]
for position, url in urls:
print(position, url)
Because the fields are stable across all five engines, you can write one function that takes an engine name and reuse it for Bing, Google, Yahoo, DuckDuckGo, and Brave — which is exactly how a multi-engine rank tracker stays maintainable.
Async with httpx
When you are checking hundreds of queries, an async client is the right tool. The same request with httpx looks like this:
import httpx, asyncio
async def bing_search(query: str):
async with httpx.AsyncClient() as client:
resp = await client.get(
"https://apiserpent.com/api/search",
params={"q": query, "engine": "bing", "country": "us", "num": 10},
headers={"X-API-Key": "YOUR_API_KEY"},
)
resp.raise_for_status()
return resp.json()["results"]["organic"]
async def main():
results = await bing_search("best running shoes 2026")
for r in results:
print(r["position"], r["title"], r["url"])
asyncio.run(main())
Fan out asyncio.gather across a keyword list and you can check a few hundred queries per minute from a single Python process, then write the results to a CSV or a database for a rank-tracking pipeline.
Country, pagination, and filters
Bing search supports 112 country codes through the country parameter — us, uk, in, de, fr, jp, and more. Add it when you need localized results rather than the default region. Pagination uses pages to move past page one, and num controls results per page up to the documented maximum.
| Parameter | What it does |
|---|---|
engine=bing | Selects the Bing index |
q | The query you are searching for |
country | ISO country code for localized results (112 supported) |
num | Results per page (10 by default) |
pages | Pagination past the first page |
freshness | Restrict to recent results (day/week/month) |
A freshness filter is useful for news-adjacent queries; combine freshness=7d with a trending keyword and you get only recent coverage. The full parameter reference lives in the documentation, and you can try a live query without writing code in the playground.
Rate limits and errors, honestly
Two things to know before you scale up. First, a non-2xx response is not charged — failed requests do not consume credits, so a retry loop that checks the status code is safe to build. Second, if you hit a 429, it means automated overuse or temporary server load, and the fix is to back off and retry with exponential delay rather than hammer the endpoint harder. Treating the API politely is the only pacing rule you need.
For a production pipeline, wrap the fetch in a small retry helper that catches 429 and 5xx, sleeps, and retries a limited number of times. Combined with the async pattern above, that is a complete, honest Bing data pipeline in under fifty lines. If you would rather compare the options before committing, our free Bing scraping guide lays out the DIY route alongside the API.
Bing results, parsed JSON, in one request.
Serpent returns parsed JSON for Bing, Google, Yahoo, DuckDuckGo, and Brave through one endpoint. New accounts include 10 shared free calls on eligible endpoints, then pay-as-you-go pricing with no subscription.
Get Your Free API KeyExplore: Bing SERP API · All SERP APIs · Pricing
FAQ
Is there still an official Bing Search API?
Microsoft retired the Bing Web Search API in 2025. In 2026 the practical route to Bing results as JSON is a SERP API such as Serpent API, which exposes Bing through engine=bing with the same contract as Google, Yahoo, DuckDuckGo, and Brave.
What does the Bing response include?
The Bing response includes organic results with position, title, url, and snippet. When present for the query it also includes People Also Ask, video results, shopping product listings, ads, and related searches, all returned as structured JSON.
How much does Bing search data cost?
Serpent uses flat per-call pricing with no subscription. Bing web search starts at $0.60/1K pages on Default, $0.06/1K on Growth, and $0.03/1K on Scale. New accounts get 10 shared free calls on eligible endpoints.
Can I use Python requests or httpx?
Yes. The endpoint accepts any HTTP client. Send a GET to https://apiserpent.com/api/search with the q, engine, and country parameters and an X-API-Key header, then read json.results.organic. The examples in this guide use requests and httpx.

