New: AI voiceover + auto-captions - script to captioned video in one API call. Read the announcement

Guides

Social Media Video Automation: Batch-Render Ad Variants

TikTok suggests 3-5 creatives per ad group across 3-5 ad groups, so up to 25 videos. We rendered variants of one 9:16 template in 13 to 19 seconds each.

Phil Duong

Phil Duong

Founder

Social Media Video Automation: Batch-Render Ad Variants

Your media buyer wants more creative. TikTok's own guidance says a single campaign should carry 3 to 5 creatives per ad group across 3 to 5 ad groups, which is up to 25 videos. For one campaign. This month.

Nobody hand-edits 25 vertical videos for one offer. So the usual answer is an AI video generator, and that answer quietly breaks the thing you were trying to do.

Here's what social media video automation looks like when the goal is a creative test: one template, a variable matrix, and a batch render. I built it against a live 9:16 flash-sale template, rendered four real variants, timed them, and hit a failure that has nothing to do with rendering. All the numbers below are measured, and the prop files are reproducible.

Key Takeaways

  • TikTok suggests "3-5 different creatives per ad group and 3-5 diversified ad groups per campaign" (TikTok Ads), so 9 to 25 videos for one campaign.
  • Four variants of the same 20-second 9:16 template rendered in 13 to 19 seconds each. The renders finish faster than the videos play.
  • 25 variants costs 12.5 credits, about $1.21. The batch is not the expensive part.
  • The real failure mode is copy length, not rendering. A longer replacement value clipped inside a fixed-size text box and the render still reported success.

What social media video automation actually means

Two very different jobs share this name, and picking the wrong one wastes a week. Automation here means assembling a fixed layout from swapped values, not generating new footage. The layout, timing, and animation stay identical across every output. Only the values you nominate change.

That distinction decides which job you're doing. One job is many variants of one offer, for creative testing on paid social. That's this post. The other job is one video per item in a catalog, which is a different shape of problem covered in our guide to e-commerce product video automation. Same machinery, different unit of work.

The example throughout is a real template: Black Friday / Flash Sale Countdown, a five-scene 1080x1920 composition running 20 seconds at 30fps. It carries 92 overlays. Twenty-nine of them are marked replaceable, driven by 12 named variables.

How many ad variants do you actually need?

TikTok publishes the number. Its creative best practices for performance ads state: "We suggest between 3-5 different creatives per ad group and 3-5 diversified ad groups per campaign" (TikTok Ads Help Center, retrieved 2026-08-20). Multiply the low end and you get 9 videos. Multiply the high end and you get 25.

Videos Needed Per Campaign Under TikTok's Own GuidanceHorizontal bar chart showing the number of video creatives a single TikTok campaign requires under TikTok's published recommendation of 3 to 5 creatives per ad group across 3 to 5 ad groups: 9 videos at the low end (3 by 3), 16 in the middle (4 by 4), and 25 at the high end (5 by 5). Source: TikTok Ads Help Center, creative best practices for performance ads, retrieved August 2026.Videos Needed Per CampaignTikTok suggests 3-5 creatives per ad group, across 3-5 ad groups010203 x 3 groups94 x 4 groups165 x 5 groups25Source: TikTok Ads Help Center, creative best practices, retrieved August 2026

Meta says something similar on the other platform, and it's worth quoting with its scope intact. In its best practices for Advantage+ app campaigns, Meta writes: "You can add up to 50 images or videos at one time. In order to maintain the best performance for your ads, we recommend that you upload a high volume of creative assets and refresh them a few times a month to avoid creative fatigue" (Meta Business Help Center, retrieved 2026-08-20). That guidance is written for app campaigns, not as a blanket rule, but the instruction is the same one TikTok gives.

Both platforms tell you to ship volume and refresh it. Neither tells you how to produce it. TikTok also has a preference about how you refresh: "add new creatives to an existing ad group instead of creating a new ad group to extend its lifetime." So the volume isn't a one-time build. It's a standing supply problem.

Why AI generation breaks a creative test

A creative test only works if every variant is identical except the one thing you're testing. Change the offer and the footage and the pacing at once, and a winning variant tells you nothing you can act on. You've learned that one specific video worked, not why.

