Back to The Vault
Pillar · Meta Ads OS
02

The Bulk Uploader

Launch 50+ Meta ads in 20 minutes without touching Ads Manager.

Published June 23, 2026 · 14 min read

A man named Marcus runs a DTC skincare brand out of a converted garage in Scottsdale, Arizona. Every Tuesday, he sits down with a coffee, opens Meta Ads Manager, and spends the next three hours uploading creatives one at a time. Click “Create.” Select campaign. Select ad set. Upload image. Paste headline. Paste primary text. Set CTA. Click “Publish.” Repeat.

Three hours. Every week. For eight ads.

Last month Marcus switched to a Google Sheet and an automation workflow. He fills in one row per ad: headline, primary text, image file, CTA, targeting. Then he clicks a button. The workflow reads every row, creates the campaigns, ad sets, and ads, uploads the creatives, and publishes them. All of them. At once.

His three-hour Tuesday became a 20-minute Tuesday. The rest of his morning is now spent doing things that actually grow his business, like figuring out which of those 50 ads is going to make him money.

This is the playbook for that system. Two versions: the free DIY route (Google Sheets + n8n + Meta’s API) and the fast-but-paid route (SaaS tools that do it for you). Pick whichever matches your comfort level and budget.


Why Bulk Uploading Matters More Than You Think

If you built the Static Ads Engine from Pillar 1, you now have a folder full of ad creatives. Maybe 32 variations, maybe 64. Each one is a specific hypothesis about what hook, persona, and style combination will convert.

Now you need to get them into Meta Ads Manager. And this is where most people’s systems fall apart.

The manual upload process in Ads Manager is designed for someone launching 3-5 ads. Not 50. Not 100. If you’re uploading 50 ads by hand, you’re spending your entire afternoon on data entry. You’ll make typos. You’ll paste the wrong headline on the wrong creative. You’ll forget to set the UTM on ad #37 and not notice until you’re trying to figure out why your attribution is broken two weeks later.

Bulk uploading fixes all of this. You define your ads in a structured spreadsheet where every field is visible and reviewable. Then you push the whole batch to Meta in one operation. Consistent naming conventions. Consistent UTMs. Consistent targeting. Zero copy-paste errors.

The second reason this matters: speed of testing. The faster you can launch creative tests, the faster you find winners. An advertiser who tests 50 creatives a week will find winning angles three to four times faster than someone testing 8. Over a quarter, that’s the difference between a profitable ad account and one that’s still “figuring things out.”


Path A: The Free Route (Google Sheets + Composio MCP + Claude Code)

This is the zero-monthly-cost option. It requires more setup time (about 60-90 minutes the first time), but once it’s running, it’s free forever. You’ll use three tools: Google Sheets (your ad management dashboard), Composio (the bridge that connects Claude Code to Meta’s API), and Claude Code (the brain that orchestrates everything).

What You Need

  1. Claude Code installed with a Pro or Max subscription (same as Pillar 1)
  2. A Composio account (free tier available at composio.dev)
  3. A Meta Business account with an active Ad Account
  4. A Google account for Sheets and Drive
  5. Your ad creatives already generated (from Pillar 1 or elsewhere), uploaded to your Meta Ads Creative Library

Step 1: Set Up Composio and Connect Your Meta Ads Account

Composio is a service that handles the painful OAuth authentication between Claude Code and Meta’s API. Without it, you’d need to create a Facebook Developer App, generate access tokens, manage token refresh, and deal with Meta’s permission scopes. Composio does all of that for you.

Go to composio.dev and create a free account. From the dashboard, find “Metaads” in the toolkit catalog and click “Connect.” You’ll be redirected to Facebook’s login screen. Log in, select the ad account you want to connect, and approve the permissions.

Back in the Composio dashboard, you’ll see your connection is active. Now grab two things:

  • Your Composio API key (found in the dashboard under API Keys)
  • Your MCP URL (shown on the Metaads toolkit page after connection)

Step 2: Add the Composio MCP Server to Claude Code

Open your terminal and run:

claude mcp add --transport http metaads-composio "YOUR_MCP_URL_HERE" --headers "X-API-Key:YOUR_COMPOSIO_API_KEY"

Then restart Claude Code:

exit
claude

Verify it worked:

claude mcp list

You should see metaads-composio in the list. Claude Code can now talk directly to your Meta Ads account: creating campaigns, ad sets, and ads; uploading creatives; pulling performance data; pausing underperformers. All through natural language.

If you see an error: Make sure you copied the MCP URL and API key exactly. No trailing spaces. The URL should start with https://. If you’re still stuck, run claude mcp remove metaads-composio and try the add command again.

