← All playbooks
Playbook

Apple Ads launch

Sets up Apple Ads (Search Ads) search results campaigns for an app from scratch through the user's connected Apple Ads account – researches keywords (Apple's own suggestions and search popularity plus AppGoat keyword data), builds the standard Brand / Category / Competitor / Discovery structure with exact and Search Match ad groups, adds cross negatives so the campaigns don't bid against each other, and creates everything PAUSED for the user to review and enable. Every change is a dry run with a diff the user approves.

~15–40 + 1 per applied change credits a run/apple-ads-launch <app> [country] [target_cpa]

A first Apple Ads setup for one app in one or a few countries, with the structure most successful search results accounts use:

CampaignAd groupMatchKeywordsPurpose
BrandExactEXACTthe app's name and misspellingsdefend the brand, cheap installs
CategoryExactEXACTgeneric terms describing what the app doesthe main volume
CompetitorExactEXACTnames of competing appsconquest; usually pricier
DiscoverySearch MatchSearch Match on, no keywords(Apple picks)find new terms for the optimizer

Each campaign gets the other campaigns' keywords as EXACT negatives, so a search triggers one campaign only and the reports stay clean. Everything is created PAUSED; enabling is a separate step the user confirms, so nothing spends until they say so.

Install

Every client runs the playbook as a prompt of the hosted AppGoat MCP server. A Claude Code plugin with all playbooks is coming soon.

Add to Claude

Click Add to Claude, confirm in the Claude directory and sign in with your AppGoat account. Works in claude.ai, Claude Desktop and the mobile apps.

Can't use the directory? In Settings → Connectors choose Add custom connector and paste https://api.appgoat.ai/mcp.

Then pick apple-ads-launch from the “+” menu → AppGoat (it is served as a prompt), or upload the skill folder as a zip in Settings → Capabilities → Skills.

