EMAX Studio Blog

How to Set Up the Meta Ads CLI: Step-by-Step Tutorial for 2026

Manuel Mrosek · 2026-06-16 · views

How to Set Up the Meta Ads CLI: Step-by-Step Tutorial for 2026

To set up the Meta Ads CLI, you create a System User in Business Manager, generate a never-expiring token with ads_management, ads_read, and business_management permissions, link your Ad Account and Page as assets, and then point the CLI at that token through a config file. The whole process takes about 45 minutes if you have admin access to a Business Manager, a Facebook Page, and a verified payment method on your Ad Account.

This is the deep-dive companion to our overview on running Facebook Ads with AI agents. That piece explains why a CLI-driven setup beats Ads Manager clicks for anyone running more than a handful of campaigns. This one is the hands-on guide: every step, every error message we hit when we built our own stack, and a real first-campaign walkthrough at the end.

What the Meta Ads CLI Actually Does

The "Meta Ads CLI" is not a single official binary. It is a thin server-side automation layer that sits between your scripts and the Meta Marketing API. You write Python or Node code, the CLI handles authentication, request signing, and the long-lived System User token, and your campaigns go up through graph.facebook.com/v23.0/ without anyone clicking through Ads Manager.

The hard part is not the wrapper code — that is a hundred lines. The hard part is the 7-step setup ritual inside Business Manager that produces a token Meta will actually accept for production traffic. That ritual removes the OAuth refresh dance and the token-expiry pain that breaks every browser-based automation eventually.

The payoff is real. Once the CLI stack is running, you can launch a campaign with 6 ad variants in under 90 seconds, pull yesterday's performance into a daily report at 7:00 AM via cron, and auto-pause underperforming ads — without ever logging into Ads Manager.

Prerequisites

Before you start, make sure you have these in place. Skipping any of them sends you down a 2-hour rabbit hole later.

You need a Meta Business Manager account with admin rights — personal Facebook accounts will not work for System User tokens. You need a Facebook Page where you are listed as an admin, not just an editor. You need a Meta Ad Account inside that Business Manager with a verified payment method and at least one country approved for billing. You need a Pixel (or "Dataset" in the new terminology) configured for whatever website you are driving traffic to. And you need Python 3.10+ or Node 18+ installed locally with the ability to install packages.

If you do not have a Pixel yet, create one before continuing. Even if you plan to use Conversions API (CAPI) only — like we do — you still need the Pixel ID as a routing address for server-side events.

The 7-Step Setup

These steps are sequential. Each one unlocks the next. Skipping ahead breaks the chain in ways that are hard to debug because Meta's error messages are often misleading.

Step 1: Create a Business Manager System User

Go to Business Settings → Users → System Users. Click "Add" and create a new System User. The name does not matter for the API but matters for your future sanity — name it something like your-brand-agent so you remember what it is doing six months from now. Choose role "Admin" (not "Employee") because System Users without admin rights cannot manage Custom Conversions or Pixel events.

When we built our stack, we created emaxstudioagent. The System User ID gets assigned automatically (15-digit number). Write it down.

Step 2: Create a Developer App with Marketing API Use Case

Go to developers.facebook.com → My Apps → Create App. Choose use case "Marketing API" if you see it in the dropdown. If you only see "Other," that is fine too — System User tokens work either way. The German UI labels this "Werbeanzeigen mit Marketing API" while the English UI calls it just "Marketing API" or "Other." Both produce identical tokens.

Set the app to Business type, not Consumer. Add the Marketing API product to the app from the left sidebar. The app starts in Development Mode. You must move it to Live Mode (more on that below) before the System User token will work for real ads.

To move to Live Mode, Meta requires a public privacy policy URL and an app icon (1024×1024 PNG). Both are non-negotiable. The app icon does not need to be polished — a placeholder works — but the URL needs to actually resolve to a privacy policy page. We host ours at /legal on our main domain.

Step 3: Generate a Never-Expiring System User Token

Back in Business Settings → System Users → [your System User] → click "Generate New Token." Select the app you just created in Step 2. Then select the permissions:

  • ads_management — required to create, edit, and pause campaigns
  • ads_read — required to pull insights and reporting data
  • business_management — required to manage assets and custom conversions

Set the expiration to "Never." System User tokens are the only Meta tokens that genuinely never expire — User Access Tokens max out at 60 days, Page Tokens depend on the User Token they were derived from. This is the entire point of using a System User instead of OAuth for backend automation.

Copy the token immediately. Meta shows it once. Store it in a secrets manager or an .env file with chmod 600. Never commit it to git.

Step 4: Link the Ad Account and Page as Assets

The System User exists but has no access to anything yet. You have to explicitly assign assets. In Business Settings → System Users → [your System User] → click "Add Assets."

Assign your Ad Account with full permission ("Manage Campaigns" + "Manage Performance"). Assign your Page with full permission. Assign your Pixel/Dataset with full permission. If you have multiple Ad Accounts and you want the CLI to manage them all, assign each one.