This is where generation and testing pull against each other. Ask a generator for 25 videos and you get 25 videos that differ in every dimension. The result isn't a test, it's a lottery with a bigger ticket count. You can still find a winner, but you can't extract a rule from it, so next month you start over.

Template assembly inverts that. The 63 static overlays in our example can't drift, because nothing in the pipeline touches them. The 29 replaceable fields change only where you name them. Isolation isn't a discipline you have to maintain, it's a property of the file. That's the whole argument for template-based video over AI-generated video when the goal is a readable test rather than a pile of assets.

Step 1: Pick the variable you're testing

The template's variable contract is the test plan. Twelve named keys, each mapping to one testable idea:

KeyDefaultOverlays it updatesWhat it tests
sale_nameBLACK FRIDAY6Brand frame
store_nameNorthfield Supply6Brand frame
deadline_labelENDS MIDNIGHT SUNDAY6Urgency
discount_value40%2Offer
time_remaining48 HOURS LEFT2Urgency
discount_scopeOFF EVERYTHING1Offer
urgency_lineWhen it's gone, it's gone.1Urgency
product_imagehero image URL1Creative
promo_codeFLASH401Attribution
cta_labelSHOP NOW1Call to action
cta_detailnorthfieldsupply.com/bf1Call to action
terms_noteDiscount applied at checkout1Compliance

Look at the third column. Three of those 12 keys each write to six different overlays, spread across all five scenes. Change deadline_label once and every scene updates together.

How 12 Variables Write 29 Overlay FieldsDonut chart breaking down the 29 replaceable overlay fields in the flash-sale template by the variables that drive them: three repeated keys (sale name, store name, deadline label) account for 18 fields, two keys account for 4 fields, and seven single-use keys account for 7 fields. Source: props file for the Black Friday flash-sale template, August 2026.12 Variables Write 29 Overlay FieldsOne value change can update six overlays across five scenes29fields3 repeated keys, 6 overlays each: 182 keys, 2 overlays each: 47 single-use keys: 7Source: Renderly template props, August 2026

That fan-out is why a declared variable contract beats find-and-replace on a script. With find-and-replace, six occurrences are six chances to leave one stale, and a stale deadline in scene four is the kind of thing nobody catches until a customer does.

For a test matrix, combine axes rather than listing videos. Two offers, times two urgency framings, times two calls to action, is 8 variants. Add three hero images and you're at 24, right inside TikTok's recommended band.

Step 2: Build the matrix and send it

The render request takes nine fields, and replacements is the one that matters here. You pass templateId plus a replacements object keyed by variable name, and every replaceable overlay carrying that name picks up the new value.

const OFFERS = [
  { discount_value: "40%", discount_scope: "OFF EVERYTHING", promo_code: "BF40" },
  { discount_value: "$50", discount_scope: "OFF SITEWIDE",   promo_code: "BF50" },
];
const URGENCY = [
  { deadline_label: "ENDS MIDNIGHT SUNDAY", time_remaining: "48 HOURS LEFT" },
  { deadline_label: "ENDS TONIGHT",         time_remaining: "6 HOURS LEFT" },
];
const CTAS = [{ cta_label: "SHOP NOW" }, { cta_label: "SHOP THE SALE" }];
 
for (const offer of OFFERS) {
  for (const urgency of URGENCY) {
    for (const cta of CTAS) {
      await fetch("https://renderly.video/api/v1/renders", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.RENDERLY_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          templateId: "black-friday-flash-sale-countdown",
          replacements: { ...offer, ...urgency, ...cta },
        }),
      });
    }
  }
}

Eight variants, one nested loop. The API also accepts replacement keys at the top level. So { templateId, discount_value: "40%" } does the same thing as nesting them, which helps when you're mapping a spreadsheet column onto a request.

Register a webhook endpoint once with POST /api/v1/webhooks and let completions come to you. Skip the per-render webhookUrl for batch work. It's signed with a constant rather than your secret, carries no delivery id, and isn't retried. It can't support the idempotency a 25-render batch needs. The full setup is in our guide to video rendering webhooks.

