Apple Ads, formerly Apple Search Ads, covers search, Today tab, product pages and Maps placements. Erdi pulls the campaign report Apple already generates and plots spend against installs under your events.
Daily spend, impressions, taps and installs from Apple, stored as apple-suffixed series so a later Google Ads source can sit beside them instead of merging into one line. The runner adds ads_spend and ads_installs as the sum across platforms. Those sums are spend and installs only — not averages. Cost per acquisition and cost per tap are stored as ads_cpa_apple and ads_cpt_apple, the values Apple reports (CPA and CPT). Tap-through rate (taps ÷ impressions) and conversion rate (installs ÷ taps) are stored as ads_ttr_apple and ads_cr_apple, computed from the same daily buckets — omitted when the denominator is zero. Erdi does not divide spend by installs for CPA, and does not roll those averages into a platform total. Reporting is not real time — the last three hours may be missing, and installs keep landing after the day ends — so Erdi marks today as pending until the next sync settles it (same hatch style as App Store Connect). Apple draws the day boundary in the ad account's own time zone, shown in the Apple Ads reporting footer. If you run five campaigns or fewer, spend is also split by campaign on the rollup. Country and campaign depth also land in metric_rows (see Your own numbers) for the Acquisition breakdown — that table is not what Timeline or alerts read. Cost per paying user is calculated on the overview from spend and new paying users; it is not stored.
An Apple Ads API client: client ID, team ID, key ID, org ID and the private key you generated. Pick the App Store app for this project — otherwise every campaign in the org lands here. The private key is stored encrypted. Erdi exchanges them for an OAuth access token and pulls the last thirty days on a schedule; the first sync looks back ninety days. This is a pull, not a webhook from Apple.
Generate a key pair locally. The private half never leaves your machine.
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out apple-ads-private.pem openssl ec -in apple-ads-private.pem -pubout -out apple-ads-public.pem
The installs in these reports are the ones Apple attributed to a tap on your ad. They are not a subset of the downloads App Store Connect reports, and subtracting them from that number does not leave you with organic installs.
Apple counts app installs in three separate systems: Apple Ads attributes them to ad taps, App Store Connect Analytics counts downloads by how someone found the app, and App Store Connect Sales counts download totals on its own basis and its own delay. The difference between any two of them is a definition gap, not a number about your app. Erdi shows each series as its source reports it and does not combine them.
Keywords, search terms, creatives, and ad-group detail. Those stay in Apple Ads. Age and gender too. Apple reports both as Low Volume or Unknown for anything at indie scale — even in Apple's own dashboard. Erdi doesn't fetch a column that would only ever say Unknown. Erdi also does not show ROAS, LTV, payback or cohorts — those need an attribution chain iOS does not give you.
Set it up under Settings → Sources in your project.