# Bing SERP Scraper (`axiomworks/bing-search-scraper`) Actor

Scrape Bing SERPs for queries in a chosen country and language. Results include organic ranks, titles, URLs, displayed URLs, snippets and dates, along with text ads and related searches.

- **URL**: https://apify.com/axiomworks/bing-search-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** SEO tools
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bing Search Results Scraper

**Returns:** one row per Bing result with type, query, position, title, url, domain, snippet, sourceUrl.
**Input:** `{"queries": ["best running shoes"], "country": "US", "maxPagesPerQuery": 1, "maxItems": 10}`
**Best for:** SEO rank tracking, competitor research, web search for AI agents.

```json
{"type": "organic", "query": "laptop kaufen", "position": 1, "title": "Laptops & Notebooks kaufen bei MediaMarkt", "url": "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html", "emphasizedKeywords": ["Laptops", "Notebooks kaufen"], "sourceUrl": "https://www.bing.com/search?q=laptop%20kaufen&cc=DE&setlang=de"}
```

### What does Bing Search Results Scraper do?

This Bing scraper returns structured Bing SERP data: one row per organic result, text ad or related search. Supply queries, a country and a language to use it as a Bing API for search workflows.

It is built for three common jobs:

- **SEO rank tracking.** Every organic record carries a rank (`position`), the page it appeared on, the decoded target URL and the domain, so you can see where a site ranks for a keyword in a given market and compare runs over time.
- **Competitor ad monitoring.** Text ads are returned with their headline, landing URL, displayed URL, advertiser and placement (top, bottom or other), so you can watch who bids on a keyword.
- **Web search for AI agents and pipelines.** One record is one result, which makes the output easy to feed to a language model, a spreadsheet or a database.

The Actor reads the public Bing results page the same way a visitor's browser would. It does not log in, and it never opens the result pages or clicks the ads. Only Bing search pages are requested, and ad landing URLs are decoded from the ad link rather than visited, so no advertiser is charged for a click.

Results depend on the market you choose. The Actor sends the country to Bing and also routes the request through a residential connection in that country, because Bing returns degraded or empty pages when the connection country and the market do not match.

### What data can you get?

Fields that do not apply are generally `null`; `breadcrumbs` is emitted only for organic records.

| Field | Type | Description |
|---|---|---|
| `id` | string | Stable 16-character id built from the type, market, query and URL (or suggestion text) |
| `type` | string | `organic`, `ad` or `relatedSearch` |
| `query` | string | Search query sent to Bing |
| `country` | string | Upper-case 2-letter country code used |
| `language` | string | Language code used |
| `page` | integer | Results page (1-based) where the item was first seen |
| `position` | integer | Organic: absolute rank across pages. Ad and related search: order of first appearance within the query |
| `positionOnPage` | integer | Organic only: rank within its page |
| `title` | string | Result headline, or the suggested query for a related search |
| `url` | string | Decoded target URL, ad landing URL, or the Bing search URL for a related search |
| `displayedUrl` | string | The breadcrumb-style URL line Bing shows under the title |
| `breadcrumbs` | array | Organic only: the path segments of the displayed URL, split on the separator Bing shows |
| `faviconUrl` | string | Organic only: icon URL shown in the result header, when present; never fetched |
| `emphasizedKeywords` | array | Organic only: distinct bold text spans in the title and snippet, preserving Bing wording |
| `domain` | string | Hostname of `url` without `www.` |
| `snippet` | string | Description text under the result |
| `date` | string | Organic only: the date Bing shows before the snippet, when present |
| `siteName` | string | Organic only: the site label Bing shows above the title |
| `adUrl` | string | Ads only: the raw Bing click link (never requested) |
| `advertiser` | string | Ads only: the advertiser domain shown on the ad |
| `placement` | string | Ads only: `top`, `bottom` or `other` |
| `resultsTotal` | integer | Bing's "About N results" estimate for the page, when shown |
| `sourceUrl` | string | The exact Bing results page URL the record came from |
| `scrapedAt` | string | ISO timestamp of collection |

`emphasizedKeywords` contains distinct bold spans from the organic title and snippet, preserving capitalization. It reports Bing's wording, without inferring relevance or operator support. It is null when neither element has bold spans.

`faviconUrl` is the icon URL in the organic result header, when available. It is not a thumbnail. The Actor never fetches it; an application displaying it decides whether to load the image. These nullable fields add context without creating extra records or requests.