Prefer not to write the loop? The Zapier integration and Make.com both drive the same endpoint from a spreadsheet. A variant matrix is genuinely easier as a loop, though. Nested combinations are what code is good at.

Step 3: Know what the batch costs

A 20-second 1080x1920 render costs 0.5 credits. Twenty-five of them is 12.5 credits, which is about $1.21 on the $29 Creator plan. Rendering is not the expensive part of creative testing. It stopped being the expensive part a while ago.

One honest wrinkle in our own favor and against it: credits round up to the nearest half. A 20-second video is 0.33 minutes of output, but it bills as 0.5. Short vertical assets therefore pay a premium against our headline per-minute rate, which narrows the gap to vendors that meter by the second.

Cost of a 25-Variant Batch (8.33 Output Minutes)Lollipop chart comparing the entry-plan cost of rendering 25 twenty-second vertical ad variants, which is 8.33 minutes of output, across five programmatic video APIs: Renderly at $1.21, Shotstack at $1.67, JSON2Video at $2.08, Creatomate at $7.00, and Plainly at $11.50. Source: vendor pricing pages, verified August 2026.Cost of a 25-Variant Batch25 renders at 20 seconds each, so 8.33 minutes of output, on entry plansRenderlyShotstackJSON2VideoCreatomatePlainly$1.21$1.67$2.08$7.00$11.50Source: vendor pricing pages, verified August 2026

Now price it as a habit instead of a one-off, because that's how both platforms describe it. TikTok says to refresh "when delivery results exhibit a consistently declining trend," and Meta's app-campaign guidance says a few times a month. Call it two batches of 25 monthly: 25 credits, roughly $2.42, on a $29 plan that includes 300. The credits stop being the constraint almost immediately.

What replaces them as the constraint is copy. Fifty variants a month means fifty sets of values that all have to be written, checked, and kept truthful about the actual offer. That's the work the render pipeline hands back to you, and it's worth staffing for before you automate the easy half.

Full per-minute rates and break-evens are in our video API pricing comparison. One more thing matters at batch scale: a failed render refunds its credits automatically, exactly once, and a job whose worker dies gets swept and refunded within two hours. In a 25-render batch, one bad image URL should cost you a retry, not a support ticket.

Does one render cover TikTok, Reels, and Shorts?

Yes, and that's the easy part. All three placements take a 1080x1920 vertical video, so a single render ships to all three with no extra work and no extra credits. The 20-second runtime sits inside every one of their limits too.

Feed placements are where it stops being easy, and the API has a trap here worth knowing about. The render request accepts width and height overrides, which looks like a free way to get a 4:5 or 1:1 cut out of the same template. It isn't. Those fields resize the canvas; they don't re-lay-out the composition.

I tested it rather than assuming. Rendering the same variant with height: 1350 produced this:

Two frames from the same template rendered at two canvas sizes. The 9:16 frame on the left shows the full design including the 48 HOURS LEFT bar and the deadline footer. The 4:5 frame on the right is pixel-identical at the top but the bottom third, including the urgency bar and footer, is missing.

Everything above the cut is identical. Everything below 1350 pixels is gone, including the urgency bar and the countdown footer, which happened to be the two elements carrying the deadline. The render succeeded and reported no problem.

So treat aspect ratio as a template property, not a request parameter. If you need a 4:5 feed cut, use a composition authored at 4:5 and give it the same variable names. Then one matrix of replacement values drives both, and you're back to changing one thing at a time.

What actually breaks: copy length, not the render

Here's the part the tool blogs skip. I rendered four variants of this template and all four succeeded. One of them was unusable anyway.

Our finding: every one of the 44 text overlays in this template sets fontSizeFixed: true. Nothing auto-shrinks. A replacement value longer than the default wraps to a second line, and if the box has no room for one, that line gets clipped. The render still reports success.

Two frames from real renders of the same template side by side. The left frame reads 40% OFF EVERYTHING on one clean line. The right frame reads $50 OFF ORDERS OVER with the second line, $150, sheared off at the bottom of its container.

The numbers behind that image: discount_scope sits in a 980 by 152 pixel box, set in Anton at 132px with a line height of 1.06. One line needs about 140 pixels, so the box fits exactly one. "OFF EVERYTHING" is 14 characters and fits. "OFF ORDERS OVER $150" is 20 characters, needs about 259 pixels, and loses its bottom half.

