# App Store Ads Scraper: Apple Search Ads Library (`automation_craft/app-store-ads-scraper`) Actor

See which apps buy App Store ads against yours: every Apple Search Ads ad shown in the EU in the last year, by app, developer, link, file or country, with slot, days running, creative and targeting flags. Add-ons: advertiser lists with ad counts, Apple's restrictions feed, changed ad alerts.

- **URL**: https://apify.com/automation_craft/app-store-ads-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (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.25 / 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.
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

### App Store Ads Scraper: Apple Search Ads Library

**Scrape App Store ads** from Apple's public App Store Advertising Repository, the EU ad library of every ad bought through Apple Ads (called Apple Search Ads until April 2025) and shown on the App Store in 25 EU countries over the last year: search results, the Search tab, the Today tab and product pages. Give App Store links, app or developer ids, names, or whole countries, and get one row per ad with the advertised app, the developer and its legal name, the placement, the format, the first and last day shown, the targeting flags, the texts, the screenshots and the videos.

Optional add-ons, each off until you switch it on and each with its own price: Apple's restrictions feed (ads Apple removed and advertiser accounts it suspended, with reason and countries), an advertiser search (one row per app or developer with its ad count, the latest day shown and sample ads, to list who advertises), and changed ads for monitors (a known ad delivered again when Apple reports a later last day shown). You can also give your links as a file, a Google Sheet or a Drive file, and pick your own proxy.

Use it to see which apps advertise against yours, where on the App Store they buy ads, in which countries and for how long, and what creative they show. Every page Apple returns is read to the last one, and each app, developer or country gets a coverage row with Apple's own total next to the ads delivered. A name that matches no app, or several, comes back as a free row listing the candidates with their ids. Each ad is charged once per run.

### Quick start

1. Open the Actor, keep the prefilled input (the name `Temu`, Germany, 20 ads) and press Start.
2. Put your competitors into the first fields: App Store links (`https://apps.apple.com/de/app/.../id1641486558`), app or developer ids, exact names, or a file of links. With none of them, no advertiser search and no restrictions feed, the run browses every App Store ad of the countries you pick.
3. Pick countries (all 25 when empty), a period (90 days, 180 days or a year), and optional filters: placements, formats, `startDate` and `endDate`.
4. Set `maxAds` (1,000 when left out), and a `memoryName` for a scheduled run that should return only new ads.
5. Optional: an advertiser search (`advertiserSearchTerms`, for example `fitness`), the restrictions feed (`includeRestrictions`), or changed ads for a monitor (`redeliverChanged` with a `memoryName`).
6. Read the dataset: `ad` rows, `advertiser` and `restriction` rows when asked for, one `coverage` row per app, developer, country or restrictions feed, free `status` rows, and one `summary` row with every counter. The "Ads", "Advertisers", "Restrictions" and "Coverage" views show the main columns of each.

### What you get

One `ad` row per App Store ad. Apple's ad id is one ad in one country: an app that ran the same creative in three countries has three rows. Fill rates measured by this Actor on 2026-10-11 on 5,000 ads of France (2,697 apps of 2,185 developers; the first pages Apple returns, which hold the ads shown on its newest day):