A few notes on how the fields behave:

Organic ranks are deduplicated by URL across pages, and results that Bing shows inside AI summary boxes are not counted as organic rank positions. Ads are deduplicated within a query, because the same ad often shows on several pages.

- The `date` field is only filled when Bing prints a date in front of the snippet, which is the case for a minority of results.
- Ads and related searches mostly appear from the second results page onward, so with `maxPagesPerQuery` set to 1 you will usually get organic results only.

### How to use

1. Open the Actor and go to the Input tab.
2. Type one search query per line under **Search queries**, for example `best running shoes`. Alternatively supply Bing search URLs as strings or `{"url":"…"}` objects under **Bing search URLs**.
3. Enter a 2-letter **Country** code and a **Language** code, such as `US` and `en`.
4. Set **Max pages per query** and **Max items** to control how much is collected.
5. Choose which result types you want: organic results, ads and related searches.
6. Leave the proxy setting on its default. Residential proxies are required for complete pages and are applied automatically.
7. Click Start. Results appear in the dataset as they are collected, and you can export them as JSON, CSV, Excel or XML.

Queries are processed up to three at a time, and the pages within one query are fetched one after another with a short pause. A run with a single query and three pages typically takes under a minute.

#### Search operators

Search terms are passed to Bing exactly as you type them. Operators such as quotes, `-term` or `site:` are included in the request, but Bing does not always honor them for anonymous visitors, so do not rely on operator filtering for rank tracking.

#### Start URLs

If you already have Bing search URLs, put them in **Bing search URLs**. The Actor reads `q` (the query), `cc` (the country) and `setlang` (the language) from each URL. Those values override the Country and Language inputs for that URL. Other parameters, such as filters, are kept. URLs that are not Bing search URLs, or that have no `q` parameter, are skipped with a warning.

#### Nonsense and misspelled queries

Bing silently replaces queries it cannot match with a different query and shows results for that instead. With **Skip substituted queries** on (the default), the Actor checks whether any word of your query appears in the first-page results. If none does, it returns nothing for that query and reports why in the run status message and in the `RUN_SUMMARY` record. Turn the option off if you want whatever Bing returns.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `queries` | array of strings | prefill `best running shoes` | Search terms, one per item. Also accepted under the names `searchQueries`, `keywords` and `query` |
| `startUrls` | array | none | Full Bing search URLs. Plain strings and `{ "url": ... }` objects both work |
| `country` | string | `US` | 2-letter market code, also used as the proxy country |
| `language` | string | `en` | Language code sent to Bing (for example `en`, `de`, `fr`, `zh-hans`) |
| `maxPagesPerQuery` | integer | 3 | Results pages per query, 1 to 20 |
| `maxItems` | integer | 100 | Maximum records across all queries and types, 1 to 10000 |
| `timeRange` | string | any | Freshness filter for search terms: `any`, `day`, `week` or `month` |
| `includeOrganic` | boolean | true | Return organic results |
| `includeAds` | boolean | true | Return text ads |
| `includeRelatedSearches` | boolean | true | Return related searches |
| `skipUnrelatedResults` | boolean | true | Drop queries that Bing replaced with a different query |
| `proxyConfiguration` | object | Apify residential | Proxy settings. Residential is enforced |

Example input:

