Apple Ad Repository Scraper
Pricing
from $5.28 / 1,000 ad results
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
from $5.28 / 1,000 ad results
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
4 days ago
Last modified
Categories
Security
Limited permissionsShare
🎯 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.