Ads
Rank acquisition campaigns, ad groups, keywords, and ads by lifetime USD revenue via MCP tools.
Advertising Insights rank acquisition campaigns, ad groups, keywords, and ads by USD revenue from attributed users — and, when an Apple Search Ads integration is connected, by spend / ROAS alongside. Revenue aggregates app_users by attribution source and joins each user's lifetime RevenueCat revenue (refreshed daily and on every subscription webhook); spend / impressions / taps / installs come from Apple's Reports API into ad_campaign_lifetime + ad_adgroup_lifetime (refreshed daily by the apple_ads_sync job). Requires a RevenueCat integration for revenue data and Apple Search Ads attribution for human-readable names; the Apple Search Ads integration is also what unlocks spend numbers and start dates / status.
Trailing 12-month window. Both sides of the ROAS calculation are scoped to the same window: spend is summed from Apple's Reports API in 4×90-day chunks (Apple caps single requests at ~90 days), and revenue is filtered to users with app_users.first_seen_at inside that same window — so users acquired before the spend window's start don't inflate ROAS by contributing revenue against zero matchable spend. The window in days is echoed back as window_days on every ads response.
Drill from campaigns into ad groups, then into keyword/ad leaves.
list-ad-campaigns
Rank campaigns by lifetime USD revenue from attributed users, joined to ad spend (where available) for ROAS. Aggregates app_users by attribution_source + campaign, joins each user's lifetime RevenueCat revenue, then LEFT JOINs ad_campaign_lifetime for spend / impressions / taps / installs synced from the network's Reports API (Apple Search Ads today). Returns user_count, paid_user_count (lifetime ever-paid), retained_user_count (currently on an auto-renewing paid subscription, excludes trials), total_revenue_usd, arpu, total_spend_usd, roas (revenue ÷ spend), start_date, status per campaign, sorted by revenue desc. Spend / ROAS are null when no Apple Search Ads integration is connected, no row in ad_campaign_lifetime matches yet, or the org reports in a non-USD currency — the response top-level carries total_spend_usd, ad_metrics_synced_at, and currency_warning (non-null currency code, e.g. "EUR", when at least one row's spend was reported in something other than USD).
Pass project_id for a single project, or team_id to aggregate the best-performing campaigns across every project in a team — each row then also carries a project_id so you can tell which project owns each campaign and use it on the project-scoped drill-downs (list-ad-groups, list-ad-leaves).
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | UUID | One of | The project ID. Mutually exclusive with team_id |
team_id | UUID | One of | Team ID — aggregates across every project in the team |
attribution_source | string | No | Defaults to apple_search_ads (only value populated today) |
app_id | UUID | No | Scope to users acquired into a single app (project mode only; ignored when team_id is set) |
limit | number | No | Max campaigns (1-500, default 100) |
list-ad-groups
Rank ad groups within a campaign by lifetime USD revenue + spend (ROAS). Same response shape as list-ad-campaigns, one level deeper, joined against ad_adgroup_lifetime for ad-group-level spend / start_date / status. Each row carries total_spend_usd, roas, start_date, status alongside revenue / users / paid_user_count / retained_user_count / ARPU; the response top-level also exposes total_spend_usd, ad_metrics_synced_at, and currency_warning.
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project ID |
campaign_id | string | Yes | Network-specific campaign ID returned by list-ad-campaigns |
attribution_source | string | No | Defaults to apple_search_ads |
app_id | UUID | No | Scope to a single app |
limit | number | No | Max ad groups (1-500, default 100) |
list-ad-leaves
Within a single ad group, list keyword-level and ad-level revenue rankings side-by-side. Returns both keywords and ads arrays — Apple Search Ads attributes a user to one or the other depending on whether the install came from a search keyword or an auto-driven ad placement.
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project ID |
campaign_id | string | Yes | Parent campaign ID |
ad_group_id | string | Yes | Ad group ID returned by list-ad-groups |
attribution_source | string | No | Defaults to apple_search_ads |
app_id | UUID | No | Scope to a single app |
limit | number | No | Max leaves per side (1-500, default 100) |
sync-ads
Trigger a manual refresh of advertising insights for one project. Fires both revenuecat_sync (refreshes lifetime revenue per user) and apple_ads_sync (resolves any unresolved ASA IDs to readable names AND pulls campaign + ad-group spend / impressions / taps / installs from Apple's Reports API into ad_campaign_lifetime + ad_adgroup_lifetime, filtered by adamId so each project only stores rows for its own apps). Admin-only. Both jobs also run on a daily cron — revenuecat_sync at 03:00 UTC, apple_ads_sync at 04:45 UTC.
| Parameter | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project ID |
Use this after onboarding a new RevenueCat integration or to force-refresh between cron runs. Use get-job on the returned job_run_id to monitor progress.