```json
{
  "queries": ["project management software", "crm software"],
  "country": "US",
  "language": "en",
  "maxPagesPerQuery": 2,
  "maxItems": 80,
  "includeAds": true,
  "includeRelatedSearches": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

The `maxItems` limit is exact: when it is reached, the Actor stops requesting pages and stops adding records. Within each page, records are written in this order: organic results first, then ads, then related searches. A small `maxItems` therefore returns organic results from the first page.

### Output

This organic record came from a local run of `laptop kaufen` in the German market. The null icon reflects that response variant; other Bing layouts provide the icon URL.

```json
{
  "id": "7ae1878cf2283980",
  "type": "organic",
  "query": "laptop kaufen",
  "country": "DE",
  "language": "de",
  "page": 1,
  "position": 1,
  "positionOnPage": 1,
  "title": "Laptops & Notebooks kaufen bei MediaMarkt",
  "url": "https://www.mediamarkt.de/de/category/laptops-notebooks-362.html",
  "displayedUrl": "https://www.mediamarkt.de › de › category",
  "breadcrumbs": [
    "www.mediamarkt.de",
    "de",
    "category"
  ],
  "faviconUrl": null,
  "emphasizedKeywords": [
    "Laptops",
    "Notebooks kaufen"
  ],
  "domain": "mediamarkt.de",
  "snippet": "Laptops & Notebooks für alle Bedürfnisse Homeoffice Bildbearbeitung und vieles mehr - Jetzt bei MediaMarkt online kaufen!",
  "date": null,
  "siteName": "mediamarkt.de",
  "adUrl": null,
  "advertiser": null,
  "placement": null,
  "resultsTotal": 46000,
  "sourceUrl": "https://www.bing.com/search?q=laptop%20kaufen&cc=DE&setlang=de",
  "scrapedAt": "2026-10-12T23:51:46.947Z"
}
```

An ad record has the same fields, with `type` set to `ad`, the decoded landing page in `url`, the raw Bing click link in `adUrl`, and `advertiser` and `placement` filled in when Bing shows them.

Besides the dataset, each run stores a `RUN_SUMMARY` record in the default key-value store. For every query it lists the pages fetched, the number of organic results, ads and related searches, the number of retries and the reason a query returned nothing, if any.

### How much does it cost?

Every dataset record is one charged result. `maxItems` caps the records returned. See the Pricing tab for current billing details. Runs stop successfully with a clear message when the maximum cost per run cannot cover another result.

To keep a run small, lower `maxItems` and `maxPagesPerQuery`, and turn off the result types you do not need.

### Use with AI agents (MCP)

You can call this Actor from any MCP-compatible client through the Apify MCP server. Add the Actor as a tool with a configuration like this:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/bing-search-scraper"
    }
  }
}
```

Example prompts for your agent:

- "Search Bing for 'best running shoes' in the US and list the top 10 organic results with their domains."
- "Use Bing to check which advertisers show text ads for 'crm software' in the UK."
- "Get the related searches Bing suggests for 'home insurance' and group them by topic."

Each record is one result, so an agent can call the Actor with `{"queries": ["your query"], "maxPagesPerQuery": 1}` and read the dataset items directly.

### Integrations and API

