Apple Ad Repository Scraper
Pricing
Pay per event
Apple Ad Repository Scraper
Query Apple's official EU DSA Ad Repository API for every App Store ad Apple served an app or developer, per country — creative assets, targeting flags, impression dates. Give an app/developer name or known App Store id. No login, no API key.
Pricing
Pay per event
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 hours ago
Last modified
Categories
Share
🎯 What this scrapes
Under the EU Digital Services Act (Article 39), Apple is legally required to publish every App Store ad it delivered to EU users in a public Ad Repository. This Actor turns that repository into a queryable dataset: give it an app or developer name (or a known App Store id if you already have one) and it resolves the entity, then pulls every ad Apple served for it — per EU country, with the creative assets, targeting flags, and impression dates attached — instead of you hand-paging Apple's own web UI one app at a time.
Batch multiple apps or developers in a single run. Each target is fault-isolated — one app with zero ads or a temporary hiccup never sinks the others.
🔥 What we handle for you
- 🛡️ Browser fingerprint rotation —
curl-cffiimpersonates real Chrome / Firefox TLS handshakes on every request. - 🔁 Retries with exponential backoff on
408 / 429 / 503— up to 5 attempts per page,Retry-Afterhonoured. - 🔎 Two-stage resolution — hand us a name and we resolve it to the right App Store entity ourselves, or skip straight to an ad-list query if you already know the id.
- 📄 Real pagination past Apple's 50-item page size, up to the cap you set.
- 🧊 Clean, typed dataset rows — Pydantic-validated, ISO-8601 timestamps, stable ids, JSON / CSV / Excel export straight from the Apify Console.
- 💰 Pay-Per-Event pricing — you only pay for ad rows that hit your dataset. No data, no charge.
💡 Use cases
- ASO agencies tracking which App Store ad creatives a client or rival is currently running in the EU.
- Competitive intel — see exactly what formats, copy, and targeting a rival app is using, per country.
- Ad-tech and policy research using Apple's own DSA transparency disclosures as a structured dataset.
- Periodic monitoring — schedule a run and diff successive pulls to catch new creative launches.
⚙️ How to use it
- Click Try for free at the top of the page.
- Enter one or more app/developer names in
entityNames, or known App Store ids inentities— at least one of the two is required. - Optionally narrow
countryOrRegionsanddatePreset, or leave the defaults. - Click Start. Output streams into the run's dataset as each target resolves.
- Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.
📥 Input
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
entityNames | array | no* | [] | App/developer names, resolved via Apple's own entity search. |
entities | array | no* | [] | Known {id, type} pairs — skips name resolution. |
countryOrRegions | array | no | [] | ISO alpha-2 EU codes. Empty = every EU country Apple's own country endpoint returns, fetched live. |
datePreset | string | no | "LAST_90_DAYS" | LAST_90_DAYS / LAST_180_DAYS / LAST_YEAR. |
maxItemsPerQuery | integer | no | 500 | Cap on ad rows collected per resolved target. |
proxyConfiguration | object | no | {"useApifyProxy": false} | Apify Proxy routing — off by default, see Limitations. |
* At least one of entityNames / entities must be populated — validated before any charge fires.
Example input
{"entityNames": ["Duolingo"],"entities": [{"id": 570060128, "type": "APP"}],"countryOrRegions": ["DE", "FR", "IT", "ES", "NL"],"datePreset": "LAST_YEAR","maxItemsPerQuery": 120}
📤 Output
Every row is one ad, in one country — the API itself scopes each record to
a single countryOrRegion, so no extra fan-out is needed on our end.
| Field | Type | Notes |
|---|---|---|
adId | string | Apple's stable ad identifier. |
appId / appName | integer / string | App Store id and name shown in the ad. |
developerId / developerName / legalName | integer / string / string | Advertiser identity, including the DSA-disclosed legal entity name. |
placement / format / subFormat | string | Where and how the ad ran, e.g. APPSTORE_SEARCH_RESULTS / "Icon + Asset Ad". |
countryOrRegion | string | EU country this row's impressions were served in. |
firstImpressionDate / lastImpressionDate | string | Date range Apple recorded impressions for this ad, in this country. |
adBannerSubtitle / adBannerPrimaryCategory / adBannerShortDescription / adBannerPromotionalText | string | Ad banner creative text fields. |
adBannerInAppPurchases / adBannerEditorialBadge | boolean | Ad banner disclosure flags. |
adAssetPictureUrls / adAssetVideoUrls / appIconVariations | array | Creative asset URLs — empty list when none, never null. |
audienceAgeTarget / audienceGenderTarget / audienceLocationTarget / audienceCustomerTypeTarget | boolean | Which audience-targeting dimensions this ad used. |
dataEndDate | string | Apple's own data-freshness cutoff for this query — see Limitations. |
searchedEntityId / searchedEntityType / searchedEntityName | integer / string / string | The resolved target this row came from. |
scrapedAt | string | ISO-8601 UTC timestamp when the row was scraped. |
Example output
{"adId": "a1b2c3","appId": 570060128,"appName": "Duolingo: Language Lessons","developerName": "Duolingo","placement": "APPSTORE_SEARCH_RESULTS","format": "Icon + Asset Ad","countryOrRegion": "DE","firstImpressionDate": "2026-06-01","lastImpressionDate": "2026-08-30","adBannerSubtitle": "Lerne kostenlos","adBannerPrimaryCategory": "Education","adBannerInAppPurchases": true,"adAssetPictureUrls": ["https://is5-ssl.mzstatic.com/.../asset1.png"],"audienceLocationTarget": true,"dataEndDate": "2026-09-14","searchedEntityId": 570060128,"searchedEntityType": "APP","searchedEntityName": "Duolingo","scrapedAt": "2026-09-21T00:00:00Z"}
💰 Pricing
Pay-Per-Event — you pay only when these events fire:
| Event | USD | What it is |
|---|---|---|
actor-start | $0.20 | One-off warm-up charge per run |
ad-result | $0.006 | Charged once per ad row (one ad in one country) written to the dataset |
Example: 1 000 ad rows costs $0.20 start + 1 000 × $0.006 = $6.20 total. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.
🚧 Limitations
- EU-only by design, not by weakness. The Ad Repository exists because the EU's Digital Services Act mandates it — it covers App Store ads shown to EU users only. That's precision, not a gap: it's the exact scope Apple's legal disclosure obligation covers.
- Apple's own data lags ~7 days. Every row carries
dataEndDate, the cutoff Apple itself publishes for that query — so you always know exactly how fresh the data is instead of guessing. This is Apple's documented freshness window, not something we can shrink. - Two endpoints are deliberately out of scope for v1: per-ad locale/icon variations and Apple's advertising-restrictions endpoint. Both are real, sellable datasets in their own right — documented as follow-ups, not silently dropped.
- No proxy is used by default (
proxyConfiguration.useApifyProxy: false) — live wire probes found zero anti-bot surface on this API. You can opt into a named Apify Proxy group yourself if that ever changes.
❓ FAQ
Is this legal?
Yes — the Ad Repository is Apple's own public disclosure, published because EU law requires it. We only fetch what Apple already makes publicly queryable.
Why do I need both entityNames and entities?
You don't — either alone works. entityNames is the convenient path (we
resolve the name to Apple's id for you); entities skips that lookup if
you already know the numeric App Store id and entity type.
Why is dataEndDate a few days behind today?
That's Apple's own freshness cutoff for the Ad Repository, not a delay we introduce — we surface it on every row so you always know exactly how current your pull is.
How do I export to Sheets?
After the run, click Storage → Dataset → Export and pick CSV. Google Sheets imports it directly.
💬 Your feedback
Spotted a bug, hit a weird edge case, or need a new field? Open an issue on the Actor's Issues tab on Apify Console — we ship fixes weekly and we read every report.