Step 3: Create the Bulk Upload Spreadsheet Template

This is the spreadsheet that will serve as your ad management dashboard. Every row is one ad. Every column is one field that Meta needs.

In Claude Code, type:

Create a Google Sheets template for bulk uploading Meta ads. The sheet should 
have these columns:

A: campaign_name (string, your campaign naming convention)
B: campaign_objective (OUTCOME_TRAFFIC, OUTCOME_LEADS, OUTCOME_SALES, etc.)
C: daily_budget (number in cents, e.g., 2000 = $20/day)
D: adset_name (string)
E: targeting_age_min (number, 18-65)
F: targeting_age_max (number, 18-65)
G: targeting_genders (1=male, 2=female, 0=all)
H: targeting_interests (comma-separated interest IDs)
I: optimization_goal (LINK_CLICKS, LANDING_PAGE_VIEWS, CONVERSIONS, etc.)
J: ad_name (string, should match your creative matrix concept name)
K: headline (string, 40 chars max recommended)
L: primary_text (string, the main ad copy)
M: description (string, optional link description)
N: creative_asset_id (the ID from your Meta Creative Library)
O: call_to_action (LEARN_MORE, SHOP_NOW, SIGN_UP, GET_OFFER, etc.)
P: destination_url (the landing page URL)
Q: utm_source (default: facebook)
R: utm_medium (default: paid)
S: utm_campaign (auto-populated from campaign_name)
T: utm_content (auto-populated from ad_name)
U: status (PAUSED or ACTIVE, default PAUSED for safety)
V: upload_result (blank, will be filled by the workflow)

Include a header row with these exact column names. Add 5 example rows 
using a fictional supplement brand as the example data. Set all example 
ads to PAUSED status.

Save this as a downloadable CSV template and also provide the Google Sheets 
link format.

Claude will generate the template. Copy it into a new Google Sheet in your Drive.

Pro tip on naming conventions: Use a consistent pattern like [brand]_[objective]_[hook]_[persona]_[date]. For example: vitapure_conversions_problem_sarah_20260501. This isn’t just organizational hygiene. When you pull performance reports later, consistent naming lets Claude parse which hooks and personas are winning without you manually tagging anything.

Step 4: Fill In Your Ads

Now comes the part that replaces three hours of manual uploading with 20 minutes of spreadsheet work.

If you ran the Static Ads Engine from Pillar 1, you already have a creative-matrix.json file with all your ad concepts defined. You can have Claude Code populate the spreadsheet automatically:

Read my creative-matrix.json and populate the bulk upload spreadsheet with 
one row per ad concept. Use these defaults:

- campaign_objective: OUTCOME_SALES
- daily_budget: 1000 (= $10/day per ad set)
- targeting: [describe your target audience]
- optimization_goal: CONVERSIONS
- destination_url: [your landing page URL]
- call_to_action: SHOP_NOW
- status: PAUSED

For each row, pull the headline and primary_text from the creative matrix. 
Set the ad_name to match the concept_name from the matrix.

Leave creative_asset_id blank for now. I'll add those after uploading 
images to my Meta Creative Library.

This gives you a complete spreadsheet in seconds. Review it, tweak any headlines or copy you want to adjust, and add the creative asset IDs (you’ll get these from your Meta Ads Creative Library after uploading your images).

How to get your creative asset IDs: Go to Meta Ads Manager, click “All Tools,” then “Media Library.” Upload your images there. After each upload, click on the image and look for the “Asset ID” in the details panel. Copy that ID into column N of your spreadsheet for the matching ad.

Step 5: Run the Bulk Upload

This is the moment. Your spreadsheet is filled in. Your creatives are in Meta’s library. Time to push everything live.

In Claude Code:

Read the bulk upload spreadsheet at [Google Sheets URL or local CSV path].

For each row:
1. Create the campaign if it doesn't already exist (check by campaign_name)
2. Create the ad set under that campaign if it doesn't already exist
3. Create the ad with the specified creative, headline, primary text, CTA, 
   and destination URL
4. Append UTM parameters to the destination URL
5. Set the ad status to whatever's in column U (should be PAUSED)
6. Write the result (success or error message) back to column V

Process rows in order. After every 10 rows, show me a progress summary 
with any errors.

Do NOT set any ads to ACTIVE. Keep everything PAUSED so I can review 
in Ads Manager before going live.

What you should see: Claude reads each row, calls the Meta API through Composio, and creates the ad objects. For each row, you get a confirmation or an error message written back to column V. A batch of 50 ads takes about 5-10 minutes.