When we set this up, we assigned act_975780295197610 (our Ad Account) and Page 1113585798495892 (our EMAX Studio page) plus Pixel 1464075091373537. The act_ prefix on Ad Account IDs is required when you call the API — it is part of the actual ID, not a formatting convention.

Step 5: Assign "Page verwalten" / "Manage Page" Permission

This is the step that traps almost everyone the first time. Step 4 assigned the Page as an asset, but the default permission level is "Anzeigen erstellen" / "Create Ads" — which is not enough. The System User needs "Page verwalten" / "Manage Page" to publish ad creatives that reference the Page.

If you skip this, every ad creation API call will return a generic "permission denied" error that does not mention the Page. You will spend hours checking your token scopes and Ad Account permissions while the actual problem is one click deep in the Page asset settings.

Click on the Page in the asset list, scroll to permissions, and toggle "Manage Page" on for the System User. Save.

Step 6: Install the CLI and Create a Config File

For Python, install the official SDK:

pip install facebook-business

For Node, use the community-maintained client:

npm install facebook-nodejs-business-sdk

Create a config file at ~/.meta-ads/config.json (or wherever your stack stores secrets):

{
  "access_token": "EAA...your-system-user-token",
  "app_id": "910292175368026",
  "app_secret": "your-app-secret",
  "ad_account_id": "act_975780295197610",
  "page_id": "1113585798495892",
  "pixel_id": "1464075091373537",
  "api_version": "v23.0"
}

Set permissions: chmod 600 ~/.meta-ads/config.json. The app_secret is optional for System User tokens but enables appsecret_proof signing, which Meta recommends for production.

Step 7: Run the First Test Command

Verify everything works by listing your campaigns. In Python:

from facebook_business.api import FacebookAdsApi
from facebook_business.adobjects.adaccount import AdAccount
import json

cfg = json.load(open("/path/to/config.json"))
FacebookAdsApi.init(access_token=cfg["access_token"])
account = AdAccount(cfg["ad_account_id"])
campaigns = account.get_campaigns(fields=["name", "status", "objective"])
for c in campaigns:
    print(c["name"], c["status"], c["objective"])

If this returns a list (even an empty list, if you have no campaigns yet), you are done. If it raises OAuthException or Permission denied, go back to the error table below.

Common Setup Errors and How to Fix Them

These are the 8 errors that bit us during the build. Every one of them cost real hours. Save yourself the pain.

Error What It Actually Means Fix
Cannot use Custom Conversion with 0 events as promoted_object Your Custom Conversion has not fired yet, so Meta refuses to optimize for it Optimize for LANDING_PAGE_VIEWS first; switch to OFFSITE_CONVERSIONS after 50+ events have fired
App must be Live, not Development You generated a token but never moved the app to Live Mode Add privacy policy URL + app icon, then toggle App Review → Live in the app dashboard
Use Case must be Marketing API, not Other (UI varies) German UI label "Werbeanzeigen mit Marketing API" maps to English "Marketing API." Both work for System User Tokens. Either use case works; ignore the dropdown name and proceed
Instagram requires EU Pay-or-Consent + Page Linkage Instagram-placed ads fail with HARD_ERROR on EU traffic if your IG account is not linked to a Page that has Pay-or-Consent set Link your Instagram Business account to a Page in Business Settings → Accounts → Instagram
bid_strategy is required Ad Set creation missing the bid_strategy field Add "bid_strategy": "LOWEST_COST_WITHOUT_CAP" to the Ad Set payload
targeting_automation.advantage_audience is required New v23.0 field is mandatory Add "targeting_automation": {"advantage_audience": 1} (or 0)
video_feeds placement is deprecated This placement was removed in v23.0 Remove video_feeds from your placement list; use feed and instagram_reels instead
image_hash is required for video_data Video creatives need a thumbnail image registered as a hash Extract a frame with ffmpeg -i video.mp4 -ss 00:00:01.5 -frames:v 1 thumb.jpg, upload via /adimages, use the returned hash

The Custom Conversion one is the meanest because the error message technically tells you what is wrong but the workaround is non-obvious. A brand-new Custom Conversion has zero events in Meta's system. Meta refuses to optimize a campaign for something it has no historical data on. The trick is to launch the campaign optimized for Landing Page Views first, let 50+ conversions fire through CAPI, then switch the Ad Set's promoted_object to OFFSITE_CONVERSIONS with your Custom Conversion ID. After that, optimization actually works.

A Real First-Campaign Walkthrough

Here is what we ran as our first live test. Real values, real flow, real results.

Create the Campaign. Objective: OUTCOME_TRAFFIC (later switched to OUTCOME_SALES once we had conversion data). Status: PAUSED initially so the Ad Set and Ads can be created underneath before flipping everything to ACTIVE in one step. Budget lives at Ad Set level in our setup.

Create the Ad Set. Daily budget: 1000 (cents = $10/day). Optimization: LANDING_PAGE_VIEWS. Bid strategy: LOWEST_COST_WITHOUT_CAP. Targeting: countries ["US", "GB", "CA"], age 25 to 55, language English. Placements: feed, instagram_reels, stories, marketplace. Targeting automation: {"advantage_audience": 1}.

