# Bing Ads Library Scraper - Microsoft Ads Monitor (EU) (`ivan-petrus-g/microsoft-ads-library-monitor`) Actor

Track competitors' Bing ads from Microsoft's official Ad Library (EU/EEA). Search by advertiser or ad text, filter by country and date, get ONLY NEW ads since the last run, with impressions by country, targeting, paid-for-by and run dates.

- **URL**: https://apify.com/ivan-petrus-g/microsoft-ads-library-monitor.md
- **Developed by:** [Ivan Petrus](https://apify.com/ivan-petrus-g) (community)
- **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

## Bing Ads Library Scraper: Microsoft Ads Monitor for the EU

**Bing ads scraper built on Microsoft's official, public Ad Library API.** Enter competitor **advertiser names**, **advertiser IDs** or **words from the ad copy**. You get every Bing ad Microsoft has recorded for them in the **EU/EEA**: title, description, display and landing URL, plus (with details) **first/last shown dates, total impressions range, impression share by country, targeting types and "paid for by"**. With **"Only new ads"** on, every scheduled run returns **only ads that appeared since the last run**, so the dataset becomes a competitor-ads alert feed.

No login, no cookies, no browser: the actor reads Microsoft's documented public API, with retries, HTTP 429 handling and proxy rotation. **Failed searches are never charged.**

### Sample output

One ad row from a real Apify cloud run (Oct 2026, advertiser "Booking.com B.V.", details on), shortened:

```json
{
  "type": "ad",
  "advertiserName": "Booking.com B.V.",
  "adId": "79852171128411",
  "title": "Mercato Centrale Florence - Mejor Precio Garantizado",
  "description": "Booking.com Web Oficial – Hotel. Reserva Fácil, Rápida, Segura y Con Confirmación Inmediata.",
  "destinationDomain": "booking.com",
  "startDate": "2024-02-27",
  "endDate": "2026-08-03",
  "totalImpressionsRange": "100 - 250",
  "impressionsByCountry": [{"countryCode": "ES", "impressionShare": 97.8}, {"countryCode": "IT", "impressionShare": 2.2}],
  "targetingTypes": ["Location", "MicrosoftAudiences"],
  "isNew": true
}
```

### What you get

| Data | Details |
|---|---|
| 🆕 New-ads diff | Remembers seen ads (named key-value store) and outputs only new ones on later runs. Each row has `isNew`. |
| ✍️ Ad copy | `title`, `description`, `displayUrl`, `destinationUrl` (with UTM/tracking parameters, which often reveal campaign names), `destinationDomain` |
| 🏢 Advertiser | `advertiserName`, `advertiserId`, `paidForBy` (when someone else paid, e.g. an agency) |
| 📅 Run dates | `startDate`, `endDate`, `daysRunning` (first/last impression recorded in the EU/EEA) |
| 📊 Reach | `totalImpressionsRange` ("10K - 25K"), numeric `impressionsMin`/`impressionsMax`, `impressionsByCountry` (% share per EU/EEA country), `topCountry` |
| 🎯 Targeting | `targetingTypes` (Location, Age, Gender, MicrosoftAudiences, AdvertiserAudiences) and `alsoUsedForExclusion` |
| 📋 Summary row (free) | Per advertiser / search term: ads in the library, ads fetched, **new ads since last run**, top advertisers, top countries |

Filters: **countries** (EU/EEA 2-letter codes), **date range** (`lastDays`, or `dateFrom`/`dateTo`), max ads per target. Advertiser names are resolved automatically (one brand often has several Microsoft Advertising accounts; `best` checks all accounts with the exact name).

### Use cases

- **Daily competitor alerts for Bing / Microsoft Advertising:** schedule it every morning and get only the new ads by email, Slack, Google Sheets or webhook.
- **PPC research in Europe:** see which headlines, offers and landing pages competitors run on Bing, how long they keep them, and in which countries they get impressions.
- **Agencies:** monitor many advertisers in one run; the `paidForBy` field shows which agency pays for an account.
- **Keyword / message research:** search ad text ("car insurance", "crm software") to see who advertises on a theme.
- **Compliance and brand protection:** spot advertisers using your brand name in their ad copy.

### Input examples

**Daily monitor (new ads only):**

```json
{ "advertiserNames": ["Booking.com B.V."], "onlyNewAds": true, "maxAdsPerTarget": 100 }
```

**Who advertises "car insurance" in Germany, last 30 days:**

```json
{ "searchTerms": ["car insurance"], "countries": ["DE"], "lastDays": 30, "onlyNewAds": false }
```

**Exact account, fast copy-only export (no details):**

```json
{ "advertiserIds": ["4294969411"], "includeDetails": false, "maxAdsPerTarget": 500, "onlyNewAds": false }
```

**Start monitoring silently (record current ads, output nothing on the first run):**

```json
{ "advertiserNames": ["Zalando SE"], "advertiserNameMatch": "allSimilar", "firstRunBehavior": "baselineOnly", "stateStoreName": "zalando-bing" }
```

### Output example

```json
{
  "type": "ad",
  "target": "Booking.com B.V. (4294969411)",
  "adId": "79852171128411",
  "advertiserName": "Booking.com B.V.",
  "advertiserId": "4294969411",
  "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",
  "destinationDomain": "booking.com",
  "isNew": true,
  "paidForBy": null,
  "startDate": "2024-02-27",
  "endDate": "2026-08-03",
  "daysRunning": 889,
  "totalImpressionsRange": "100 - 250",
  "impressionsByCountry": [ { "country": "Spain", "countryCode": "ES", "impressionShare": 97.8 }, { "country": "Italy", "countryCode": "IT", "impressionShare": 2.2 } ],
  "topCountry": "ES",
  "targetingTypes": ["Location", "MicrosoftAudiences"],
  "alsoUsedForExclusion": ["Location"]
}
```

**Summary row (free):** `{ "type": "summary", "target": "Booking.com B.V. (4294969411)", "totalAdsInLibrary": "1000+", "adsFetched": 50, "newAdsSinceLastRun": 3, "topCountriesInOutput": { "DE": 6, "ES": 6 } }`

Failed searches appear as `{ "type": "error", "status": "failed", "error": "...", "hint": "..." }` and are **not charged**.

### Pricing (pay per event)

- **$1.50 per 1,000 ads** ($0.0015 per ad row), **details included**. With "Only new ads" on, you pay only for new ads.
- **$0.002 per run** start fee. No proxy or compute costs on top. Summary and error rows are free.
- Example: 10 competitors checked daily with ~5 new ads each costs about **$0.08 per day**.

Set **Max ads per target** or a maximum cost per run to cap spending. If the run stops at your limit, undelivered new ads are **not** marked as seen, so they arrive next time.

### Limits you should know (from Microsoft's API)

- **EU/EEA only.** Microsoft publishes this library for the EU Digital Services Act, so it contains ads that got impressions in the EU/EEA (from advertisers anywhere in the world). Ads shown only in the US or UK are not in it.
- **About 1,000 ads per query.** The API returns at most ~1,000 results per search (`totalAdsInLibrary` shows "1000+"). For very big advertisers, narrow with `countries` or a date range.
- **1–3 day delay.** New impressions appear in the library with a delay, so a "new" ad may have started a day or two earlier.
- **Ordering is not chronological** and paging can overlap; the actor removes duplicates, but for huge advertisers a single run may not see every ad. Running daily with a date window (`lastDays: 7`) gives the best coverage.
- **Country filters are slow** on Microsoft's side (sometimes 20–90 s per page). The actor waits longer and retries automatically.
- **Rate limits.** Unauthenticated calls are limited per IP. The actor paces requests and rotates Apify Proxy sessions on HTTP 429.

### Daily alerts to Slack or email

1. Fill in the input and click **Save as a new task** (one task per client or competitor set is a good pattern).
2. In **Schedules**, create a schedule (for example every day at 08:00 in your time zone) and add the task.
3. In the task's **Integrations** tab, add the **Slack** or **Gmail** integration to get a message when a run finishes,
   or a **webhook** on "Run succeeded" that passes the run to Zapier, Make, n8n or your own endpoint. Those tools can read the rows from
   `https://api.apify.com/v2/datasets/{defaultDatasetId}/items` and format them however you like.

Because monitor mode outputs **only the ads that appeared since the previous run**, every scheduled run's dataset *is* your alert list. An empty dataset (apart from free summary rows) means nothing changed.
Turn on Apify's run-failure notifications too, so you hear about a failed run instead of silence.

### Related actors

Part of a small **competitor-intelligence suite** by the same developer. Same conventions everywhere: pay per event, failed items are never charged, and the monitors return only what changed since the last run.

- [Google Trends Scraper & API](https://apify.com/ivan-petrus-g/google-trends-api): interest over time, by region/city, top queries and Trending now for any country.
- [Google Ads Transparency Scraper & New Ads Monitor](https://apify.com/ivan-petrus-g/google-ads-transparency-monitor): competitors' Google Search, Display and YouTube ads, with only-new-ads alerts.
- [LinkedIn Ad Library Scraper & New Ads Monitor](https://apify.com/ivan-petrus-g/linkedin-ad-library-monitor): competitors' LinkedIn ads without login, incl. EU impressions and targeting.
- [ATS Jobs Scraper & Hiring Monitor](https://apify.com/ivan-petrus-g/company-hiring-monitor): new and closed jobs from Greenhouse, Lever, Ashby, Workday and 6 more job boards, by company domain.
- [App Store & Google Play Scraper](https://apify.com/ivan-petrus-g/app-store-monitor): ratings, installs, versions, chart and keyword ranks of iOS and Android apps, with change rows.

### FAQ

**What is the Microsoft Ad Library?** Microsoft's public repository of ads served on Bing (search, shopping and other Microsoft Advertising placements) in the EU/EEA, with the advertiser, payer, dates, reach and targeting. This actor returns the same data as the website [adlibrary.ads.microsoft.com](https://adlibrary.ads.microsoft.com/) as JSON, CSV or Excel.

**Do I need a Microsoft account or API key?** No. The public API works without sign-up.

**Does it show spend or clicks?** No. Microsoft publishes impression ranges and country shares, not spend or clicks.

**How do I find an advertiser ID?** Just enter the advertiser name; resolved IDs are shown in the log and in the `target` field. Re-use them as `advertiserIds` for exact monitoring.

**Can I get alerts?** Yes. Schedule the actor and connect the dataset to email, Slack, Google Sheets, Zapier, Make or n8n. With "Only new ads", each run's dataset is your list of new ads.

**Is it legal?** It reads Microsoft's official public transparency API. You are responsible for how you use the data and for complying with applicable law.

*Keywords: microsoft ads library scraper, bing ads library api, bing ads scraper, microsoft advertising competitor ads, bing ad spy, EU ad repository, DSA ad library, competitor ads monitor, new ads alert, ppc competitor research.*

# Actor input Schema

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

Advertiser (account or verified legal) names, e.g. 'Booking.com B.V.'. Resolved to advertiser IDs automatically: exact matches first, otherwise the top suggestion.

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

Numeric Microsoft Ad Library advertiser or account IDs (e.g. 4294969411). The most precise option.

## `searchTerms` (type: `array`):

Find ads whose copy contains these words (e.g. 'car insurance', 'crm software'). Each term is one search.

## `advertiserNameMatch` (type: `string`):

best = all accounts with exactly this name (or the top suggestion). allSimilar = up to 5 advertisers whose name contains the text.

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

Only ads served in these countries (2-letter codes: DE, FR, NL, PL, ES, IT, SE...). Empty = all EU/EEA. The library only covers the EU/EEA. Note: Microsoft's API answers country-filtered queries slowly (20-90 s per page).

## `lastDays` (type: `integer`):

Only ads that ran within the last N days. Overrides dateFrom/dateTo. Microsoft updates the library with a 1-3 day delay.

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

YYYY-MM-DD. Ads that ran on or after this date.

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

YYYY-MM-DD. Defaults to today when dateFrom is set.

## `includeDetails` (type: `boolean`):

One extra API call per ad: first/last shown dates, total impressions range, impression share by country, targeting types used (and excluded), paid-for-by.

## `maxAdsPerTarget` (type: `integer`):

0 = as many as the API allows (about 1,000 per query). Tip: use a date range or countries to narrow big advertisers.

## `onlyNewAds` (type: `boolean`):

Remember which ads were already seen (in a named key-value store) and output only new ones. Perfect for scheduled runs.

## `firstRunBehavior` (type: `string`):

outputAll = the first run returns all current ads (up to the limit). baselineOnly = the first run only records current ads; later runs return what's new (cheaper).

## `stateStoreName` (type: `string`):

Named key-value store that keeps seen ad IDs. Use different names for independent monitors.

## `includeSummary` (type: `boolean`):

Adds one free summary row per advertiser / search term: ads in the library, ads fetched, new ads, top advertisers and countries.

## `maxConcurrency` (type: `integer`):

Targets processed in parallel (each with its own proxy session).

## `requestDelaySecs` (type: `number`):

Pause between two API calls of one worker. Microsoft rate-limits unauthenticated calls.

## `maxRetries` (type: `integer`):

Retries with backoff and proxy rotation on 429/5xx/timeouts.

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

Apify Proxy (datacenter) spreads requests over several IPs, which avoids Microsoft's per-IP rate limits.

## Actor input object example

```json
{
  "advertiserNames": [
    "Hubspot, Inc."
  ],
  "advertiserNameMatch": "best",
  "includeDetails": true,
  "maxAdsPerTarget": 10,
  "onlyNewAds": true,
  "firstRunBehavior": "outputAll",
  "stateStoreName": "microsoft-ads-monitor-state",
  "includeSummary": true,
  "maxConcurrency": 2,
  "requestDelaySecs": 1,
  "maxRetries": 6,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `ads` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `runSummary` (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": [
        "Hubspot, Inc."
    ],
    "maxAdsPerTarget": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ivan-petrus-g/microsoft-ads-library-monitor").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": ["Hubspot, Inc."],
    "maxAdsPerTarget": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("ivan-petrus-g/microsoft-ads-library-monitor").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": [
    "Hubspot, Inc."
  ],
  "maxAdsPerTarget": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call ivan-petrus-g/microsoft-ads-library-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ivan-petrus-g/microsoft-ads-library-monitor"
        }
    }
}
```

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/VcuF3Oi6wrFMV65cx/builds/RGZHehxyV03stzlsl/openapi.json