Common errors and fixes:

  • “Invalid creative asset ID”: The image hasn’t finished processing in Meta’s library. Wait 5 minutes and retry.
  • “Invalid targeting spec”: One of your interest IDs is wrong. Use Meta’s targeting search (in Ads Manager, create a manual ad set and search for your interests to find the correct IDs).
  • “Budget too low”: Meta requires a minimum daily budget (usually $1/day per ad set, but varies by country and objective). Increase your budget value.
  • “Duplicate campaign name”: Claude found an existing campaign with that name. It should skip creation and use the existing one, but if it errors, rename your campaign in the sheet.

Step 6: Review and Activate

Go to Meta Ads Manager. You should see all your campaigns, ad sets, and ads sitting in PAUSED status. Click through a few to verify: correct headlines, correct images, correct URLs, correct UTMs.

When you’re satisfied, you can activate them in two ways:

Option 1 (in Ads Manager): Select all the ads you want to launch, click “Actions,” and “Turn On.”

Option 2 (in Claude Code):

Activate all ads in campaigns matching the pattern "vitapure_conversions_*" 
that are currently PAUSED. Confirm the total count before activating.

Claude will count the ads, show you the total, and ask for confirmation before flipping them live.


Path B: The Fast Route (SaaS Tools)

If the Composio/Claude Code setup feels like too much, there are paid tools that handle bulk uploading with a simpler interface. Here’s what’s available as of April 2026, with honest verdicts.

Markifact (Free Template + n8n Workflow)

Markifact offers a pre-built Google Sheets template plus an n8n workflow that pushes ads to Meta via the Marketing API. The template is clean, the column structure is well thought out, and the workflow handles campaign creation, ad set creation, and ad creation in sequence. It also supports video ads with a separate node.

Cost: The template and workflow are free. n8n’s self-hosted version is free. n8n Cloud starts at $24/mo if you don’t want to self-host.

Best for: People comfortable with n8n’s visual workflow builder who want a battle-tested template they don’t have to build from scratch.

Caveat: You still need to set up Meta API credentials (Facebook Developer App, access token). Markifact’s docs walk you through it, but it’s the same OAuth pain that Composio eliminates. Budget 30-45 minutes for first-time setup.

How to get started: Go to markifact.com/templates/meta-ads-bulk-uploader. Copy the Google Sheet template. Import the n8n workflow JSON. Follow their setup guide for connecting your Meta API credentials.

Ads Uploader ($59/mo)

A dedicated SaaS tool built specifically for bulk Meta ad uploads. Clean interface, drag-and-drop creative assignment, built-in CSV import.

Cost: $59/mo flat.

Best for: Agencies or heavy advertisers who upload 100+ ads per week and want the fastest possible path from spreadsheet to live campaign.

Honest assessment: It works well, but $59/mo adds up to $708/year. If you’re spending less than $3K/mo on Meta ads, the ROI is questionable. The free Composio route gets you the same result for $0/mo after setup.

Kitchn.io

Supports Meta, TikTok, and Snapchat bulk uploads. One agency reported going from 250 to 1,200 ads per month after adopting it.

Cost: Pricing varies by volume, starts around $99/mo.

Best for: Multi-platform advertisers who also run TikTok and Snapchat campaigns and want one tool for all three.

Adacted ($99 one-time)

A self-hosted bulk uploader tool. Pay once, own it forever.

Cost: $99, one-time.

Best for: Budget-conscious advertisers who want to avoid monthly fees and don’t mind a slightly less polished interface.

Meta’s Native Bulk Upload (Free, but Manual)

Meta Ads Manager has a built-in CSV upload feature. Download the template from Ads Manager (“Bulk Import” under the “Ads” tab), fill it in, upload. Free.

Cost: $0.

Best for: Someone who needs bulk upload once and doesn’t want to set up any tools.

Honest assessment: The CSV format is confusing. The column names don’t match what you see in the UI. Error messages are cryptic. It works, but it’s not pleasant, and there’s no automation. Every upload is manual.

Which Route Should You Pick?

Here’s the decision framework:

If you already have Claude Code running from Pillar 1, use Path A (Composio). The marginal effort to add the MCP server is small, and you get a system that stays free and integrates with everything else in this playbook.

If you don’t want to touch a terminal and you upload fewer than 20 ads per week, use Markifact’s template with n8n. Visual workflow builder, no code, free.

If you’re an agency uploading hundreds of ads per week across multiple clients, use Ads Uploader or Kitchn.io. The monthly fee pays for itself in time saved.

If you’re testing this for the first time and just want to see if bulk uploading is for you, use Meta’s native CSV import. It’s ugly, but it’s free and requires zero setup.


The Automation Loop: Connecting Pillar 1 to Pillar 2

