Launch in 5 markets without 5x the work.

One command turns a campaign into translated locale variants or persona-targeted copies. Every variant is a TypeScript file — reviewable, diffable, and applied like any other campaign.

Terminal
$ ads expand --campaign campaigns/brand-search.ts \
    --locales de,fr,es --translate

  Expanding: brand-search → 3 locale variants

  ✓ campaigns/brand-search--de.ts    (DE · translated)
  ✓ campaigns/brand-search--fr.ts    (FR · translated)
  ✓ campaigns/brand-search--es.ts    (ES · translated)

  Each variant: localized headlines · geo targeting updated · budget preserved

  Run `ads plan` to preview all changes before applying.

Expanding to a new market means opening the platform UI and clicking through every campaign, ad group, and ad — duplicating and translating each one by hand.

5 markets means 5x the campaigns to maintain. A budget change in the original campaign has to be repeated in every locale variant.

Targeting a different audience angle — SaaS founders vs. ops managers — means yet another full duplication. The complexity compounds.

ads-as-code expands a campaign into locale translations or ICP variants in one command. Variants are TypeScript files — diffable, reviewable, and applied like any other campaign.

How it works

Locale translations — one campaign, every market

`ads expand --locales` creates translated copies of your campaign for each target locale. Headlines, descriptions, and body copy are translated by AI. Targeting and geo are updated automatically.

Terminal
$ ads expand --campaign campaigns/brand-search.ts \
    --locales de,fr,es,nl --translate

  brand-search--de.ts
    ~ name       → "Acme — Brand Search — DE"
    ~ geo        ["US"] → ["DE", "AT", "CH"]
    ~ headlines  15 headlines translated to German

  brand-search--fr.ts
    ~ name       → "Acme — Brand Search — FR"
    ~ geo        ["US"] → ["FR", "BE", "CH"]
    ~ headlines  15 headlines translated to French

  ✓ 4 files created. Run `ads plan` to review.

ICP expansion — same product, different audience angles

Use `ads expand --icps` to generate variants targeting different buyer personas. Each variant gets rewritten copy for that persona while preserving budget and structure.

Terminal
$ ads expand --campaign campaigns/brand-search.ts \
    --icps "ops managers at B2B SaaS,founders at early-stage startups" \
    --rewrite-copy

  brand-search--ops-managers.ts
    ~ headlines  "Automate the Work Your Ops Team Hates"
                 "Reclaim 10 Hours a Week for Your Ops Team"

  brand-search--founders.ts
    ~ headlines  "Ship Workflows Without Engineering Help"
                 "One Person Can Run What Took a Team"

  ✓ 2 files created. Run `ads plan` to review.

Variant customization — fine-tune before applying

Variants are plain TypeScript files. Edit them like any campaign — adjust bids, swap headlines, change targeting. Then run `ads plan` to diff all variants at once.

TypeScript
// campaigns/brand-search--de.ts
// Generated by `ads expand` — edit freely

import { google, daily, exact, phrase, headlines, descriptions, rsa, url } from '@upspawn/ads'

export default google.search('Acme — Brand Search — DE', {
  budget: daily(30),  // ← adjusted for DE market
  bidding: 'maximize-clicks',
})
  .group('Core KW', {
    locale: { language: 'de', geo: ['DE', 'AT', 'CH'] },
    keywords: [...exact('acme'), ...phrase('workflow automatisierung')],
    ad: rsa(
      headlines('Workflows mit KI automatisieren', 'Kein Code nötig', '500+ Integrationen'),
      descriptions('Acme verbindet Ihre Tools. Sofort einsatzbereit.'),
      url('https://acme.dev/de/'),
    ),
  })

Capabilities

Locale translations

`ads expand --locales` translates headlines, descriptions, and body copy into target languages and updates geo targeting to match.

ICP expansion

`ads expand --icps` rewrites copy for different buyer personas while preserving structure, budgets, and bidding strategy.

Campaign multiplication

One source campaign becomes N variant files. Every variant is a full TypeScript campaign definition — no templates, no magic.

Customizable variants

Variants are plain TypeScript files. Edit bids, copy, and targeting before applying. No lock-in to generated content.

Batch generation

Expand multiple campaigns in one pass. All variants are created, reviewed with `ads plan`, and applied in one `ads apply`.

Preserves original structure

Budget tiers, ad group hierarchy, keyword match types, and bidding strategy carry over unchanged from the source campaign.