Turn a Shopify product feed into unique, tracked AI video ads for every SKU using reference image generation, prompt templates, canonical UTMs, and BigQuery measurement. Includes the kill rule logic that pauses unprofitable product videos automatically.
You have 900 products and roughly zero videos for them. The one motion asset you own is a hero video that cost five figures to produce, and every other SKU is stuck as a static image while competitors advertise motion on the same shelf.
Catalog AI video ads are the answer, but not the way most tutorials frame it. The magic is not a cleverer prompt. It is turning your product feed into a deterministic asset factory, where every row becomes a tracked, uploadable, pausable video ad with its own SKU-level profit ledger.
That is what this product-feed ROAS playbook builds.
What You'll Build
A scriptable pipeline that takes your raw product export and outputs:
- One rendered, post-produced video per active SKU
- A canonical UTM parameter on every final URL keyed to that SKU
- A Merchant Center feed with per-item video URLs
- A BigQuery view that reports true SKU-level ROAS
- A daily automation that pauses unprofitable product videos without human review
Prerequisites
- A product feed export. Shopify CSV works; any ecommerce export with SKU, title, image URL, price, bullet points, and active status is fine.
- API access to a video generation model. Google's Veo or OpenAI's Sora for top-tier fidelity; Kling, Luma, or Runway as mid-tier volume options. Verify current pricing and batch limits on provider pages before scaling.
- Merchant Center and Google Ads accounts with API or script access.
- Python 3.9 or newer for the glue.
- About 20 to 30 hours of an operator who can read code and read a profit report.
No creative team required. That is the point.
The 2026 Shift: Catalog AI Video Ads Are a Feed Engineering Problem
OpenAI and Google both turned image-to-video from a demo into a usable product within days of each other in December 2024. Trace the launches on the OpenAI and Google DeepMind pages. Two structural facts from those launches dictate your entire toolchain.
First, native clips are short. Google's Veo API returned roughly 8-second clips at launch, with an invisible SynthID watermark baked into every frame. You cannot generate a 20-second ad in one pass.
You need an assembly pipeline: multiple shots stitched, captions layered, and an end card appended in post. Second, those clips were silent. Music, voiceover, and sound design are a separate post-production layer with its own cost.
Meanwhile Google kept consolidating video ads into Performance Max. PMax does not expose per-SKU budgets, per-SKU targeting, or per-SKU placement. The correct mental model is no longer “put one video per SKU in a campaign.”
It is: feed Google a SKU-keyed asset library and let the engine choose, then measure outcomes downstream on your own event data. Verify the exact campaign UI state before you build, because Google changed it repeatedly through 2025.
The inventory math works. YouTube Shorts passed 70 billion daily views, announced by Google itself, which gives you enough feed placements to absorb thousands of distinct product videos without exhausting frequency.
The bottleneck was never creative production. It is deterministic feed engineering: clean product data, one canonical SKU key, and tracking that survives the ad platform's black box.
System Design: Build One Product Video Generation Pipeline, Then Reuse It 1,000 Times
Start with a hard rule: always generate from a reference product image, never from text-only prompts.
Give a model the prompt “bottle of lavender cleaning spray, kitchen background, cinematic light” and it will invent a bottle that looks 80 percent like yours. Wrong cap, wrong label, wrong color. On a catalog of thousands, an 80 percent similar product is a falsified ad.
The prompt should describe motion, environment, and lighting. The product facts come from feed columns: title, material, color, top feature bullet. Assemble them with an f-string, not free-written copy, so the model cannot invent attributes you never shipped.
Plan for versioning before upload. Merchant Center allows only one primary video per product item, and the last upload wins. If you generate three creative variants and dump them into the same field, you get silent overwrites.
Design feed columns like video_primary, video_test, and video_archive from day one.
Finally, tier your models by catalog position. A 50-SKU catalog runs entirely at top-tier fidelity. A 50,000-SKU catalog needs a policy: hero SKUs at top tier, long-tail SKUs at mid-tier, and template-based overlays for the bottom.
Test 20 SKUs on a mid-tier API before committing the whole catalog, because consistency varies wildly by product category.
Step-by-Step: Generate Video Ads from a Product Feed
Worked example: a DTC supplement brand with 250 core products, roughly 900 SKUs after variants, and no video team.
Here is the exact path. The code is simplified but copy-pasteable. Swap the API object for the client your provider gives you.
Step 1: Normalize the Feed
import pandas as pd
df = pd.read_csv('shopify_export.csv')
df = df[df['status'] == 'active'].copy() # drop drafts and archived SKUs
df['slug'] = (
df['handle']
.str.replace(r'[^a-z0-9-]', '-', case=False, regex=True)
.str.lower()
)
Confirm the columns you need exist before anything else: SKU, title, image URL, price, bullet points. If your feed is messy here, every downstream step inherits the mess.
Step 2: Build the Prompt Template From Feed Columns
def build_prompt(row):
title = row['title']
material = row['material']
color = row['color']
feature = row['top_feature']
return (
f'Product hero video. Start on a clean white studio surface. '
f'Product: {title}. Material: {material}. '
f'Color: {color}. Feature highlight: {feature}. '
f'Slow turntable reveal, then a single dry pour splash, '
f'soft daylight, shallow depth of field. '
f'End with product centered, label fully legible. '
f'No text overlays, no hands.'
)
Generate 20 SKUs first as a QC cohort. Check every frame for hallucinated labels, wrong caps, and distorted packaging before you spend on the remaining 880.
Step 3: Batch Generate, Then Post-Produce
jobs = {}
for idx, row in df.iterrows():
job = api.generate(
prompt=build_prompt(row),
reference_image=row['image_url'], # always pass the real packshot
duration_sec=8,
aspect_ratio='16:9',
)
jobs[job.id] = row['sku']
# Poll asynchronously, download clips, then append audio and overlays
Do not loop synchronously and wait on each clip. Submit all jobs, poll, and download. Consumer chat UIs are a terrible medium for this volume; you need the model's API or a batch endpoint.
After render, add an ElevenLabs voiceover naming the product and its one benefit, a licensed music bed, and an FFmpeg pass that burns the price and end card into the frame. Never rely on the model to render readable text.
Step 4: Append the Canonical SKU Parameter
import urllib.parse
df['final_url'] = df.apply(
lambda row: (
'https://store.com/products/' + row['slug'] + '?'
+ urllib.parse.urlencode({
'utm_source': 'google',
'utm_medium': 'video',
'utm_campaign': 'catalog_q4',
'utm_term': row['sku'], # canonical SKU key in clicks
'utm_content': 'v1', # video version
})
),
axis=1,
)
Your purchase event payload must send the same SKU as item_id. If clicks use utm_term and purchases use a different field, your join fails and every SKU looks unprofitable. One canonical key everywhere.
We covered the failure modes in depth in our post on creative tracking mistakes.
Step 5: Upload to Merchant Center and PMax
Upload each video to a CDN such as Google Cloud Storage, then push per-item video URLs through the Merchant Center Content API following Google's developer documentation. Do not rely on ad-hoc feed column injection for video. Import the same asset library into your Performance Max asset groups so YouTube inventory can serve it.
At the end of this process, your feed has 900 rows, each with a rendered video URL, a final URL, and a UTM key. The output is boring on purpose. The interesting part comes next.
The Measurement Layer: SKU-Level Video ROAS Tracking and Automated Kill Rules
Standard Google Ads and GA4 reports aggregate by campaign and ad group, not by SKU. You cannot see that SUP-417 spent $312 with zero purchases while SUP-088 quietly returned 6x. To see that, export click and event data to BigQuery and join on the SKU key yourself.
The join is the product.
SELECT
sku,
SUM(spend) AS total_spend,
SUM(revenue) AS total_revenue,
SAFE_DIVIDE(SUM(revenue), SUM(spend)) AS sku_roas
FROM
`your_project.catalog_video.joined_events`
GROUP BY sku
ORDER BY sku_roas ASC
LIMIT 50;
The bottom 50 rows of that query are your kill list. Export Google Ads cost data and GA4 purchase data into BigQuery using the connectors Google Cloud provides, then schedule the join daily. You cannot manage 900 SKUs in a spreadsheet and you should not try.
Now automate the decision. Google Ads Scripts run free on a schedule inside the Ads UI. This is the operational brain:
// Google Ads Script, scheduled daily at 6 AM
function runKillRules() {
const skus = fetchSKUmetrics(); // your BigQuery view, exported to the script
skus.forEach(sku => {
const hasData = sku.impressions >= 400 && sku.clicks >= 15;
const overBudget = sku.cpa > sku.blendedTarget * 2;
if (hasData && overBudget) {
pauseSKU(sku.id);
}
});
}
Two rules keep this from firing on noise. Minimum impression and click floors come first. A SKU with $2 in clicks and zero purchases is statistically meaningless; pausing it on Monday would have killed a video that converts by Friday.
Separate view-through from click-through conversions. YouTube view-through revenue is real but volatile, and mixing it into your pause rule causes whiplash. Judge kill decisions on click-through data first.
Common AI Video Ad Pitfalls and How to Design Around Them
The five failures that break catalog pipelines, in order of damage:
- Text-only prompts. The model invents packaging. Always pass the reference image.
- Misplaced SKU keys. Different fields on the click side and the purchase side means zero clean joins. One canonical field everywhere.
- Premature evaluation. No impression floor, no click floor, and you kill profitable long-tail videos on day two.
- Single Merchant Center video field. Multiple variants overwrite each other silently. Version in feed columns before upload.
- Free compute fantasy. Only 50 to 70 percent of generated clips survive QC. Retries, rejected renders, and audio rework double your real cost. Budget for junk.
Also know what you are competing against. Google and Meta both auto-generate video from product data inside their ad platforms. That tooling wins on speed and zero cost per SKU.
It loses on brand consistency and measurement determinism because you do not control the creative or the UTM.
For commodity products where price matters more than packaging, use the platform tools. For brands where the physical product is the selling point, build the custom pipeline.
These two strategies answer different questions, and the cost of mixing them up is a catalog of on-brand videos you cannot measure.
If you prefer a no-code route for the orchestration layer, our no-code automation guides cover equivalent connectors. The measurement discipline stays identical.
Next Steps
Do not generate 900 videos this week. Generate 20, put them through the tracking layer, and let them spend for two weeks while you verify the BigQuery join returns sane numbers. Once SKU-level profitability is proven on the cohort, scale to the full catalog.
For a single hero product without this complexity, follow our single product playbook first.
One more thing to internalize: automation only works when the data under it is clean. The same reason most CRM automation efforts die is broken inputs, and that failure mode will kill a catalog video pipeline twice as fast because the volume hides the errors.
Clean feed, canonical key, working join. Then scale.
The Shortcut
You now know exactly how the machine works: connectors, prompt templates, and SQL joins. If running one more API queue and debugging its attribution sounds like a month of your life, that is what our managed scale engagements handle end to end, from $2,500 per month.
You keep the SKU-level reporting. We own the plumbing.
Cover photo by Luke Jones on Unsplash.
Frequently Asked Questions
Can I run catalog-scale AI video ads without building my own pipeline? +
Yes. Platform tools inside Google and Meta auto-generate catalog videos from product data at near-zero cost per SKU, but they sacrifice creative control, brand consistency, and deterministic UTM tracking. The custom pipeline in this playbook exists precisely because platform tools cannot give you clean SKU-level ROAS data.
How much does it cost to generate video ads for a full product catalog? +
Provider price cards change often, so think directionally rather than precisely. At early 2025 rates, generating videos for roughly 900 SKUs required about 2,000 to 2,500 generation jobs after retries. Raw generation landed in the low thousands of dollars with mid-tier APIs, plus audio, rendering, and operator time. Only 50 to 70 percent of generated clips survive QC, so budget for regeneration.
Why do I need SKU-level UTM parameters when Google Ads already tracks conversions? +
Because Google Ads and GA4 aggregate performance by campaign and ad group, not by individual product SKU. The UTM parameter in the final URL is the only consistent key that lets you join click data to purchase events in BigQuery and calculate true per-SKU profitability, which is what your kill rules need to operate.
Lucas Oliveira