Here’s where this gets powerful. If you’ve built both the Static Ads Engine (Pillar 1) and this Bulk Uploader (Pillar 2), you can chain them together into a single workflow.

In Claude Code:

Build me a weekly ad refresh workflow that does the following:

1. Read my latest creative-matrix.json
2. Generate 16 new ad variations using Nano Banana 2 (4 hooks x 4 personas, 
   minimal style only, 1K resolution)
3. Upload the generated images to my Meta Ads Creative Library
4. Populate a new bulk upload spreadsheet with one row per ad
5. Create the campaigns, ad sets, and ads via Composio, all set to PAUSED
6. Send me a summary of what was created

Save this as a reusable Claude Code skill called "weekly-ad-refresh"

Now every week, you type /weekly-ad-refresh and Claude generates fresh creatives, uploads them, creates the ads, and hands you a summary. Your only job is reviewing and activating.

That’s the system. From concept to live ad in under 30 minutes, every week, for the cost of a few API calls.


Advanced: Building a Naming Convention That Feeds Your Analytics

This section is optional but highly recommended. If you set up your naming conventions correctly now, every future pillar in this series becomes easier.

The naming pattern that works best for automated analytics:

[brand]_[objective]_[hook-type]_[persona]_[style]_[version]_[date]

Example:

vitapure_sales_problem_sarah_minimal_v1_20260501

Why this matters: When you build the Creative Analytics system in Pillar 3 (replacing Motion app), Claude will parse your ad names to automatically identify which hooks, personas, and styles are winning. If your names are ad1, ad2, ad3, you’ll need to manually tag everything. If they follow this pattern, the analysis is automatic.

Set this convention in your brand-kit.md:

Add the following naming convention to my brand-kit.md:

AD NAMING CONVENTION:
Pattern: [brand]_[objective]_[hook]_[persona]_[style]_[version]_[date]
- brand: vitapure (always lowercase, no spaces)
- objective: sales | traffic | leads
- hook: problem | benefit | social | curiosity
- persona: sarah | marcus | dana | jordan (from creative matrix)
- style: minimal | lifestyle
- version: v1, v2, v3
- date: YYYYMMDD

Example: vitapure_sales_problem_sarah_minimal_v1_20260501

This convention must be used for all campaign names, ad set names, and ad 
names. The bulk upload spreadsheet should auto-generate names from these 
components.

The Downloadable Artifacts

This pillar comes with two files:

  1. bulk-upload-template.csv: The complete spreadsheet template with all 22 columns, example data, and built-in validation notes. Drop it into Google Sheets and start filling in your ads.
  2. bulk-uploader-skill.md: A Claude Code skill file that handles the entire upload workflow, including error handling, progress reporting, and result logging. Drop it into .claude/skills/ and run /bulk-upload to execute.

Both are in the Vault downloads section.


What This System Will Not Do

It will not fix bad ads. If your creatives are weak, uploading them faster just burns money faster. This is a distribution tool, not a strategy tool. Use the Static Ads Engine (Pillar 1) and the Impressions Spy (Pillar 5) to make sure you’re uploading things worth running.

It will not manage your budget. You still need to set daily budgets, bid strategies, and optimization goals intelligently. Bulk uploading lets you test more, but you need a budget allocation strategy to go with it.

It will not replace Ads Manager entirely. You’ll still use Ads Manager for monitoring performance, adjusting bids, and reading delivery diagnostics. The bulk uploader replaces the creation workflow, not the management workflow. (Pillar 3, Creative Analytics, handles the management side.)


Quick Reference: Route Comparison

RouteSetup timeMonthly costBest for
Composio + Claude Code60-90 min first time, then instant$0Anyone already using Claude Code
Markifact + n8n30-45 min$0 (self-hosted) or $24/mo (cloud)Visual workflow builders
Ads Uploader10 min$59/moHigh-volume agencies
Kitchn.io15 min~$99/moMulti-platform (Meta + TikTok + Snap)
Meta native CSV5 min$0One-off uploads

What’s Next

You’ve got the production engine (Pillar 1) and the distribution engine (Pillar 2). The next piece is knowing whether your ads are actually working.

Pillar 3: Creative Analytics shows you how to replace Motion app ($250/mo) with a free Claude Code build using Windsor MCP. You get automated creative tagging, win-rate analysis, kill/scale recommendations, and iteration suggestions for underperformers. All pulling from your live Meta Ads data.

If you set up the naming conventions from this guide, Pillar 3’s analytics will automatically parse your hook types, personas, and styles. The system compounds.

[CTA: Read Pillar 3: Creative Analytics] | [CTA: Browse the Vault]


Continue building the system.

← Back to The Vault