So write the pre-flight check into the workflow. Auditing the props before rendering caught it:

[32] discount_scope       "OFF ORDERS OVER $150"
  likely WRAPS: ~2 rendered lines vs 1 authored
  likely CLIPS vertically: needs ~259px height, container 152px

Shortening the value to "OFF SITEWIDE" cleared the warning, and the re-render is the middle panel of this post's cover image. But treat the audit as a screen, not a verdict. It also flagged a "SHOP THE SALE" button that rendered perfectly well on one line, because its width estimate assumes an average character and Anton is condensed. So: audit to find candidates, then render a single frame of each candidate to confirm. Two cheap steps beat 25 expensive ones.

The practical version of this is a character budget per axis. Before you write 25 variants of copy, find out how many characters each slot actually holds, and write to it.

How do you tell which variant won?

The render request has no metadata field. Nine fields, none of which is a label, so there's nowhere to stash "variant B, urgency test" on the job itself. Attribution has to live somewhere else.

The move that works for offer testing is a unique code per variant. Our four renders carried BF40, BF50, and BFTONIGHT, each visible on the closing frame:

Two closing frames from different renders of the same template, one showing promo code BF40 and the other showing BFTONIGHT, with the rest of the layout identical.

A code redeemed at checkout attributes cleanly, independent of pixels, attribution windows, and platform reporting disagreements. Pair it with your own file naming and the platform's UTM parameters and you can reconcile three ways.

It has a real limit, and it's worth saying plainly. This works for coded offers. It does nothing for brand or awareness variants, where there's no redemption event to tie back. For those, per-variant landing pages are the closest equivalent.

Where this fits

Two platforms are telling advertisers to ship more video than a human can edit, and neither is going to stop. The production method matters more than the volume target. A batch of 25 unrelated videos costs the same as a batch of 25 controlled ones, and teaches you far less.

  • TikTok's own number is 9 to 25 creatives per campaign, refreshed into existing ad groups.
  • One template with a named variable contract holds everything constant except the axis you're testing.
  • The batch is cheap: 12.5 credits, about $1.21, and roughly 6 minutes of render time for 25 variants.
  • Budget characters per slot before you write the copy, and confirm one frame per axis before you render the batch.

Scaling past a few dozen renders is the same pattern with better plumbing. That's covered in generating 1,000+ videos with API automation. The wider strategy sits in our guide to personalized video at scale.

Start with the template this post used. The Black Friday / Flash Sale Countdown page has a working preview and the same 12 variables, so your first variant matrix is a loop away.

Frequently asked

How many video ad variants do you need for TikTok?
TikTok's official creative guidance suggests 3-5 different creatives per ad group and 3-5 diversified ad groups per campaign. That works out to 9 variants at the low end and 25 at the high end for a single campaign. Meta gives similar advice for Advantage+ app campaigns: upload a high volume of assets and refresh them a few times a month.
How long does it take to render 25 video ad variants?
We measured four variants of the same 20-second 9:16 template at 13, 13, 14, and 19 seconds each on a single local machine. At that rate 25 variants is roughly 6 minutes of render time. Renders run in parallel on cloud infrastructure, so real batches finish faster than the sum.
What does a batch of 25 video ad variants cost?
A 20-second 1080x1920 render costs 0.5 credits, because Renderly rounds up to the nearest half credit. Twenty-five variants is 12.5 credits, about $1.21 on the $29 Creator plan. The same 8.33 output minutes costs $1.67 on Shotstack and $11.50 on Plainly at published rates.
Can you batch-render vertical video without writing code?
Yes. The Zapier app and Make.com both create renders from a spreadsheet row, and each row can carry its own replacement values. A 25-row variant matrix is easier to express as a loop than as a Zap, though, so the no-code route suits ongoing per-record video better than one-off creative tests.
Why not use an AI video generator for ad variants?
A creative test needs every variant identical except the one thing under test. A generator that produces 25 different videos has changed the script, the pacing, and the footage all at once, so a winning variant tells you nothing you can reuse. Template assembly holds everything else fixed by construction.