# X Ads Transparency Scraper: Twitter Ads Library (`northloop-labs/x-ads-transparency-scraper`) Actor

Scrape the X (Twitter) Ads Repository for ads served in Europe: advertiser handle, creative text (via oEmbed), targeting, impressions, reach, funding and dates. Optional only-new monitor for competitor tracking. No X login.

- **URL**: https://apify.com/northloop-labs/x-ads-transparency-scraper.md
- **Developed by:** [Northloop Labs](https://apify.com/northloop-labs) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.06 / 1,000 ad saveds

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

## X Ads Transparency Scraper: Twitter Ads Library

Scrape the public [X Ads Repository](https://ads.x.com/ads-repository) (Twitter ads transparency for Europe) by **advertiser handle**. For every ad you get the **tweet URL**, **creative text** (via public oEmbed), **country**, **targeting**, **impressions**, **reach**, **funding type/currency**, **account name** and **approval status**.

**Track new competitor ads:** turn on *Only new ads*, schedule the Actor, and each run saves only ads that were not seen before (state lives in a key-value store in **your** Apify account).

No X login and no developer app. Complements our [Google Ads](https://apify.com/northloop-labs/google-ads-transparency-library) and [Meta Ads](https://apify.com/northloop-labs/meta-ads-library-scraper) scrapers.

> **Coverage note:** X's repository is built for EU Digital Services Act transparency. It lists ads **served in European markets**. Empty results usually mean the advertiser had no EU-served ads in that date range — not that the tool is broken.

### What you can use it for

- **Competitor research:** see which creatives and markets rivals are running on X in Europe.
- **Compliance / transparency datasets:** impressions, reach, funding and targeting as X discloses them.
- **Brand monitoring:** schedule daily runs and get only new ads for watched handles.
- **Cross-platform ad intel:** pair with Meta and Google Ads scrapers for the same brand.

### How to scrape X Ads Repository ads

| Field | Description |
|---|---|
| `advertisers` | Handles, `@handles` or `https://x.com/...` URLs (up to 50) |
| `marketPreset` | `eu27`, `dach`, `nordics`, `uk_ie`, `benelux`, `southern`, `eea` or `custom` |
| `countries` | Two-letter codes when preset is `custom` |
| `startDate` / `endDate` | Inclusive delivery window (`YYYY-MM-DD`) |
| `maxResults` | Hard cap on ads saved (and charged) |
| `onlyNew` | Skip ads already in the monitor store |
| `monitorStoreName` | KV store name (default `x-ads-monitor`) |
| `enrichCreatives` | Resolve tweet text via oEmbed (default on, free) |
| `searchTerms` | Optional keyword filter on creative / targeting |
| `minImpressions` / `minReach` | Drop small campaigns |
| `useProxy` | Off by default; enable only if you hit blocks |

#### Input example

```json
{
  "advertisers": ["Apple", "SamsungMobile"],
  "marketPreset": "dach",
  "startDate": "2026-01-01",
  "maxResults": 50,
  "enrichCreatives": true
}
```

Only-new watch:

```json
{
  "advertisers": ["Nike"],
  "marketPreset": "eu27",
  "startDate": "2026-01-01",
  "onlyNew": true,
  "maxResults": 200
}
```

#### Output example

```json
{
  "adKey": "2012134234748760425|54125326|DE|4503599691193047",
  "tweetId": "2012134234748760425",
  "tweetUrl": "https://x.com/i/status/2012134234748760425",
  "advertiserHandle": "Apple",
  "advertiserName": "Apple",
  "country": "DE",
  "accountName": "APPLE EMEA MAL 2 - NEW",
  "fundingType": "NonExclusiveIo",
  "fundingCurrency": "EUR",
  "approvalStatus": "Verified",
  "creativeText": "Jetzt 3x mehr Schutz vor Kratzern mit dem Ceramic Shield 2.",
  "targetingNames": ["Europe", "AgeOver18"],
  "impressions": 18635967,
  "reach": 1383216,
  "scrapedAt": "2026-10-24T16:00:00.000Z"
}
```

X does not always keep the underlying tweet public. When oEmbed fails, metrics and targeting still save and `enrichmentStatus` explains why.

### How much does it cost?

Pay per event (platform usage included; Apify takes its usual Store cut from the prices below):

| Event | Price | When |
|---|---|---|
| Actor start | **$0.001** per GB of memory | Every run (default **256 MB** → ~$0.00025) |
| Ad saved | **$0.00008** (**$0.08 / 1,000**) | Each unique ad written. Duplicates and already-seen ads in only-new mode are free. Empty searches are free. |

**Examples:** 50 ads ≈ **$0.004**. 1,000 ads ≈ **$0.08**.

**No session fee and no OCR fee.** The repository works over a guest HTTP session. Creative text comes from X's public oEmbed — we do not OCR images.

Priced under the main Store rival (~$0.10 / 1k) while keeping a positive margin after Apify's cut.

### Reliability notes

- X sometimes returns rate limits or temporary over-capacity. The Actor retries with backoff; raise `requestDelayMs` if needed.
- Empty results for a handle + market + date range are **valid** and uncharged.
- Repository data can lag live delivery. Coverage is limited to what X discloses for European markets.

### Tips

- Start with `marketPreset: "dach"` or a few countries, then widen to `eu27`.
- Use `onlyNew` + an Apify schedule for competitor alerts.
- Keep `enrichCreatives` on for readable copy; turn it off only if you need the absolute minimum request count.

### Use with AI agents, MCP, Make, Zapier, n8n and the API

#### AI agents and the Apify MCP server

```text
https://mcp.apify.com?tools=northloop-labs/x-ads-transparency-scraper
```

#### API

```bash
curl -X POST "https://api.apify.com/v2/acts/northloop-labs~x-ads-transparency-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"advertisers": ["Apple"], "marketPreset": "dach", "startDate": "2026-01-01", "maxResults": 30}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("northloop-labs/x-ads-transparency-scraper").call(
    run_input={"advertisers": ["Apple"], "marketPreset": "dach", "startDate": "2026-01-01", "maxResults": 30}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

### Data & privacy

- The Actor reads only the **public X Ads Repository** and public oEmbed responses. It collects advertiser handles, disclosed account/funding fields, targeting labels, impressions, reach and creative text that X already publishes.
- It collects **no personal data** about people who saw or clicked ads beyond what X discloses in the repository.
- Results are written **only** to the run's default Apify dataset in your account. In only-new mode, seen ad keys are kept in a key-value store in **your** account (`monitorStoreName`), which you can delete anytime. No external storage or webhooks.

### Is it legal to scrape the X Ads Repository?

The Ads Repository is a public transparency tool required under the EU Digital Services Act. The Actor reads it the same way a browser does, at a moderate pace. Tweet creatives can be protected by copyright and trademarks — use them for research and analysis, not to republish as your own. This is not legal advice; check the rules that apply to your use.

### FAQ

#### How much does it cost?

About **$0.08 per 1,000 ads**, plus a tiny Actor-start charge at 256 MB. Empty searches cost essentially nothing beyond start.

#### Why is there no session fee?

Unlike Meta, X's Ads Repository accepts a guest HTTP session without a residential browser warm-up for typical runs.

#### Does it need an X login or API key?

No.

#### Can I get US-only ads?

X's live repository is oriented to European delivery. US-only commercial ads are generally not listed here. For historical US political archives, other tools exist; this Actor targets current EU-served ads.

#### Can I watch one brand every day?

Yes: set `advertisers`, turn on `onlyNew`, save a task and schedule it.

### How this Actor was made

This Actor was made with AI. An AI agent wrote and tested the code, this README and the store listing, and a human owns and maintains the Actor.

### More Actors from Northloop Labs

- [Meta Ads Library Scraper: Facebook & Instagram Ads](https://apify.com/northloop-labs/meta-ads-library-scraper): Meta Ads Library by keyword, Page or URL.
- [Google Ads Transparency Center Scraper](https://apify.com/northloop-labs/google-ads-transparency-library): a company's ads from the Google Ads Transparency Center.
- [Luma, Eventbrite & Meetup Events Scraper](https://apify.com/northloop-labs/tech-events-finder): tech, AI and startup events from Luma, Eventbrite and Meetup.
- [Greenhouse, Lever, Ashby & Workable Jobs Scraper](https://apify.com/northloop-labs/company-jobs-finder): open jobs from company career pages.
- [Podcast Transcriber for RSS & Apple Podcasts](https://apify.com/northloop-labs/podcast-transcriber): podcast transcripts with timestamps and SRT subtitles.
- [EU TED & UK Find a Tender Scraper](https://apify.com/northloop-labs/public-tenders-monitor): UK and EU public tenders with daily alerts.
- [Google Trends Scraper: Keywords, Regions & Related Queries](https://apify.com/northloop-labs/google-trends-scraper): bulk Google Trends with comparisons and rising-query alerts.
- [YouTube Transcript Scraper: Captions, Subtitles & Text](https://apify.com/northloop-labs/youtube-transcript-scraper): YouTube transcripts with captions or Whisper, timestamps and SRT.
- [Google Maps Leads Scraper: Emails, Phones & Socials](https://apify.com/northloop-labs/google-maps-leads-scraper): local business leads with emails, phones, socials and a lead score.
- [Home Depot Scraper: Products, Prices, Stock & Reviews](https://apify.com/northloop-labs/home-depot-scraper): Home Depot products, prices, store stock and reviews.

### Feedback

Want LinkedIn or TikTok ad libraries, richer creative media URLs, or a filter that's missing? Open an issue in the **Issues** tab.

# Actor input Schema

## `advertisers` (type: `array`):

X handles, @handles or profile URLs to look up (up to 50). Example: Apple, @Nike, https://x.com/SamsungMobile

## `marketPreset` (type: `string`):

Ready-made country groups. Choose Custom to use the Markets list below.

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

Two-letter country codes when Market preset is Custom. The repository covers EU/EEA ads; empty results outside that scope are normal.

## `startDate` (type: `string`):

Inclusive delivery start (YYYY-MM-DD). Repository coverage generally starts in 2023.

## `endDate` (type: `string`):

Inclusive delivery end (YYYY-MM-DD). Leave empty to use today.

## `maxResults` (type: `integer`):

Hard cap on ads written (and charged) in this run.

## `maxAdsPerAdvertiser` (type: `integer`):

Optional cap after X returns the result set for one handle. 0 = no extra cap.

## `onlyNew` (type: `boolean`):

Skip ads already stored under the monitor key. Use with a schedule for competitor alerts.

## `monitorStoreName` (type: `string`):

Key-value store in your account that remembers seen ad keys when Only new is on.

## `enrichCreatives` (type: `boolean`):

Resolve each unique tweet through X's public oEmbed endpoint for creative text and author. Recommended. No extra charge.

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

Keep a row only when creative, advertiser or targeting contains any of these case-insensitive terms.

## `minImpressions` (type: `integer`):

Drop ads with fewer disclosed impressions.

## `minReach` (type: `integer`):

Drop ads with less disclosed reach.

## `requestDelayMs` (type: `integer`):

Raise this if X returns rate limits or over-capacity errors.

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

Retries for timeouts, 429 and 5xx with exponential backoff.

## `useProxy` (type: `boolean`):

Off by default — the repository works with a guest session from most IPs. Turn on only if you see blocks.

## `proxyCountry` (type: `string`):

Residential exit country when Use residential proxy is on (e.g. DE, FR).

## Actor input object example

```json
{
  "advertisers": [
    "Apple"
  ],
  "marketPreset": "dach",
  "countries": [
    "DE",
    "FR"
  ],
  "startDate": "2026-01-01",
  "maxResults": 50,
  "maxAdsPerAdvertiser": 0,
  "onlyNew": false,
  "monitorStoreName": "x-ads-monitor",
  "enrichCreatives": true,
  "minImpressions": 0,
  "minReach": 0,
  "requestDelayMs": 400,
  "maxRetries": 4,
  "useProxy": false,
  "proxyCountry": "DE"
}
```

# Actor output Schema

## `overview` (type: `string`):

Advertiser, country, creative text, impressions, reach and tweet link.

## `details` (type: `string`):

Targeting, funding, account and approval fields for each ad.

## `runSummary` (type: `string`):

Counts, per-advertiser results and errors for this run.

# 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 = {
    "advertisers": [
        "Apple"
    ],
    "marketPreset": "dach",
    "countries": [
        "DE",
        "FR"
    ],
    "startDate": "2026-01-01",
    "maxResults": 50,
    "monitorStoreName": "x-ads-monitor",
    "proxyCountry": "DE"
};

// Run the Actor and wait for it to finish
const run = await client.actor("northloop-labs/x-ads-transparency-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 = {
    "advertisers": ["Apple"],
    "marketPreset": "dach",
    "countries": [
        "DE",
        "FR",
    ],
    "startDate": "2026-01-01",
    "maxResults": 50,
    "monitorStoreName": "x-ads-monitor",
    "proxyCountry": "DE",
}

# Run the Actor and wait for it to finish
run = client.actor("northloop-labs/x-ads-transparency-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 '{
  "advertisers": [
    "Apple"
  ],
  "marketPreset": "dach",
  "countries": [
    "DE",
    "FR"
  ],
  "startDate": "2026-01-01",
  "maxResults": 50,
  "monitorStoreName": "x-ads-monitor",
  "proxyCountry": "DE"
}' |
apify call northloop-labs/x-ads-transparency-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,northloop-labs/x-ads-transparency-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/YjUeAXZJLPg4gogce/builds/afofp4sMYiZaAElaD/openapi.json
