# Microsoft Ads Library Scraper: Bing Ads & Impressions (`kyungminlee/microsoft-ads-library-scraper`) Actor

Scrape the Microsoft (Bing) Ads Library: every Bing search ad an advertiser ran in the EU/EEA, with ad copy, URLs, images and optional details (first/last shown, impressions range, impressions by country, targeting). Official public API, no login. $1.50 per 1,000 ads. Unofficial.

- **URL**: https://apify.com/kyungminlee/microsoft-ads-library-scraper.md
- **Developed by:** [Kyungmin Lee](https://apify.com/kyungminlee) (community)
- **Categories:** Marketing, SEO tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 ads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Microsoft Ads Library Scraper do?

**Microsoft Ads Library Scraper** pulls **every Bing search ad an advertiser has run in Europe** out of the [Microsoft Ads Library](https://adlibrary.ads.microsoft.com), Microsoft's public ad transparency database. Type a brand name (`Nike`, `Booking`) or paste advertiser IDs. You get each ad as a clean row: **headline, description, display URL, landing page, images**, the advertiser's verified identity and a link to the ad's Library page. Turn on **ad details** to also get **first and last shown dates, total impressions range (with numeric min/max), impression share by country, targeting types** and who paid for the ad.

It calls Microsoft's **publicly documented Ad Library API** (`adlibrary.api.bingads.microsoft.com`) without any account, login or browser, so runs are fast and cheap. The Library covers ads shown in the **European Economic Area (EU + Iceland, Liechtenstein, Norway) since June 2023**.

**Using Google too?** Pair this Actor with [Google Ads Transparency Center Scraper](https://apify.com/kyungminlee/ads-transparency-scraper) for **Google + Bing search ads transparency** with the same workflow and field names.

### Why use Microsoft Ads Library Scraper?

- **PPC competitor research**: see every Bing/Microsoft Advertising ad a competitor runs, their copy, landing pages and which EU markets they target.
- **Agency reporting**: schedule a weekly run per client or competitor and send new ads to Sheets, Slack or your dashboard.
- **Reach estimates**: impressions ranges and per-country impression shares show where a campaign actually ran and how big it was.
- **Compliance and brand protection**: find advertisers using your brand in their ads and check "paid for by" and restriction information published under the EU Digital Services Act.
- **Ad copy datasets**: collect thousands of real search ad headlines and descriptions for creative research or AI training.

### How to use Microsoft Ads Library Scraper

1. Enter one or more **Advertiser names** (for example `Nike`) or **Advertiser IDs** / advertiser page URLs.
2. Optionally pick **Countries** (`Germany`, `FR`, `NL`...) and a date window (**Shown from / Shown until**, absolute or relative like `30 days`).
3. Set **Max ads per advertiser** (default 100) and switch on **Include ad details** if you need dates, impressions and targeting.
4. Click **Start**. Ads appear in the **Dataset** tab; export JSON, CSV, Excel or HTML, or read them through the Apify API.

Each name is resolved to the best-matching advertiser account. Microsoft's own search also returns unrelated names that merely contain your text ("nike" inside "Kli**nike**n"); the Actor ignores those and logs which advertiser it picked. Raise **Advertisers per name** to include sister accounts (for example several `Booking.com B.V.` accounts).

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `advertiserNames` | array | `["Nike"]` (prefill) | Brand or company names; IDs and advertiser URLs also work |
| `maxAdvertisersPerName` | integer | `1` | Matching advertiser accounts to scrape per name |
| `advertiserIds` | array | – | Numeric IDs (`4295000966`) or `https://adlibrary.ads.microsoft.com/advertiser/...` URLs |
| `countries` | array | all EU/EEA | Names, ISO codes or Microsoft codes; with no advertiser, lists all advertisers' ads there |
| `dateFrom`, `dateTo` | string | – | `YYYY-MM-DD` or relative (`30 days`, `3 months`) |
| `maxAdsPerQuery` | integer | `100` | Max ads per advertiser (up to 10,000) |
| `includeAdDetails` | boolean | `false` | Dates, impressions, country shares, targeting, paid-for-by |
| `keywords` | array | – | Experimental keyword search in ad copy (see FAQ) |
| `proxyConfiguration` | object | off | Apify Proxy, only if you see repeated rate limits |

```json
{
  "advertiserNames": ["Nike", "Booking"],
  "countries": ["Germany", "FR"],
  "dateFrom": "3 months",
  "maxAdsPerQuery": 200,
  "includeAdDetails": true
}
```

### Output

One dataset item per ad (duplicates removed by `adId`):

```json
{
  "adId": "79852171128411",
  "advertiserId": "4294969411",
  "advertiserName": "Booking.com B.V.",
  "advertiserCountry": "Netherlands",
  "advertiserVerified": true,
  "title": "Mercato Centrale Florence - Mejor Precio Garantizado",
  "description": "Booking.com Web Oficial – Hotel. Reserva Fácil, Rápida, Segura y Con Confirmación Inmediata.",
  "displayUrl": "www.booking.com",
  "destinationUrl": "https://www.booking.com/hotel/it/piazza-del-mercato-centrale.es.html?aid=2276447",
  "landingDomain": "booking.com",
  "imageUrls": [],
  "detailsIncluded": true,
  "paidForBy": null,
  "firstShown": "2024-02-27",
  "lastShown": "2026-08-03",
  "daysShown": 889,
  "impressionsRange": "100 - 250",
  "impressionsMin": 100,
  "impressionsMax": 250,
  "impressionsByCountry": [
    { "country": "Spain", "countryCode": "ES", "impressionSharePercent": 97.8 },
    { "country": "Italy", "countryCode": "IT", "impressionSharePercent": 2.2 }
  ],
  "targetingTypes": ["Location", "MicrosoftAudiences"],
  "targetingExcludedTypes": ["Location"],
  "restrictionReason": null,
  "libraryUrl": "https://adlibrary.ads.microsoft.com/ad/79852171128411",
  "advertiserLibraryUrl": "https://adlibrary.ads.microsoft.com/advertiser/4294969411",
  "searchType": "advertiserName",
  "searchQuery": "Booking",
  "scrapedAt": "2026-10-15T03:07:09+00:00"
}
```

A `SUMMARY` record in the run's key-value store lists which advertiser each name matched, how many ads Microsoft reports per query, and the events charged.

### Data fields

| Field | Description |
|---|---|
| `adId`, `libraryUrl` | Microsoft ad ID and its public Ad Library page |
| `advertiserId`, `advertiserName`, `advertiserLibraryUrl` | Advertiser account or verified legal entity |
| `advertiserCountry`, `advertiserVerified` | Registration country and verification status (filled for advertisers you search by name or ID) |
| `title`, `description`, `displayUrl` | Ad copy as shown on Bing (for dynamic ads, a recent representative version) |
| `destinationUrl`, `landingDomain` | Landing page and its domain |
| `imageUrls`, `assets` | Images attached to the ad (shopping and multimedia ads) |
| `firstShown`, `lastShown`, `daysShown` | First/last recorded EEA impression (details only) |
| `impressionsRange`, `impressionsMin`, `impressionsMax` | Total EEA impressions bucket, e.g. `250K - 500K`, plus numbers (details only) |
| `impressionsByCountry` | Impression share per EU/EEA country (details only) |
| `targetingTypes`, `targetingExcludedTypes` | Targeting used: Location, Age, Gender, MicrosoftAudiences, AdvertiserAudiences (details only) |
| `paidForBy`, `restrictionReason` | Payer if different from the advertiser; why an ad was restricted (details only) |
| `searchType`, `searchQuery` | Which of your inputs produced the ad |

### Pricing

Pay per event, no subscription. You pay only for ads saved to the dataset:

| Event | Price | When |
|---|---|---|
| `ad` | **$1.50 per 1,000 ads** ($0.0015 each) | Each ad saved without details |
| `ad-details` | **$2.00 per 1,000 ads** ($0.002 each) | Each ad saved with details (charged instead of `ad`) |

Examples: one competitor's 100 newest ads ≈ **$0.15**; 1,000 ads with full details ≈ **$2.00**. Unknown advertisers, empty searches, failed requests and the experimental keyword search are never charged. Ads whose details Microsoft refuses to return are still saved and charged at the `ad` price. Set a maximum charge per run and the Actor stops exactly there.

### Tips

- Use the **legal or account name** shown on adlibrary.ads.microsoft.com when a brand name is ambiguous, or paste the advertiser ID.
- Microsoft returns at most **1,000 ads for one query** and its pages overlap. The Actor removes duplicates and, when you ask for more than one query can give, splits the query by country and date range automatically.
- Listing ads is quick (about 1,000 ads in 5-8 minutes). **Details need one rate-limited request per ad** (roughly 5 s each), so 100 ads with details take about 8-10 minutes.
- Schedule a weekly run with `dateFrom: "7 days"` to track only recent ads.
- For a few very large advertisers (for example Booking.com) Microsoft's API never answers when **countries and dates are combined**. The Actor detects this, skips that advertiser without charging and tells you; run it again with only countries or only a date range.
- Leave the proxy off. The Actor already spaces requests and backs off on HTTP 429.

### FAQ

**Is this an official Microsoft product?** No. This is an unofficial tool, not affiliated with or endorsed by Microsoft. It uses Microsoft's publicly documented, unauthenticated [Ad Library API](https://learn.microsoft.com/en-us/advertising/guides/ad-library-api) and returns only what Microsoft publishes for transparency.

**Which ads are included?** Ads shown on Bing in the EU/EEA, recorded since June 2023. Ads shown only outside Europe (for example US-only campaigns) are not in the Library.

**Can I search by keyword in ad copy?** Not right now. Microsoft's keyword search endpoint currently fails on their server (HTTP 500 or timeout). The Actor tries it once, logs a warning, skips keywords and charges nothing for them. It will work automatically once Microsoft fixes it. Until then, search by advertiser name, ID or country.

**Do I get spend or clicks?** No. Microsoft publishes impressions ranges and country shares, not spend or clicks.

**Is it legal?** The data is published by Microsoft for anyone to view without login under the EU Digital Services Act. You are responsible for how you use it. Advertiser names are the business identities Microsoft discloses; no other personal data is collected.

**Something broken or missing?** Open an issue in the **Issues** tab with your input and we will fix it quickly.

# Actor input Schema

## `advertiserNames` (type: `array`):

Brand or company names, like the advertiser search on adlibrary.ads.microsoft.com (`Nike`, `Zalando`, `Booking.com`). Each name is resolved to the best-matching advertiser account(s); the log and the `SUMMARY` record show exactly which advertiser was matched. Microsoft's search also returns unrelated names that merely contain the text ("nike" inside "Kliniken") - those are ignored. You can also paste advertiser IDs or advertiser page URLs here.

## `maxAdvertisersPerName` (type: `integer`):

How many matching advertiser accounts to scrape for each advertiser name, best match first. Big brands often have several accounts (for example a regional "Nike - EMEA" account plus local ones); raise this to include them.

## `advertiserIds` (type: `array`):

Microsoft advertiser IDs (digits, e.g. `4295000966`) or advertiser page URLs such as `https://adlibrary.ads.microsoft.com/advertiser/4295000966`. Use these when a name is ambiguous.

## `countries` (type: `array`):

Only ads shown in these countries. Country names (`Germany`), ISO codes (`DE`, `FR`, `NL`) or Microsoft's numeric codes (`72`). The library covers the 27 EU countries plus Iceland, Liechtenstein and Norway; other countries are skipped with a warning. Empty = all EU/EEA countries. With only countries (no advertiser), the Actor lists ads from all advertisers shown there.

## `dateFrom` (type: `string`):

Only ads shown on or after this date: `YYYY-MM-DD`, or a relative value such as `30 days` or `3 months` (that long before the run). The library starts in June 2023.

## `dateTo` (type: `string`):

Only ads shown on or before this date: `YYYY-MM-DD` or a relative value such as `7 days`. Microsoft updates the library with a 1-3 day delay.

## `maxAdsPerQuery` (type: `integer`):

Maximum number of ads to save for each advertiser (or keyword / country query). Microsoft returns at most 1,000 ads for one query; above that the Actor automatically splits the query by country and date range and merges the deduplicated results, which takes longer.

## `includeAdDetails` (type: `boolean`):

Fetch each ad's detail record: first and last shown date, total impressions range (with numeric min/max), impression share by country, targeting types used, who paid for the ad and any restriction reason. One extra request per ad (about 2 s each, Microsoft rate-limits detail calls), charged as `ad-details` instead of `ad`. Ads whose details cannot be fetched are still saved and charged as `ad`.

## `keywords` (type: `array`):

Search ad text across all advertisers. Experimental: Microsoft's keyword search currently fails on their side (HTTP 500), so the Actor tries it once, logs a warning and skips keywords without charging. It will start working automatically when Microsoft fixes it.

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

Not needed for normal use: Microsoft's API is public and the Actor already paces requests (1-2 s apart, automatic back-off on rate limits). Enable Apify Proxy only if you keep seeing "rate-limited" messages; the Actor then switches IP after repeated 429 responses.

## Actor input object example

```json
{
  "advertiserNames": [
    "Nike"
  ],
  "maxAdvertisersPerName": 1,
  "maxAdsPerQuery": 30,
  "includeAdDetails": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "advertiserNames": [
        "Nike"
    ],
    "maxAdsPerQuery": 30,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kyungminlee/microsoft-ads-library-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 = {
    "advertiserNames": ["Nike"],
    "maxAdsPerQuery": 30,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("kyungminlee/microsoft-ads-library-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 '{
  "advertiserNames": [
    "Nike"
  ],
  "maxAdsPerQuery": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call kyungminlee/microsoft-ads-library-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kyungminlee/microsoft-ads-library-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/dGUF533UZCpgG3G2E/builds/dYtZ0CXXGbqDRubEk/openapi.json