| Field | What it holds | Fill |
|---|---|---|
| `adId` | Apple's ad id (32 hex characters) | 100 percent |
| `country`, `countryName` | the country the ad was shown in | 100 percent |
| `appId`, `appName`, `appStoreUrl` | the advertised app, its App Store id (as text) and its App Store page in that country | 100 percent |
| `developerId`, `developerName`, `developerUrl` | the developer the ad ran for and its App Store page | 100 percent |
| `legalName` | the seller's legal name on the App Store | 100 percent; differs from the developer name on 26.6 percent |
| `placement`, `placementName` | `APPSTORE_SEARCH_RESULTS` (96.1 percent), `APPSTORE_PRODUCT_PAGE` (1.8), `APPSTORE_SEARCH_TAB` (1.5) or `APPSTORE_TODAY_TAB` (0.6), and the plain name | 100 percent |
| `format` | `Icon Ad` or `Icon + Asset Ad` (72.1 percent carry assets) | 100 percent |
| `firstShown`, `lastShown`, `daysShown` | first and last day Apple recorded an impression (YYYY-MM-DD), and the days between, both counted; the first day can lie before the period | 100 percent |
| `targeting`, `targetingUsed` | whether the campaign used Apple's age, gender, location and customer type refinements (Apple publishes yes or no, not the values) | 100 percent; any of them on 13.4 percent (customer type 12.0, age 2.4, gender 1.0, location 0.1) |
| `language`, `languageName`, `previewDevice` | the default language of the ad and the device Apple previews it on | 100 percent |
| `iconUrl`, `category`, `description` | the app icon, its App Store category and the description Apple shows with the ad | 100 percent |
| `subtitle` | the app's subtitle | 96.8 percent |
| `promotionalText` | the promotional text, when the ad has one | 31.0 percent |
| `inAppPurchases` | true when the app offers in-app purchases | 100 percent (true on 78.7) |
| `assets`, `screenshotCount`, `videoCount`, `firstScreenshotUrl` | the screenshots and videos in their order, with width, height and orientation | at least one image on 99.8 percent; a video on 17.7 percent |
| `colors`, `editorialBadge`, `subFormat` | Apple's colour code, the editorial badge flag, and Apple's sub format | 0.3, 1.0 (true) and 0 percent |
| `variations` | with Add variations on: every language version of the ad (app name, subtitle, category, promotional text and, where Apple has them, per device screenshots) and its icon variations, with a `status` | on request |
| `foundBy` | the app, developer, name or country that found the ad, and the countries asked | 100 percent |
| `period`, `periodStart`, `periodEnd` | Apple's reporting window the ad was read in | 100 percent |

A `coverage` row per app, developer or browsed country holds `appleTotal` (Apple's own count of ads for your countries and period), `pagesRead`, `pagesFailed`, `adsDelivered`, `adsCharged`, the ads skipped as already known (`knownSkipped`), already delivered (`duplicatesSkipped`) or filtered out (`filteredOut`), `stopReason`, and `complete`: true only when every page was read to Apple's last and the distinct ads seen equal Apple's total.

#### Advertiser rows (optional)

With `advertiserSearchTerms`, every app and developer in Apple's repository whose name starts with your text gets one `advertiser` row: `advertiserType` (app or developer), `advertiserId`, `name`, `appStoreUrl`, `adsCount` (Apple's total of its ads in your countries and period), `latestShown` (the newest last day shown among its ads), `sampleAds` (up to three ads: id, country, placement, format, first and last day), `countriesAsked`, `period`. Rows with `adsCount` 0 are free and marked `charged: false`. On 2026-10-12 the search "fitness" found 35 apps and developers, and Temu's developer had 407 ads in Germany and France over 90 days.

#### Restriction rows (optional)

With `includeRestrictions`, every record of Apple's restrictions feed in your period gets one `restriction` row: `action` (`ACTION_ADVERTISING_REMOVED` or `ACTION_ACCOUNT_SUSPENDED`) and `actionName`, `actionDate`, `reason`, `basis`, `details`, `firstShown`, `placements` with the countries affected, `countries`, `targeting` flags, and a `restrictionId` (Apple gives none: a hash of the record). Apple's feed names no app, developer or ad. On 2026-10-12 it held 42 removed ads and 6 suspended accounts over 90 days, 196 and 19 over a year. A record is kept when one of its countries is among yours.

#### Changed ads (optional, for monitors)

With `redeliverChanged` and a `memoryName`, an ad the memory delivered before comes back when Apple now reports a later last day shown (the ad kept running): `changeStatus: "updated"` and `previousLastShown`, charged as an Ad update instead of an Ad. New ads carry `changeStatus: "new"`.

Free `status` rows: `name_not_found` and `name_ambiguous` (with up to 20 candidate apps and developers, their ids and App Store links), `no_ads` (an app, developer or country without ads in your scope, or none passing your filters), `lookup_failed` (Apple did not answer after its retries), `invalid` (a value that could not be used), `skipped` (inputs not started because the run stopped), `memory_free`.