Build the Creatives. Three image creatives and three video creatives — six ads total. For images, we used our own EMAX Studio output (eat your own dogfood): three hooks, three brand-colored backgrounds, all 1080×1080. For videos, three 15-second vertical reels with word-by-word captions and AI voice, generated through our own pipeline (walked through in How to Create an AI Marketing Campaign Step-by-Step). Each video creative needs an image_hash for the thumbnail — extract a frame at 1.5 seconds with ffmpeg, upload it to /adimages, and use the returned hash inside the video_data block.

Activate. Flip Campaign, then Ad Set, then all six Ads to ACTIVE. Meta review usually clears in 15 to 30 minutes. Rejected ads surface per-ad via ad.get('effective_status').

Daily Report. A meta_daily_report.py script runs at 7:00 AM Berlin time via cron. It pulls insights, formats spend / CTR / CPM / conversions into a Telegram message, and auto-pauses any ad with CTR under 0.5% after 100+ impressions. The first 48 hours produced 4,200 impressions, 78 clicks (CTR 1.86%), and 12 Quick Scan completions at $1.67 per conversion — enough signal to switch optimization from Landing Page Views to OFFSITE_CONVERSIONS against the QuickScanComplete Custom Conversion on day three.

Pitfalls to Avoid

A few things will burn you. We learned each of these the hard way.

Do not hardcode tokens in git. Even private repos. Tokens leak through CI logs, accidentally-public forks, and commits made before a repo's visibility changed. Always read from environment variables or a chmod-600 config file outside the repo.

Do not skip the Page Manage permission from Step 5. The errors you get look like they are about the Ad Account or the token. They are not. Re-check the Page asset permission first whenever you see a vague "permission denied" on creative creation.

Do not deploy with the developer app still in Development Mode. The token works for the user who created it but silently fails for any other System User context. Move to Live Mode before running anything on a server.

Do not forget the image_hash for video creatives. Without it, the entire Ad creation fails with a misleading error about video_data.

Do not skip CAPI if you plan to scale. Browser pixels lose 30 to 50% of events to iOS ATT, ad blockers, and tracking prevention. Server-side Conversions API recaptures most of them — one weekend of work that pays back the first week you scale ad spend.

Frequently Asked Questions

How much does it cost to set up the Meta Ads CLI?

The setup itself is free. The Marketing API, System User tokens, Business Manager, and all developer tools are zero-cost — you only pay for the ads you actually run. Plan on 4 to 6 hours of setup time the first time and 30 minutes any time after.

Can I run multiple ad accounts through one CLI install?

Yes, and this is one of the main reasons agencies use System User tokens. Add each Ad Account as an asset in Business Settings, and you can target any of them by changing the ad_account_id in your config or passing it as a parameter. One System User token can manage hundreds of Ad Accounts across multiple Business Managers if the permissions are in place.

What about a Google Ads CLI — is the setup similar?

The concept is similar but Google's setup is rougher. Google requires a developer token approval that can take 7 to 21 days, OAuth2 refresh tokens that expire periodically, and an additional layer of MCC (Manager Account) permissions. Meta's System User token is genuinely the simpler of the two systems. If you run both platforms, set up Meta first to learn the patterns.

How do I rotate tokens safely if one is compromised?

Generate a new System User token (same permissions, same "Never" expiration), update your config, test that the new token works, then revoke the old one. Meta lets you keep multiple active tokens for the same System User simultaneously, so you can roll without downtime. If a token is leaked, revoke immediately and audit recent ad spend through the API for unauthorized campaigns.

How does Conversions API (CAPI) fit into this setup?

CAPI is a separate but complementary system. The Meta Ads CLI manages campaigns, ad sets, and ads. CAPI sends server-side conversion events that those ads optimize against. Both use the same Pixel ID. CAPI events flow independently of any browser pixel — they are the foundation of GDPR-clean tracking because no cookies are involved and PII is hashed before transmission. The AI Facebook Ads with AI agents overview covers how CAPI fits into the bigger automation stack.

The Honest Bottom Line

The Meta Ads CLI is not magic. It is a disciplined way to remove three things from your workflow: OAuth token refreshes, manual Ads Manager logins, and the human-error cost of clicking through 14 settings every time you launch an ad. Once it is running, you do in 90 seconds what used to take 30 minutes.

The setup is fiddly because Meta's tooling is fiddly. But the steps are deterministic. Follow the 7-step setup exactly, watch for the 8 errors in the table, and you will have a production-grade ads stack by the end of the afternoon. For the bigger picture of how the CLI ties into AI creatives and daily reporting, see our overview on Facebook Ads with AI agents and AI news week 18, 2026 for what is shifting in the ads ecosystem this year.

Once the CLI is live, the question becomes what creatives to feed it. Run your landing page through a free 90-second AI-readiness scan at emax.studio — you get a score, a list of conversion gaps, and a ready-to-run campaign brief in under two minutes.


Follow EMAX Studio: Instagram | YouTube | Facebook

Share:

Ready to create your own AI video reels?

5 free credits. No credit card required.

Start Creating for Free