When to use

  • The user has an app on the App Store and connected their Apple Ads account in AppGoat (https://dash.appgoat.ai/connections, provider apple_ads). The app must be linked to the connection (connect with apps: [<App Store id>], or link it later in the dashboard); apps without campaigns are not linked automatically.
  • The Apple Ads account must be able to advertise the app (Apple Ads → Account Settings: the app's developer account linked, payment method set). Apple rejects campaigns otherwise.
  • Not for optimizing running campaigns: use apple-ads-optimizer once there are 7–14 days of data.

Inputs

  • app (required): App Store id, URL or name of the user's app.
  • country (optional): one or more storefronts, default us. Start with 1–3 countries that share a language; keywords are per language.
  • target_cpa (optional): the most the user wants to pay per install. Ask for it and for a total daily budget. Without a target: suggest 1–3 × the app's monthly price for a subscription app, or 0.5–2 USD for a free app with ads, and get a yes.

Budget split of the total daily budget B (minimum 5 per campaign): Category 45%, Brand 15%, Competitor 20%, Discovery 20%. Skip Competitor when the user doesn't want conquesting.

Steps

Costs in AppGoat credits. Without the MCP, use the REST equivalents in the REST calls below.

  1. list_connections {provider: "apple_ads"} - 0. Pick an active connection whose linked apps include the app (mode: actions to create anything; mode: read_only can only dry-run: say so). App not linked: ask the user to link it at https://dash.appgoat.ai/connections and stop.
  2. read_connection {id, what: "ads", view: "campaigns"} - 1. If the app already has campaigns, show them and ask whether to add the missing parts only (reuse names, skip existing campaigns).
  3. get_app {app} - 1: name, subtitle, category; get_competitors {app, country} - 1: up to 10 competitor names (keep the 5 most relevant).
  4. Keyword research - ~10–30:
    • read_connection {id, what: "ads", view: "suggestions", app, terms: [3–5 seed terms from the name / subtitle / category], countries} - 1: Apple's suggestions for this app.
    • get_app_keywords {app, country} - 1 (terms the app already ranks for organically).
    • read_connection {id, what: "ads", view: "popularity", terms: [≤ 100 candidates], countries} - 1: Apple's own popularity 1–100. Terms missing from the result have very low volume.
    • Optional for the top 20 category terms: keyword_research {terms, store: "apple", country} - 1 per term for difficulty and the top apps (drop terms where the top apps do something else).
  5. Build the plan (no calls): keyword lists per campaign (rules below), bids, budgets, negatives. Show it to the user as the plan table (see Output format) and get a yes before creating anything.
  6. Create, in order, each as a dry run with playbook: "apple-ads-launch", then apply_action after the user approved the plan - 0 per dry run, 1 per applied action:
    1. propose_action {type: "apple_ads.campaign.create", connection, params: {app, name: "<App> - Brand - <CC>", countries: ["US"], daily_budget, max_daily_budget: <B>}} → apply → the result's campaign.id. Same for Category, Competitor, Discovery.
    2. Per campaign apple_ads.adgroup.create {campaign_id, name: "Exact" (Discovery: "Search Match"), default_bid, search_match: false (Discovery: true)} → apply → ad_group.id.
    3. apple_ads.keyword.add {campaign_id, ad_group_id, keywords: [{text, match_type: "EXACT", bid}]} for Brand, Category and Competitor (≤ 200 per action).
    4. Cross negatives at campaign level: apple_ads.negative.add {campaign_id, keywords: [{text, match_type: "EXACT"}]}: Discovery gets every keyword of the other three; Category gets the brand terms; Competitor gets the brand terms. Read the diff of each step before applying: a blocking check (a duplicate name, a storefront the app is not in) stops that item; fix the params and propose again.
  7. Show the summary (see Output format) with the campaign ids and ask whether to go live. Only after the user explicitly says to enable a campaign: propose_action {type: "apple_ads.campaign.update", params: {campaign_id, status: "ENABLED"}} (marked "can raise ad spend"), show the diff with its daily budget, then apply_action. It applies when the org lets agents approve; otherwise it waits for approval in the dashboard: give the user the approve link. Enabling is never auto-applied by approval rules.
  8. Suggest a check-in after 7 days with apple-ads-optimizer.

Budget: ~15–40 credits for research + 1 per applied action (about 10–15 for a full setup).

Keyword and bid rules

  • Brand: the app name, the name without spaces, common misspellings, "<name> app". 3–10 terms.
  • Category: generic terms that describe what the app does and that the user would be happy to win: Apple suggestions + popularity ≥ 20, plus the app's organic ranking terms that match its core use. 20–80 terms. Drop terms about another product, a different meaning, jobs, "free" piracy-style queries or a feature the app lacks.
  • Competitor: names of the 3–8 most relevant competitors (popularity ≥ 10). Only with the user's agreement; never use a competitor's trademark in your own ad text (search results ads use the App Store listing, so this is about keywords only).
  • Default / keyword bid (max CPT): start at target_cpa × expected conversion rate, with a conversion rate of 0.5 for Brand, 0.3 for Category, 0.15 for Competitor and 0.25 for Discovery. Round to 0.05 and keep within 0.20–5.00 (in the account currency). Category terms with popularity ≥ 60 get +20%, terms below 20 get −20%.
  • Daily budget per campaign from the split above. Each daily budget must be at least 10 × its ad group default bid so the campaign can get enough taps a day; if not, reduce the number of campaigns (drop Competitor first) rather than the bids.
  • Names: <App> - <Brand|Category|Competitor|Discovery> - <CC> (CC = the first country, or INTL).

Output format

Plan (step 5):

# Apple Ads launch: <App> (<countries>) - target CPA <T> <cur>, daily budget <B> <cur>

| Campaign               | Daily budget | Ad group     | Default bid | Keywords                                   |
| ---------------------- | ------------ | ------------ | ----------- | ------------------------------------------ |
| Hush - Brand - US      | 5.00         | Exact        | 1.25        | hush, hush app, hush prayer (3)            |
| Hush - Category - US   | 15.00        | Exact        | 0.75        | prayer app, daily prayer, bible verse (42) |
| Hush - Competitor - US | 5.00         | Exact        | 0.40        | hallow, abide, pray.com (6)                |
| Hush - Discovery - US  | 5.00         | Search Match | 0.60        | (Search Match)                             |

Negatives: Discovery excludes all 51 keywords above; Category and Competitor exclude the brand terms.
All campaigns are created PAUSED. Reply "create it" or tell me what to change.

Final summary (step 7): the created campaigns with ids and status PAUSED, the keyword and negative counts, any item that was blocked and why, the enable links, and "Run apple-ads-optimizer in 7 days." Credits used: <sum>.

Automate it

A launch is a one-off: run it in a chat so the user reviews the plan. Automate the weekly follow-up with the apple-ads-optimizer playbook's GitHub Action or routine instead.

Without MCP: the REST calls

Without the AppGoat MCP server, call the API directly. Base URL https://api.appgoat.ai/v1, header x-api-key: $APPGOAT_API_KEY (create a key at https://dash.appgoat.ai). Responses are { "data": …, "meta": { "credits_used", "credits_remaining", … } }; errors are { "error": { "code", "message", "hint", "approve_url"? } } - read hint.

MCP toolREST call
list_connectionsGET /connections?provider=apple_ads (free)
read_connection view=campaignsGET /connections/{id}/ads?view=campaigns
read_connection view=suggestionsGET /connections/{id}/ads?view=suggestions&app=<adam id>&terms=a,b&countries=us
read_connection view=popularityGET /connections/{id}/ads?view=popularity&terms=a,b&countries=us
get_app / get_competitors / get_app_keywordsGET /apps/{app}, GET /apps/{app}/competitors, GET /apps/{app}/keywords
keyword_researchGET /keywords?qs=term1,term2&store=apple&country=us
propose_actionPOST /actions with "dry_run": true, "source": "playbook:apple-ads-launch" (free)
apply_actionPOST /actions/{id}/approve (1 credit when applied)

Action params:

  • apple_ads.campaign.create { app, name, countries: ["US"], daily_budget, placement?: "APPSTORE_SEARCH_RESULTS", max_daily_budget? } → result { campaign: { id, status: "PAUSED", … } }. Manual CPT, in the ad account's currency; always PAUSED.
  • apple_ads.adgroup.create { campaign_id, name, default_bid, search_match?: false, status?: "ENABLED", start_time? } → { ad_group: { id, … } }.
  • apple_ads.keyword.add { campaign_id, ad_group_id, keywords: [{ text, match_type: "EXACT", bid? }] } (≤ 200).
  • apple_ads.negative.add { campaign_id, ad_group_id?, keywords: [{ text, match_type: "EXACT" }] }.
  • apple_ads.campaign.update { campaign_id, status?: "ENABLED"|"PAUSED", daily_budget?, countries?, name? }.

Actions that can raise spend (enabling, a higher budget or bid, new countries, Search Match on) have diff.spend_increase: true. They are approved like any action: POST /actions/{id}/approve with an API key applies them when the org lets agents approve, otherwise it returns 403 with the approve_url for a person. Enabling a campaign is never auto-applied by approval rules.

CON=con_…
# Create the category campaign (dry run), then approve it
ID=$(curl -s -H "x-api-key: $APPGOAT_API_KEY" -H "content-type: application/json" https://api.appgoat.ai/v1/actions \
  -d '{"type":"apple_ads.campaign.create","connection":"'$CON'","dry_run":true,"source":"playbook:apple-ads-launch",
       "params":{"app":"6831596058","name":"Hush - Category - US","countries":["US"],"daily_budget":15,"max_daily_budget":30}}' | jq -r .data.id)
curl -s -X POST -H "x-api-key: $APPGOAT_API_KEY" "https://api.appgoat.ai/v1/actions/$ID/approve" | jq '.data.result.campaign.id'

More playbooks

/app-audit-lite~25–40 credits a run

App audit (lite)

Runs a quick App Store / Google Play audit of one app with live AppGoat data – listing quality, ratings trend, recent complaints, keyword rankings, competitors and their recent changes – and ends with a prioritized fix list.

/find-app-ideas~150–250 credits a run

Find app ideas

Finds underserved App Store / Google Play niches with live AppGoat data – search demand (keyword popularity) against weak supply (low ratings, abandoned incumbents, few strong apps) – and returns a ranked shortlist of app ideas with evidence and user pain points.

/aso-keywords-metadata-rewrite~40–80 credits a run

ASO keywords → metadata rewrite

Researches App Store / Google Play keywords for one app with live AppGoat data (current ranks, competitor keyword gaps, popularity, difficulty, relevance) and rewrites the title, subtitle, keyword field and description within the store character limits.

/competitor-digest~15–55 credits a run

Competitor digest

Writes a weekly competitor digest for one App Store / Google Play app from an AppGoat competitor watch – what each competitor changed (title, subtitle, description, screenshots, icon), price and in-app purchase changes, new versions with release-note summaries, rating and chart moves, keyword gains and losses against the user's app, keyword gaps and review themes – and ends with 3 recommended actions linked to other playbooks. Sets up or reuses the competitor_set watch.

/reviews-to-github-issues~2–10 credits a run

Reviews → GitHub issues

Turns recent negative App Store / Google Play reviews into deduplicated GitHub issues – one issue per problem topic, with linked and quoted reviews, new reviews added as comments to the existing issue instead of duplicates. Uses AppGoat review data and the gh CLI (or the GitHub MCP server).

/reply-to-every-review~1–3 + 1 per posted reply credits a run

Reply to every review

Drafts a reply to every unanswered App Store and Google Play review of the user's own app, in the app's voice, through their connected App Store Connect / Play Console account – each reply is a dry run with a before/after diff and AppGoat guardrail scores (policy, tone, claims), and only the replies the user approves are posted.

/apple-ads-optimizer~5–8 per campaign + 1 per applied change credits a run

Apple Ads optimizer

Optimizes the user's Apple Ads (Search Ads) campaigns through their connected Apple Ads account – reads the last 14 days of keyword and search term reports, raises bids on keywords that convert under the target CPA (capped +30% per run), lowers or pauses keywords that spend without installs, adds converting search terms as exact keywords and wasteful ones as negatives – every change a dry run with a diff the user approves.

/localization-push~35–60 per locale + 1 per applied change credits a run

Localization push

Localizes the user's own App Store / Google Play listing into new languages through their connected App Store Connect or Play Console account – picks target locales from markets with demand, researches the keywords people actually search in each country with AppGoat, writes a localized name, subtitle, keyword field and promotional text (Play title, short and full description) within the store limits, and pushes each locale as a dry run with a before/after diff the user approves.