### How much does it cost to scrape App Store ads?

You pay per ad delivered, at Apify's Store prices for your plan:

| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
| Ad (per 1,000 ads) | USD 1.75 | USD 1.60 | USD 1.45 | USD 1.25 |
| Ad variation set (per 1,000, only with Add variations) | USD 1.00 | USD 1.00 | USD 0.90 | USD 0.80 |
| Ad update (per 1,000, only with Deliver changed ads again) | USD 1.20 | USD 1.10 | USD 1.00 | USD 0.85 |
| Restriction (per 1,000, only with the restrictions feed) | USD 2.50 | USD 2.20 | USD 1.80 | USD 1.40 |
| Advertiser (per 1,000, only with an advertiser search) | USD 4.50 | USD 3.80 | USD 3.10 | USD 2.50 |
| Actor start (once per run) | USD 0.007 | USD 0.007 | USD 0.007 | USD 0.007 |

Platinum and Diamond plans pay the Gold price. The Actor start fee has no plan discount. The Store pricing card shows these same prices per 1,000 events: "$1.75 / 1,000" on the Ad row means one ad costs USD 0.00175.

Examples on the Free plan: every ad of one developer in one country (194 ads) costs USD 0.007 + 194 x 0.00175 = about USD 0.35; 5,000 ads of a whole country cost about USD 8.76. Ads an earlier input of the same run already delivered, ads your memory knows, rows your filters drop, names without a match, targets without ads and calls Apple did not answer are free. A variation set is charged only when Apple answered the variations call for that ad. A year of the restrictions feed (215 records) costs USD 0.007 + 215 x 0.0025 = about USD 0.55 on the Free plan; an advertiser search that delivers 35 apps and developers with ads costs USD 0.007 + 35 x 0.0045 = about USD 0.16. Advertisers without ads in your scope, restrictions outside your countries or known to your memory, and known ads that did not change are free.

### Input

| Field | What it does |
|---|---|
| `searchTerms` | App or developer names, matched through Apple's own name search, which reads names from their first letter. By default only an app or developer named exactly like your text (capitals and spaces aside) is used; otherwise a free row lists the candidates. An App Store link pasted here is read as that app or developer. |
| `apps` | App Store app links or app ids (`1641486558`, `id1641486558`). Every ad of the app in your countries and period. |
| `developers` | App Store developer links or developer ids. Every ad of every app of the developer. |
| `countries` | ISO codes (`DE`, `de`) or country names (`Germany`, `Deutschland`) of Apple's 25 countries (no Lithuania, no Malta). All 25 when empty. |
| `period` | `LAST_90_DAYS`, `LAST_180_DAYS` or `LAST_YEAR`. When left out, the shortest one that holds your dates (90 days without dates). |
| `startDate`, `endDate` | Keep ads that ran on at least one day between them: `YYYY-MM-DD`, `today`, `yesterday`, or `30 days` back. |
| `placements` | `searchResults`, `searchTab`, `todayTab`, `productPage`. All when empty. |
| `formats` | `iconAd`, `iconAssetAd`. Both when empty. |
| `nameMatch` | `exact` (when left out) or `startsWith`: every app and developer whose name begins with your words as whole words. |
| `nameTypes` | `all` (when left out), `apps` or `developers`. |
| `includeVariations` | Read each delivered ad's variations with one extra call per ad (charged as an Ad variation set when Apple answers). Apple's variations call takes 4 to 33 seconds and fails now and then; after about 35 seconds of failed calls in a run (plus 15 for every set charged) no more variations are asked, and the ads are still delivered. |
| `maxAds` | Total cap, 1,000 when left out, up to 1,000,000. |
| `maxAdsPerTarget` | Cap per app, developer or browsed country. |
| `memoryName`, `resetMemory` | Cross run memory for scheduled runs: an ad delivered once under a name is never delivered or charged again under it (unless it changed and `redeliverChanged` is on). |
| `redeliverChanged` | With a memory name: deliver a known ad again when Apple reports a later last day shown, charged as an Ad update. Off when left out. |
| `startUrlsFile` | App Store links one per line, or ONE link to a public .txt or .csv file, Google Sheet or Google Drive file holding them (up to 2,000 links and 2 MB; pasted links count toward the limits of 1,000 apps and 1,000 developers; a file with more than 2,000 links uses the first 2,000 and says so on a free row; other cells are skipped and counted). Bare ids go into `apps` or `developers`. |
| `advertiserSearchTerms`, `maxAdvertisers` | Advertiser search: one row per app or developer whose name starts with your text, with its ad count; at most `maxAdvertisers` rows with ads (100 when left out). `nameTypes` limits it to apps or developers. |
| `includeRestrictions`, `restrictionActions` | Add Apple's restrictions feed; `removed`, `suspended` or both when empty. With no app, developer, name, file or advertiser search, the run returns only the feed. |
| `proxyConfiguration` | Left out: the Apify datacenter proxy. Your own proxy URLs are used as given; no proxy uses the run's own address, one call at a time; a residential group is mapped to the datacenter group (the summary says so). |