You can run the Actor from code with the Apify API clients, or connect it to other tools through Apify integrations and webhooks. Replace `YOUR_API_TOKEN` with your own token (in cURL, set it in the `APIFY_TOKEN` environment variable and send it in the `Authorization` header).

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("axiomworks/bing-search-scraper").call(run_input={
    "queries": ["best running shoes"],
    "country": "US",
    "language": "en",
    "maxPagesPerQuery": 2,
    "maxItems": 30,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["type"], item["position"], item["title"], item["url"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('axiomworks/bing-search-scraper').call({
    queries: ['best running shoes'],
    country: 'US',
    language: 'en',
    maxPagesPerQuery: 2,
    maxItems: 30,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) process.stdout.write(`${item.position} ${item.title}\n`);
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~bing-search-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries": ["best running shoes"], "maxPagesPerQuery": 1, "maxItems": 10}'
```

### FAQ

#### Why do I get fewer results than I asked for?

Bing shows between about 6 and 14 organic results per page, and the number of pages it serves is limited. If a query has fewer results than `maxItems`, or the page limit is reached first, the run ends with fewer records. Raise `maxPagesPerQuery` to get more.

#### Why are there no ads or related searches on page 1?

A fresh visit to Bing usually shows a first page without ads and without related searches. They tend to appear from page 2. Set `maxPagesPerQuery` to at least 2 or 3 if you need them. Some queries simply have no ads in some countries.

#### Why did a query return nothing?

Check the run status and `RUN_SUMMARY`. Try broader terms, check country/language and residential proxy access, or set `skipUnrelatedResults=false` to accept substitutions. Enable `includeOrganic`; ads and suggestions may need more pages.

#### Why do my results differ from what I see in my browser?

Bing personalizes results by location, including the city of the connection, and by session. Results can also change between runs. Expect some variance, especially for local queries.

#### Does the Actor support search operators?

Operators are sent as typed, but Bing may ignore them for anonymous visitors. Do not depend on them.

#### Which countries and languages are supported?

Use a 2-letter country code and a language code such as `en` or `en-US`.

#### What happens when Bing blocks a request?

The Actor retries blocked or failed requests up to three times with a pause between attempts, each time on a fresh proxy session. A target returning no records has a 75-second request budget. Unresolved targets are reported in `RUN_SUMMARY`; the run continues successfully.

### Is it legal to scrape Bing?

The Actor reads publicly visible search result pages and does not log in or access any private data. Whether scraping is appropriate for your use depends on your jurisdiction, your purpose and the terms of the website. Search results can contain personal data, so handle any personal information in line with the privacy rules that apply to you, such as GDPR. Microsoft's terms of service restrict automated querying of Bing, so check them and take legal advice if you are unsure. This Actor is an independent tool and is not affiliated with or endorsed by Microsoft or Bing.

### Feedback

If a field is missing, a market behaves unexpectedly or Bing changes its page layout and results look wrong, open an issue from the Actor page and include the query, the country and the run link.

# Actor input Schema

## `queries` (type: `array`):

Search terms, e.g. \["laptop kaufen"], or one per editor line. Required unless startUrls is supplied. Also accepts Bing URLs; API aliases query, searchQueries and keywords accept strings or arrays. Operators pass through but Bing may ignore them. Bad, blocked or unmatched targets return no records and a status message; other targets continue.

## `startUrls` (type: `array`):

Bing URLs containing q, e.g. \["https://www.bing.com/search?q=crm+software\&cc=GB\&setlang=en"] or \[{"url":"https://www.bing.com/search?q=crm"}]. Optional, default empty. URL cc/setlang override country/language; other filters are preserved. Non-Bing or q-less URLs are skipped.

## `country` (type: `string`):

Country code for Bing cc and the residential proxy, e.g. "US" or "DE"; default "US". API accepts any 2-letter code case-insensitively, e.g. "us". A search URL cc overrides this value.

## `language` (type: `string`):

Language code for Bing setlang and Accept-Language, e.g. "en", "de" or "zh-hans"; default "en". API also accepts regional codes such as "en-US" and uses the language part. A search URL setlang overrides this value.

## `maxPagesPerQuery` (type: `integer`):

Maximum Bing pages per query, e.g. 1 for a quick search; 1-20, default 3. Stops earlier if Bing has no next page or maxItems is reached. Ads and related searches may appear only on later pages.

## `maxItems` (type: `integer`):

Maximum dataset records across all queries and selected result types, e.g. 10; 1-10000, default 100. One record is one result. Returns fewer when Bing supplies fewer eligible results.

## `timeRange` (type: `string`):

Bing freshness filter for search terms: "any", "day", "week" or "month", e.g. "week"; default "any". Requests Bing’s filter; dates and matching depend on Bing. Does not add a filter to startUrls; use the URL’s filters parameter there.

## `includeOrganic` (type: `boolean`):

Whether to return organic records with rank, title, URL and snippet, e.g. true; default true. Set false to collect only other enabled result types.

## `includeAds` (type: `boolean`):

Whether to return ad records with title, landing URL, advertiser and placement when Bing shows them, e.g. false; default true. Ad links are decoded, never clicked. Enabling this does not guarantee ads.

## `includeRelatedSearches` (type: `boolean`):

Whether to return relatedSearch records with suggested query text and a Bing search URL when present, e.g. false; default true. Enabling this does not guarantee suggestions.

## `skipUnrelatedResults` (type: `boolean`):

Whether to drop a query when none of its words match first-page organic results, e.g. true; default true. Set false if legitimate results use different wording and you want to keep whatever Bing returns.

## `proxyConfiguration` (type: `object`):

Proxy settings, e.g. {"useApifyProxy":true,"apifyProxyGroups":\["RESIDENTIAL"]}; default the same. Apify Proxy is forced to RESIDENTIAL and matched to each query’s country. Custom proxyUrls are also accepted; their geographic suitability is your responsibility.

## Actor input object example

```json
{
  "queries": [
    "best running shoes"
  ],
  "startUrls": [],
  "country": "US",
  "language": "en",
  "maxPagesPerQuery": 1,
  "maxItems": 10,
  "timeRange": "any",
  "includeOrganic": true,
  "includeAds": true,
  "includeRelatedSearches": true,
  "skipUnrelatedResults": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "best running shoes"
    ],
    "country": "US",
    "language": "en",
    "maxPagesPerQuery": 1,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/bing-search-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": ["best running shoes"],
    "country": "US",
    "language": "en",
    "maxPagesPerQuery": 1,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/bing-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "best running shoes"
  ],
  "country": "US",
  "language": "en",
  "maxPagesPerQuery": 1,
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call axiomworks/bing-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/bing-search-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7hQ2FuY7rcTX3UHa6/builds/prazYBlUuY8VZgMN0/openapi.json
