Create and manage Meta (Facebook/Instagram) ad campaigns from your terminal.
Built by Attainment Labs
This is an early independent open source Meta Ads CLI, first published in February 2026 before Meta later introduced its official Ads AI Connectors and Ads CLI.
Use Meta's official connector if you want Meta-hosted OAuth and first-party support. Use this project if you want a lightweight, self-managed, scriptable CLI that you can inspect, fork, and run inside your own workflow.
Related:
- Meta's official Ads CLI documentation
- Attainment's companion MCP server
- Meta Ads Automation Playbook
Meta Ads Manager is slow. Clicking through 15 screens to launch a campaign is a waste of time when you already know what you want to run.
This tool lets you define a campaign in a YAML file and deploy it with one command.
meta-ads create --config campaign.yaml
One campaign. One ad set. Multiple ads. All created in seconds. You also get account lookup, campaign listings, insights, budget updates, bulk status operations, setup snippets, spend limits, and local audit logs.
pip install meta-ads-cliOr install from source:
git clone https://github.com/attainmentlabs/meta-ads-cli.git
cd meta-ads-cli
pip install -e .1. Set up your credentials
cp .env.example .env
# Edit .env with your Meta access token, ad account ID, and page ID2. Create your campaign config
cp campaign.example.yaml campaign.yaml
# Edit campaign.yaml with your ad copy, images, targeting, and budget3. Validate your config
meta-ads validate --config campaign.yaml4. Preview with dry run
meta-ads create --config campaign.yaml --dry-run5. Deploy
meta-ads create --config campaign.yamlYour campaign is created as PAUSED by default. Review it in Ads Manager, then activate it when ready.
Create a .env file in your project root (or export these in your shell):
| Variable | Required | Description |
|---|---|---|
META_ACCESS_TOKEN |
Yes | Your Meta API access token |
META_AD_ACCOUNT_ID |
Yes | Your ad account ID (numbers only, no act_ prefix) |
META_PAGE_ID |
Yes | Your Facebook Page ID |
META_API_VERSION |
No | API version (default: v21.0) |
META_ADS_MAX_DAILY_BUDGET_CENTS |
No | Optional daily budget guardrail |
META_ADS_AUDIT_LOG_PATH |
No | Optional JSONL audit log path |
Your campaign is defined in a single YAML file. Here is the full schema:
campaign:
name: "My Campaign"
objective: OUTCOME_TRAFFIC # See objectives below
status: PAUSED # PAUSED or ACTIVE
special_ad_categories: [] # Leave empty unless required
ad_set:
name: "My Ad Set"
daily_budget: 1000 # In cents. 1000 = $10/day
optimization_goal: LINK_CLICKS # See optimization goals below
targeting:
age_min: 18
age_max: 65
genders: [0] # 0 = all, 1 = male, 2 = female
countries: ["US"]
interests: # Optional
- id: "6003139266461"
name: "Fitness and wellness"
platforms: ["facebook", "instagram"]
facebook_positions: ["feed"]
instagram_positions: ["stream", "story", "reels"]
ads:
- name: "My Ad"
image: ./images/ad.png # Path relative to YAML file
primary_text: "Your ad copy."
headline: "Your Headline"
description: "Short description"
cta: LEARN_MORE # See CTAs below
link: "https://example.com"Campaign Objectives: OUTCOME_TRAFFIC, OUTCOME_AWARENESS, OUTCOME_ENGAGEMENT, OUTCOME_LEADS, OUTCOME_SALES, OUTCOME_APP_PROMOTION
Optimization Goals: LINK_CLICKS, IMPRESSIONS, REACH, LANDING_PAGE_VIEWS, APP_INSTALLS, OFFSITE_CONVERSIONS, LEAD_GENERATION
CTA Options: LEARN_MORE, SIGN_UP, DOWNLOAD, SHOP_NOW, BOOK_NOW, GET_OFFER, SUBSCRIBE, CONTACT_US, APPLY_NOW, WATCH_MORE
Print local MCP setup snippets for Claude, Cursor, Codex, or ChatGPT.
meta-ads setup --client claude
meta-ads setup --client cursor
meta-ads setup --client codex
meta-ads setup --client chatgptChatGPT requires a hosted MCP endpoint. Until that ships, the command prints the local config and notes the hosted requirement.
Create a full campaign from your YAML config.
# Preview first
meta-ads create --dry-run
# Deploy (will ask for confirmation)
meta-ads create
# Deploy without confirmation
meta-ads create --yes
# Use a custom config file
meta-ads create --config path/to/campaign.yamlCheck the status of a campaign and all its ads.
meta-ads status 120243616427570285Show the configured ad account.
meta-ads account
meta-ads account --json-outputList recent campaigns.
meta-ads campaigns --limit 25
meta-ads campaigns --json-outputList recent ad sets.
meta-ads adsets --limit 25List recent ads.
meta-ads ads --limit 25Pull account, campaign, ad set, or ad insights.
meta-ads insights --level campaign --date-preset last_7d
meta-ads insights 120243616427570285 --date-preset last_30d --json-outputUpdate daily budget for a campaign or ad set. This defaults to dry run.
meta-ads budget 120243616427570285 3000
meta-ads budget 120243616427570285 3000 --live
meta-ads budget 120243616427570285 3000 --live --yesIf META_ADS_MAX_DAILY_BUDGET_CENTS is set, updates above that cap are blocked.
Upload an image and return its Meta image hash. This defaults to dry run.
meta-ads upload-image ./images/ad.png
meta-ads upload-image ./images/ad.png --live
meta-ads upload-image ./images/ad.png --live --yesBulk pause, activate, or delete campaigns. This defaults to dry run.
meta-ads bulk-status PAUSED 111 222 333
meta-ads bulk-status ACTIVE 111 222 333 --live
meta-ads bulk-status DELETED 111 222 333 --live --yesPause a running campaign.
meta-ads pause 120243616427570285Activate a paused campaign. This starts spending your budget.
meta-ads activate 120243616427570285Permanently delete a campaign.
meta-ads delete 120243616427570285Validate your YAML config without making any API calls.
meta-ads validate --config campaign.yaml- Campaigns are created as
PAUSEDby default. meta-ads budget,meta-ads upload-image, andmeta-ads bulk-statusdefault to dry run.- Live budget, media upload, and bulk operations require
--live, with an interactive confirmation unless--yesis passed. META_ADS_MAX_DAILY_BUDGET_CENTSblocks budget changes above your chosen cap.- Mutating commands write JSONL audit events. Default path:
~/.meta-ads-cli/audit.jsonl.
Built for scripting. Mutating commands take --yes to skip the prompt, read commands take --json-output for machine-readable output, and every command exits non-zero on failure, so it drops into shell scripts, cron, or CI cleanly.
Create many campaigns from a folder of configs:
for cfg in campaigns/*.yaml; do
meta-ads create --config "$cfg" --yes
donePipe results into other tools:
meta-ads campaigns --json-output | jq '.[] | {id, name, status}'
meta-ads insights --level campaign --date-preset last_7d --json-output > insights.json--date-preset accepts any Meta preset (yesterday, last_7d, last_30d, and so on).
Guardrails still apply unattended: campaigns create as PAUSED, META_ADS_MAX_DAILY_BUDGET_CENTS caps budget changes, and every mutating run appends a JSONL audit event.
This is the part most people get stuck on. Here is the short version:
- Go to Meta for Developers and create an app (type: Business)
- Open the Graph API Explorer
- Select your app, then request these permissions:
ads_management,pages_read_engagement,pages_show_list - Click "Generate Access Token" and authorize
- Copy the token to your
.envfile
Important: Graph API Explorer tokens expire after about 2 hours. For production use, exchange it for a long-lived token:
curl "https://graph.facebook.com/v21.0/oauth/access_token?\
grant_type=fb_exchange_token&\
client_id=YOUR_APP_ID&\
client_secret=YOUR_APP_SECRET&\
fb_exchange_token=YOUR_SHORT_LIVED_TOKEN"Long-lived tokens last about 60 days.
Interest targeting requires Meta's internal IDs. Search for them using the API:
curl "https://graph.facebook.com/v21.0/search?\
type=adinterest&\
q=fitness&\
access_token=YOUR_TOKEN"This returns interest names and IDs you can use in your campaign YAML.
See the examples/ directory for ready-to-customize campaign configs:
- ecommerce.yaml: Product launch targeting skincare enthusiasts
- app-install.yaml: Mobile app install campaign for fitness users
This tool wraps the Meta Marketing API with requests. No heavy SDKs. The full chain:
- Uploads your ad images to your ad account
- Creates a campaign with your objective
- Creates an ad set with your budget and targeting
- Creates ad creatives linking your images and copy
- Creates ads linking creatives to the ad set
Everything is created as PAUSED by default so you can review before spending.
We wrote a free guide covering Meta Ads AI automation end to end: when to use CLI, when to use MCP, OAuth setup walkthrough, audience segmentation strategy, budget allocation frameworks, creative testing, scaling rules, and common API errors with fixes.
Get the Guide: The Engineer's Playbook for Meta Ads
PRs welcome. Keep it simple. This tool is intentionally lightweight.
git clone https://github.com/attainmentlabs/meta-ads-cli.git
cd meta-ads-cli
pip install -e .
meta-ads --helpMIT. See LICENSE.