Example through the API:

```json
{
    "apps": ["https://apps.apple.com/de/app/temu-shop-like-a-billionaire/id1641486558"],
    "developers": ["368677371"],
    "countries": ["DE", "FR", "IT"],
    "placements": ["todayTab", "searchTab"],
    "startDate": "30 days",
    "maxAds": 5000
}
```

#### How names are matched

Apple's name search returns apps and developers whose name starts with the letters you type. "Temu" returns the developer Temu, the app "Temu: Shop Like a Billionaire" and the developer "Temurbek Rakhimov". With the default `exact`, only the developer Temu is used. With `startsWith`, the developer Temu and the app are used (both begin with the word Temu), and Temurbek is not. A name that matches nothing, or several apps or developers with exactly that name, gives a free row with the candidates and their ids: put the id you mean into `apps` or `developers`.

#### Countries, pages and speed

An app or developer is read over every country in one query when no country is given, and in groups of five otherwise; a browsed country is read on its own. Apple returns 100 ads per page and the Actor reads three pages at a time through the Apify datacenter proxy. Measured on 2026-10-11: 5,000 ads of France in about 2 minutes; on 2026-10-09 one app's 3,206 ads in all countries took 40 seconds, and a read test of Apple's API from an Apify run with the same three datacenter exits walked all 175,584 ads of Germany's 90 days in 47 minutes with no page lost. The default run timeout is 2 hours: raise it for a run of more than about 200,000 ads.

#### Filters and the work allowance

Apple's API has no placement, format or date filter, so these filters are applied to every row Apple returns: every page is still read and the rows that do not pass are dropped free. Every request the run sends draws on a work allowance of 26 units (a page or a name search is 1, a variations call 3; names are searched up to three at a time) plus 0.03 for every ad charged and 10 for every variation set charged. A page that brings 34 or more new ads earns more than it costs; a name search and its first page earn their 2 units back from about 67 ads, and the base covers the rest of a list of 20 names that bring about 30 ads each (such a list is read to the end); a long list of names whose apps advertise little, or a run whose pages earn little or nothing (ads a memory already knows, a filter that keeps few rows of a whole country, names nobody has, a failing variations call) stops when it is spent, with a free row naming the inputs it did not start.

An advertiser search spends 1 unit per count call (one call per group of five countries, one for all 25 when none is given) and 1 per page of Apple's name search; each advertiser row charged earns 1.5 units, a restriction row 0.03. A search whose apps and developers mostly have no ads in your countries therefore stops at the allowance (on 2026-10-12 a search for "ma" in Luxembourg counted 31 of its first 100 names, 4 with ads), with a free row naming the apps and developers it did not count: narrow the text or widen the countries.

#### Monitoring with a memory

