CLI Full Reference
This is the complete reference for the Ads Uploader CLI. For an introduction and getting started guide, see CLI Configuration.
Commands
Authentication
| Command | What it does |
|---|---|
ads login | Authenticate via browser (opens your default browser) |
ads logout | Clear stored credentials |
ads whoami | Show the currently logged-in user |
ads config | Show configuration (account, API URL, credentials path) |
Browsing
| Command | What it does |
|---|---|
ads accounts | List all ad accounts connected to your Meta account |
ads account <id> | Set a default ad account for future commands |
ads campaigns | List active campaigns |
ads campaigns --status all | Include paused and archived campaigns |
ads campaigns --search "text" | Filter campaigns by name |
ads campaign <id> | Show the ad sets inside a campaign |
ads adsets --campaign <id> | List ad sets in a campaign (supports --search, --status) |
ads adset <id> | Show the ads inside an ad set |
ads ad <id> | View full ad details including creative settings |
ads presets | List your saved API presets |
ads presets <id> | Show details for a specific preset |
ads text-presets | List your saved text presets |
ads text-presets <id> | Show details for a specific text preset |
ads uploads | List recent upload batches |
ads uploads <batchId> | Show batch details (files, variants, hashes) |
Media Upload
| Command | What it does |
|---|---|
ads upload <files...> | Upload images and videos to your ad account |
ads upload ./directory/ | Upload an entire directory |
Ad Creation
| Command | What it does |
|---|---|
ads create spec.json | Create ads from a spec file |
ads create:preview spec.json | Dry run showing what would be created |
ads create:interactive | Guided wizard (accepts all create flags) |
Job Management
| Command | What it does |
|---|---|
ads jobs <jobId> | Check the status of a job |
ads jobs <jobId> --follow | Stream live progress updates |
ads jobs cancel <jobId> | Cancel a running job |
Create Flags
These flags apply to ads create, ads create:preview, and ads create:interactive. They can be used instead of or alongside a spec file.
| Flag | Description |
|---|---|
--account <id> | Override default ad account |
--preset <id> | Use a saved API preset (alternative to spec file) |
--text-preset <id> | Load a saved text preset |
--copy-from <adId> | Copy settings from an existing ad |
--upload <batchId> | Specify the upload batch ID |
--status <PAUSED|ACTIVE> | Set ad status (default: ACTIVE) |
--pause-at <level> | Pause level: ad (default), adSet, or campaign |
--daily-budget <amount> | Override daily budget per ad set (currency units, e.g. 50 for $50) |
--bid-amount <amount> | Override bid/cost cap per ad set (currency units) |
--text-file <path> | Load text configuration from a JSON file |
Browse Flags
These flags are available on campaigns, adsets, adset, and campaign:
| Flag | Description |
|---|---|
--status <status> | active (default) or all |
--inactive | Shorthand for --status all (on campaigns) |
--search <text> | Filter by name (on campaigns, adsets) |
Common Flags
| Flag | Description |
|---|---|
--account <id> | Override default ad account for any command |
--json | Output raw JSON (available on most commands, intended for scripting) |
Spec File Format
The JSON spec file controls every aspect of ad creation. Only two fields are required: a template source (adPresetId or copyFromAd) and uploadId.
Minimal Spec
{
"adPresetId": "your_preset_id",
"uploadId": "batch_abc123"
}
Full Example
{
"adPresetId": "preset_id_here",
"uploadId": "batch_abc123",
"adSet": {
"name": "My New Ad Set",
"dailyBudget": 50
},
"adNamePattern": "{filename}",
"texts": {
"perAd": {
"hero.jpg": {
"headlines": ["Main Headline"],
"bodies": ["Ad copy here."],
"descriptions": ["Short description"],
"cta": "SHOP_NOW",
"link": "https://example.com/landing"
}
}
},
"creativeEnhancements": "none",
"options": {
"status": "PAUSED",
"pauseAt": "adSet"
}
}
Template Source
You need one of these to tell the CLI which ad configuration to use as a base.
| Field | Description |
|---|---|
adPresetId | A saved API preset ID. Locks in the campaign, ad set, and ad config. |
copyFromAd | A Facebook ad ID to copy settings from. |
When using copyFromAd, provide the upload batch and optionally the campaign and ad set:
{
"copyFromAd": "120233848667930472",
"uploadId": "batch_abc123",
"campaign": { "id": "120233848666410472" },
"adSet": { "id": "120233848666620472" }
}
To find the right ad ID, drill through your account: ads campaigns then ads campaign <id> then ads adset <id> then ads ad <id>.
Campaign Structure
By default, ads go into the template ad's campaign. You can create a new campaign by providing campaign.name.
For multi-campaign modes, use campaign.mode with a campaigns array:
{
"campaign": {
"mode": "duplicate",
"campaigns": [
{ "name": "Campaign A" },
{ "name": "Campaign B" }
]
}
}
| Mode | Behavior |
|---|---|
"single" | Default. One campaign. |
"duplicate" | All media is duplicated into each campaign. |
"split" | Media is split evenly across campaigns. |
Ad Set Modes
By default, ads go into the template ad's existing ad set. The following modes give you control over how ads are distributed across ad sets.
Create a new ad set:
{ "adSet": { "name": "My Ad Set" } }
Use an existing ad set by ID:
{ "adSet": { "id": "120233848666620472" } }
One ad set per uploaded file:
{ "adSet": { "mode": "perUpload" } }
Auto-group into ad sets of a fixed size:
{ "adSet": { "mode": "autoGroup", "adsPerAdSet": 5 } }
Custom groups with full control over which files go where:
{
"adSet": {
"groups": [
{ "name": "Images - April 10", "media": ["hero.jpg", "banner.jpg"] },
{ "name": "Videos - April 10", "media": ["promo.mp4"] }
]
}
}
Ad set naming pattern for multi-ad-set modes:
{ "adSet": { "mode": "perUpload", "namePattern": "Ad Set {index:01}" } }
Variant grouping groups ads by variation identifier into the same ad set:
{ "adSet": { "mode": "autoGroup", "groupVariations": true, "variationIdentifier": "-" } }
Budget and Bid Override
Override the daily budget or bid amount on new ad sets. Values are in your account's currency units (e.g. 50 for $50 or 50 euros). Only one can be set at a time.
{ "adSet": { "dailyBudget": 50 } }
{ "adSet": { "bidAmount": 5 } }
Also available as CLI flags: --daily-budget 50 or --bid-amount 5.
Text Configuration
Common text applies the same copy to all ads:
{
"texts": {
"common": {
"headlines": ["Headline 1", "Headline 2"],
"bodies": ["Primary text"],
"descriptions": ["Description"]
},
"strategy": "flexible"
}
}
Per-ad text lets you set unique copy for each file:
{
"texts": {
"perAd": {
"hero.jpg": {
"headlines": ["Hero Headline"],
"bodies": ["Hero copy"],
"descriptions": ["Hero desc"],
"cta": "LEARN_MORE",
"link": "https://example.com/hero",
"urlTags": "utm_content=hero"
},
"banner.jpg": {
"headlines": ["Banner Headline"],
"bodies": ["Banner copy"]
}
}
}
}
Per-ad keys are filenames (not full paths). Each entry supports: headlines, bodies, descriptions, cta, link, displayUrl, urlTags. Fields you don't specify inherit from the template ad.
Text presets let you load a saved text configuration:
{ "textPresetId": "preset_id_here" }
You cannot combine textPresetId with texts.
Strategy options control how multiple text variations are handled:
"flexible"(default) lets Meta optimize across your text variations. Multiple headlines and bodies become options that Facebook mixes and matches."separate"creates a separate ad for each text combination.
CTA and Links
A top-level CTA applies to all ads. Per-ad CTAs in texts.perAd override it.
{
"cta": {
"type": "SHOP_NOW",
"link": "https://example.com",
"displayUrl": "example.com"
},
"urlTags": "utm_source=facebook&utm_medium=paid"
}
Standard CTA types: LEARN_MORE, SHOP_NOW, SIGN_UP, SUBSCRIBE, GET_OFFER, CONTACT_US, DOWNLOAD, ORDER_NOW, BUY_NOW, BOOK_NOW, APPLY_NOW, GET_QUOTE, GET_IN_TOUCH, WATCH_MORE
Objective-specific CTAs are inherited from the template ad and should not be set manually. Setting these on the wrong campaign type will cause a Facebook API error.
| CTA | Required Campaign Objective |
|---|---|
MESSAGE_PAGE | Messenger destination |
WHATSAPP_MESSAGE | WhatsApp destination |
INSTAGRAM_MESSAGE | Instagram DM destination |
CALL_NOW | Call campaign |
Creative Enhancements
Control Advantage+ creative enhancements:
{ "creativeEnhancements": "none" }
| Value | Effect |
|---|---|
"metaDefaults" | Let Meta decide (default if omitted) |
"all" | All features on |
"none" | All features off |
["feature1", "feature2"] | Only listed features on, rest off |
Available features: text_translation, inline_comment, enhance_cta, text_optimizations, reveal_details_over_time, image_brightness_and_contrast, image_touchups, video_auto_crop, video_filtering, image_animation, image_templates, adapt_to_placement, product_extensions, description_automation, add_text_overlay, music, carousel_to_video, carousel_dynamic_description, multi_share_end_card, multi_share_optimized
When cherry-picking features, only list ones relevant to the media type. Video features (video_auto_crop, video_filtering) only apply to video ads. Carousel features (carousel_to_video, carousel_dynamic_description, multi_share_end_card, multi_share_optimized) only apply to carousel ads.
Carousel Ads
Group uploaded files into carousel ads with per-card text:
{
"carousel": [
{
"name": "My Carousel",
"cards": ["slide1.jpg", "slide2.jpg", "slide3.jpg"],
"cardTexts": [
{ "headline": "Slide 1", "description": "First card", "link": "https://example.com/1" },
{ "headline": "Slide 2", "description": "Second card", "link": "https://example.com/2" }
]
}
]
}
Cards must reference filenames from the upload batch. Minimum 2 cards per carousel. Files claimed by a carousel are removed from the standard ad list.
Flexible Ads
Group multiple assets into a single flexible ad where Meta picks the best asset per placement:
{
"flexible": [
{
"name": "Multi-Asset Ad",
"assets": ["hero.jpg", "promo.mp4", "banner.jpg"]
}
]
}
Minimum 2 assets per group. Files claimed by a flexible group are removed from the standard ad list.
Ad Naming
Customize how your ads are named:
{ "adNamePattern": "{filename} - {date}" }
| Placeholder | What it inserts |
|---|---|
{filename} | Original filename without extension |
{index:01} | Zero-padded index (01, 02, 03...) |
{variation} | Variation identifier if variant grouping is on |
{campaign} | Campaign name |
{date} | Current date (YYYY-MM-DD) |
{date:short} | Short date (MM-DD) |
{timestamp} | Unix timestamp |
Options
{
"options": {
"status": "PAUSED",
"pauseAt": "adSet",
"schedule": {
"startTime": "2026-04-01T09:00:00",
"endTime": "2026-04-30T23:59:59"
}
}
}
| Field | Values | Description |
|---|---|---|
status | "PAUSED", "ACTIVE" | Ad launch status (default: ACTIVE) |
pauseAt | "ad", "adSet", "campaign" | Which level to pause at (default: ad) |
schedule.startTime | ISO 8601 string | Scheduled start time (uses ad account timezone) |
schedule.endTime | ISO 8601 string | Scheduled end time (optional) |
Upload and Variant Detection
Variant groups are detected automatically from filename conventions, just like in the web application. See Aspect Ratio Variations for full details on naming conventions.
Ratio suffixes: hero_4x5.jpg + hero_9x16.jpg + hero_16x9.jpg are grouped as one variant ad.
Word suffixes: hero.jpg + hero_vertical.jpg + hero_horizontal.jpg are grouped as one variant ad.
Both _ and - delimiters work. A file without a ratio suffix (e.g. hero.jpg) only groups with _vertical/_horizontal variants. For ratio-based grouping, all files need ratio suffixes.
Common Patterns
Upload and create with a preset
ads upload ./creatives/hero.jpg ./creatives/banner.jpg
ads create:preview spec.json
ads create spec.json
Where spec.json contains:
{ "adPresetId": "PRESET_ID", "uploadId": "BATCH_ID" }
Copy settings from an existing ad
Browse your account to find the ad:
ads campaigns
ads campaign 120233848666410472
ads adset 120233848666620472
ads ad 120233848667930472
Then create a spec referencing it:
{
"copyFromAd": "120233848667930472",
"uploadId": "BATCH_ID"
}
Per-ad text with unique copy per file
{
"adPresetId": "PRESET_ID",
"uploadId": "BATCH_ID",
"texts": {
"perAd": {
"hero.jpg": {
"headlines": ["Summer Sale Now On"],
"bodies": ["Save up to 50% on all items"],
"cta": "SHOP_NOW",
"link": "https://example.com/summer"
},
"banner.jpg": {
"headlines": ["New Collection Available"],
"bodies": ["Browse our latest styles"],
"cta": "LEARN_MORE",
"link": "https://example.com/new"
}
}
}
}
Auto-group into multiple ad sets
{
"adPresetId": "PRESET_ID",
"uploadId": "BATCH_ID",
"adSet": { "mode": "autoGroup", "adsPerAdSet": 3 }
}
Important Notes
- Always preview first.
create:previewcatches config errors before touching Facebook. - Ads are active by default. Use
--status PAUSEDor"status": "PAUSED"in the spec to create them paused. uploadIdcomes from the upload output. It is the batch ID returned byads upload.- Uploads are tied to an ad account. Files are uploaded directly to the selected account's Facebook media library. The batch ID can only be used with the same account.
copyFromAdneedsuploadId. You must provide the upload batch. Optionally providecampaign.idandadSet.idto control placement.- Per-ad text keys are filenames. Use
"hero.jpg", not"/path/to/hero.jpg". textPresetIdandtextsare mutually exclusive. Use one or the other, not both.- Objective-specific CTAs are inherited from the template. Do not set
MESSAGE_PAGE,WHATSAPP_MESSAGE, etc. manually.