With a `memoryName`, a scheduled run delivers and charges only ads it has not delivered before under that name. Apple sorts its pages by the last day an ad was shown, newest first, so ads that are still running, known or new, share the first pages, and a memory run reads every page of its apps and developers again and skips the known ads free; with the work allowance a memory run reads about 26 pages of ads it already knows (about 2,600 ads) plus one more page for every 33 new ads, which suits apps and developers (a developer with 2,000 ads is 20 pages) far better than whole countries. Split a larger watch list over several memory names. With `redeliverChanged`, a known ad Apple now shows with a later last day is delivered again as an update (every ad is remembered with its last day shown); ads remembered before this option existed carry no day and are never read as changed. A named memory also remembers the restrictions it delivered, so a scheduled restrictions run returns new records only. Two runs on one memory name at the same time are not supported: the second one delivers its rows free and remembers nothing.

### What this Actor does not do

- It returns what Apple's repository publishes. Apple does not publish the keywords an ad was bought on, bids, spend, impressions, taps, installs or the values of the targeting (only whether age, gender, location and customer type targeting was used).
- It covers App Store ads only. Apple Ads also sells ads on Apple Maps and in Apple News; Apple's repository holds App Store ads, and none of 2,000 rows checked on 2026-10-11 had another placement.
- It covers the 25 EU countries of Apple's repository and the last year, with Apple's publishing delay of about 5 to 7 days. No other country and no older ad.
- Restriction rows name no app, developer or ad: Apple's restrictions feed does not carry them, so a restriction cannot be joined to an ad.
- Advertiser rows are a snapshot of each run: they are not remembered across runs, so a scheduled advertiser search returns the whole list each time.
- A changed ad is one whose last day shown moved later; Apple publishes no other change of a running ad (its creative is part of the ad id).
- A file of links is read from a public address only (no login, no private network), up to 2,000 links and 2 MB.
- Residential proxies are not used: a residential group is mapped to the datacenter group, which reads Apple's API the same way.

### API

Run it and read the ads with `curl`:

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~app-store-ads-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"developers": ["1641486560"], "countries": ["DE"], "maxAds": 100}'
```

Node.js:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation_craft/app-store-ads-scraper').call({ searchTerms: ['Temu'], countries: ['DE'], maxAds: 100 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((x) => x.type === 'ad').length);
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("automation_craft/app-store-ads-scraper").call(run_input={"apps": ["1641486558"], "maxAds": 100})
ads = [x for x in client.dataset(run["defaultDatasetId"]).iterate_items() if x["type"] == "ad"]
```

### FAQ

#### Is there a library of App Store ads?

Yes. Under the EU Digital Services Act, Apple publishes its App Store Advertising Repository (adrepository.apple.com), often called the Apple Search Ads repository: every ad Apple delivered on the App Store in 25 EU countries over the last year, searchable by app or developer. This Actor reads it as rows, every page to the end.

#### How can I see which App Store ads my competitors run?

Put each competitor's App Store link, app id, developer id or exact name into the input and pick the countries. You get every ad Apple recorded for it in the EU repository: placement, format, the days it ran, the targeting flags and the creative, one row per ad and country.

#### Does it show the keywords competitors bid on in Apple Search Ads?

No. Apple's repository does not publish keywords, bids, spend, impressions or installs, so no row carries them. It shows which app advertised, where on the App Store (search results, Search tab, Today tab, product pages), in which country, on which days, with which creative, and whether age, gender, location or customer type targeting was used.

#### Which countries does the App Store ad repository cover?

Apple's 25 countries: Austria, Belgium, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Latvia, Luxembourg, Netherlands, Poland, Portugal, Romania, Slovakia, Slovenia, Spain and Sweden (no Lithuania, no Malta). Germany alone held 174,354 ads over 90 days on 2026-10-11, all 25 countries 1,866,580.

#### Can I monitor a competitor and pay only for new ads?

Yes. Give a `memoryName` and schedule the run: each ad is delivered and charged once under that name, later runs return only ads that are new. Known ads are skipped free; with `redeliverChanged` a known ad that kept running (a later last day shown) comes back as an update at the Ad update price.

#### Why does this Actor run with limited permissions?

It runs with the least privileges the platform offers: it can only use its own storages. The cross run memory is a named store the Actor creates itself under your memory name, which works with limited permissions.

### More data tools by Automation Craft

- [Apple Ads Library Scraper: App Store Ad Repository](https://apify.com/automation_craft/apple-ads-library-scraper)
- [Meta Ads Library Scraper - Ad Library, All Filters](https://apify.com/automation_craft/meta-ads-library-scraper)
- [Google Ads Transparency Scraper - Decoded Creatives](https://apify.com/automation_craft/google-ads-transparency-scraper)
- [TikTok Ads Library Scraper: EU Ads, No Login](https://apify.com/automation_craft/tiktok-ads-library-scraper)
- [Amazon Ad Library Scraper - EU Ads & Impressions](https://apify.com/automation_craft/amazon-ad-library-scraper)
- [Pinterest Ads Library Scraper - EU Ads Repository](https://apify.com/automation_craft/pinterest-ads-library-scraper)
- [Snapchat Ads Library Scraper: EU Ads Gallery](https://apify.com/automation_craft/snapchat-ads-library-scraper)
- [Microsoft Ads Library Scraper - Competitor Ads](https://apify.com/automation_craft/microsoft-ads-library-scraper)
- [LinkedIn Ad Library Scraper: Ads by Company](https://apify.com/automation_craft/linkedin-ad-library-scraper)
- [Google Trends Scraper - Compare and Trending Now](https://apify.com/automation_craft/google-trends-scraper)

### Changelog

- 0.1 (2026-10-13): optional add-ons: Apple's restrictions feed, advertiser rows with ad counts, changed ads for memory monitors, App Store links from a file, Google Sheet or Drive file, and a proxy setting; empty country, placement and format lists mean all.
- 0.1 (2026-10-11): first version of the App Store Ads listing: apps, developers and names, whole country browse, every page to Apple's last with a coverage row, filters, variations, memory.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/app-store-ads-scraper/changelog.md

# Actor input Schema

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

One name per line, for example Temu or Booking.com. Each name goes through Apple's own name search, which matches names from their first letter. By default only an app or developer named exactly like your text is used (capitals and spaces aside); when none or several are named so, you get a free row listing the candidates with their ids instead. An App Store link pasted here is read as that app or developer. At least 2 characters, up to 100 names per run; each name search draws on the run's work allowance, so a long list of names whose apps advertise little (a few ads each in your scope) can end early, with a free row naming the names not started.

## `apps` (type: `array`):

One per line: an App Store app link (https://apps.apple.com/de/app/temu-shop-like-a-billionaire/id1641486558) or an app id (1641486558 or id1641486558). Every ad of the app in your countries and period is returned. A developer link pasted here is read as that developer. Up to 1,000 per run.

## `developers` (type: `array`):

One per line: an App Store developer link (https://apps.apple.com/us/developer/temu/id1641486560) or a developer id (1641486560). Every ad of every app of that developer is returned. An app link pasted here is read as that app. Up to 1,000 per run.

## `startUrlsFile` (type: `string`):

App Store app or developer links, one per line (commas and semicolons work too), or ONE link to a public .txt or .csv file, Google Sheet or Google Drive file that holds them. Only App Store links are read from a file; other cells are skipped and counted. Up to 2,000 links (at most 1,000 apps and 1,000 developers when pasted here) and 2 MB; a file with more uses its first 2,000 and says so. Bare ids belong in the two fields above (a bare id does not say app or developer).

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

Keep ads shown in these countries. Leave empty for all 25. Through the API send ISO codes (DE, FR, IT, ...) or country names (Germany).

## `period` (type: `string`):

Apple's reporting window: ads that ran on at least one day of the last 90 days, 180 days or year up to Apple's latest day. When left out, the shortest period that holds your dates is used (90 days without dates).

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

Keep ads that ran on this day or later: YYYY-MM-DD, today, yesterday, or a number of days or weeks back from today such as 30 days. Applied to each ad's last day shown.

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

Keep ads that started on this day or earlier: YYYY-MM-DD, today, yesterday or a number of days back. Applied to each ad's first day shown. Open ended when left out.

## `placements` (type: `array`):

Keep ads in these App Store placements. Leave empty for all.

## `formats` (type: `array`):

Keep ads of these formats. Leave empty for both.

## `nameMatch` (type: `string`):

exact (when left out): only the app or developer named exactly like your text. startsWith: every app and developer whose name begins with your words as whole words (Temu gives the developer Temu and the app Temu: Shop Like a Billionaire, but not the developer Temurbek Rakhimov).

## `nameTypes` (type: `string`):

Look names up among apps and developers (when left out), apps only, or developers only.

## `includeVariations` (type: `boolean`):

Read each delivered ad's variations with one extra call per ad: every language version of the ad (app name, subtitle, category, promotional text and, where Apple has them, per device screenshots) and its icon variations. Charged as one Ad variation set per ad only when Apple answered. Apple's variations call is slow (4 to 33 seconds) and fails now and then: a failed call leaves the ad without variations and costs nothing extra, and after about 35 seconds of failed calls in a run (plus 15 seconds for every set charged) no more variations are asked while the ads are still delivered. Off when left out.

## `includeRestrictions` (type: `boolean`):

Also read Apple's feed of advertising restrictions in the period: ads Apple removed and advertiser accounts it suspended, with the date, reason, basis, details, the placements and countries affected and the targeting flags. One row per record, charged as one Restriction. Apple has no country filter for it, so a record is kept when one of its countries is among yours. With no app, developer, name or advertiser search, the run returns only this feed (it does not browse ads).

## `restrictionActions` (type: `array`):

Which restrictions to read: removed ads, suspended accounts, or both when empty. Needs Add Apple's restrictions feed.

## `advertiserSearchTerms` (type: `array`):

Names or name beginnings, one per line, for example fitness or vpn. Apple's name search matches names from their first letter; the Names of setting (in Names above) limits the search to apps or developers. With no app, developer, name or file above, the run returns only these rows (it does not browse ads).

## `maxAdvertisers` (type: `integer`):

Stop the advertiser search after this many advertiser rows with ads in total. 100 when left out. Needs an advertiser search.

## `maxAds` (type: `integer`):

Stop after this many ads in total. 1,000 when left out, up to 1,000,000. Germany alone holds about 175,000 ads over 90 days.

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

Stop each app, developer or browsed country after this many ads. 0 or left out: no cap per target (the total cap still applies).

## `memoryName` (type: `string`):

A short plain name such as temu-watch (letters, digits, spaces and . \_ , : # ( ) -). The memory belongs to this Actor; two runs on one name at the same time are not supported (the second one delivers its rows free and remembers nothing).

## `resetMemory` (type: `boolean`):

Forget every ad the memory knows before this run starts, so every ad counts as new again. Needs a memory name. Off when left out.

## `redeliverChanged` (type: `boolean`):

With a memory name: an ad the memory delivered before is delivered again when Apple now reports a later last day shown (the ad kept running), marked changeStatus updated with the earlier day, and charged as one Ad update instead of an Ad. New ads are marked new. Off when left out: known ads are skipped free.

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

Left out: the Apify datacenter proxy. Your own proxy URLs are used as given, one per worker in turn. No proxy: the run's own address, one call at a time (slower). A residential group is mapped to the datacenter group, and the run summary says so.

## Actor input object example

```json
{
  "searchTerms": [
    "Temu"
  ],
  "countries": [
    "DE"
  ],
  "maxAds": 20
}
```

# Actor output Schema

## `items` (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 = {
    "searchTerms": [
        "Temu"
    ],
    "countries": [
        "DE"
    ],
    "maxAds": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/app-store-ads-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 = {
    "searchTerms": ["Temu"],
    "countries": ["DE"],
    "maxAds": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/app-store-ads-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 '{
  "searchTerms": [
    "Temu"
  ],
  "countries": [
    "DE"
  ],
  "maxAds": 20
}' |
apify call automation_craft/app-store-ads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/app-store-ads-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/DPV1lmZkJ6KcdiAgz/builds/Wq7avmg4sL55aLgMn/openapi.json
