All posts
csv
datasets
tutorial

CSV to video: a spreadsheet into a hundred video ads

One spreadsheet, one template, one build. A practical walkthrough turning a campaign CSV into a hundred rendered video ads, with previews and approvals.

Nubu Team14 minute read
CSV to video: a spreadsheet into a hundred video ads

Every campaign you run already lives in a spreadsheet. One row per variant, columns for market, language, headline, offer and call to action, and a status column someone updates after every review call. The videos are the slow part: someone duplicates a project, pastes in the headline, swaps the end frame, exports, renames the file, and starts again. A hundred variants of one fifteen second ad is days of that work, and every paste is a chance to ship the wrong price.

CSV to video is the unglamorous name for the fix. The spreadsheet stays the source of truth, a video template supplies the design, and the system in between expands rows into finished ads. This tutorial walks that workflow end to end in Nubu: you prepare a campaign CSV, upload it into a flow, pipe its columns into the node graph, route out unapproved rows, preview the exact list of ads a build will create, render the lot, and finish with a folder of videos plus a manifest CSV listing every ad's copy and UTM parameters.

That is the machine you are about to build, and it is live: drag the pipes, change the routing, and watch the row counts move. If Nubu's flow canvas is new to you, the primer on the node-based editor covers the canvas itself, and if you are still weighing up whether to automate at all, start with what creative automation actually is. Otherwise, open a spreadsheet and follow along.

Prepare the spreadsheet

Everything downstream leans on one rule: one row per ad. If you want a UK English ad and a UK Welsh ad, that is two rows, even when only the language and headline differ. Rows are variants; columns are the ingredients a variant is made from.

A good campaign CSV carries three kinds of column:

  • Dimension columns that say which variant a row is: market, language, version. These become the axes your campaign splits along.
  • Content columns that carry what changes on screen or in the ad copy: headline, subline, call to action, offer, destination URL.
  • Working columns your team manages the sheet with: status, owner, notes, and references to which footage or cutdown belongs to each row. Nubu ignores any column you never pipe, so leave them in. The sheet should remain the document your team actually works in.

Some hygiene, because Nubu reads the file strictly:

  • Headers become column keys. The first row names every column; each header is tidied into a stable key and clashes are de-duplicated. Keep headers short and unambiguous: market, language, headline.
  • Cells are trimmed. Stray spaces around values disappear on upload, so "UK " and "UK" are the same market.
  • Exact duplicate rows collapse. Two identical rows produce one ad, not two. Deliberate near-twins need a column that distinguishes them, usually a version column.
  • Limits: a CSV can be up to 10 MB, 5,000 rows and 40 columns.

Google Sheets, Excel, Numbers and Airtable all export CSV, and that exported file is what Nubu reads; there are no live spreadsheet connectors today.

Here is the sheet this tutorial uses, kept deliberately imperfect:

marketlanguageheadlinectastatus
UKenSave nowShop the saleApproved
FRfrÉconomisez maintenantVoir l'offreApproved
DEdeJetzt sparenZum AngebotApproved
UKenSave nowShop the saleApproved
ESesAhorra ahoraVer la ofertaDraft

Five rows: one exact duplicate, one still in Draft. Keep count of what should come out the other end. The right answer is three ads.

Step 1: upload the CSV into a flow

In Nubu, campaigns contain flows, and a flow's node canvas is where data meets template (the flows overview covers the basics). Open your flow and add a CSV node from the palette's Data nodes group. Data nodes are available on every paid plan, Starter and up.

The node takes your file in two ways:

  • Upload it straight into the node.
  • Select from assets, when the CSV already lives in your asset library. Nubu copies the file into the flow rather than referencing it, so the two lives stay independent: replace or delete the library file later and the flow keeps working.

Once parsed, the node shows the first ten rows inline, and scrolling pages in more, so you can sanity-check the data without leaving the canvas. One CSV node per flow for now, which sounds like a constraint and behaves like a discipline: one flow, one source of truth.

Step 2: choose which columns to expose

The CSV node lists every header it found and lets you pick which columns to expose. Each exposed column becomes an output handle on the node, one pipe source per column, named by the key derived from your header. For the example sheet, expose all five: market, language, headline and cta will feed the campaign, and status will drive the routing in step 5.

Unexposed columns cost nothing; they simply never appear on the canvas. The full reference for columns, keys and values is in the docs under working with data.

Step 3: pipe columns into dimension and content nodes

Two node families accept column pipes. Dimension nodes (Market, Language, Version) define the axes a campaign splits along. Content nodes (Text, Value, Colour) carry the words, numbers and colours that end up in the ad.

Drag a pipe from the CSV node's market output into a Market node's data input, and the node fills itself in: every unique value in the column generates a row automatically, each with a count of how many CSV rows carry it. Do the same with language into a Language node and headline into a Text node.

Three things are worth knowing about generated rows:

  • They behave exactly like rows you type by hand. Same connectors, same gating, same look. You can add manual rows alongside them on the same node when one market needs something the sheet does not carry.
  • They always mirror the file. Generated rows are derived from the CSV itself, not copied out of it, which is why a replaced CSV can never leave stale values behind. More on that in step 8.
  • They are uncapped but sanity-checked. Every unique value appears. Pipe a column with a hundred or more unique values into a dimension node, though, and Nubu warns you, because that is usually a mispicked column: a headline column dropped on Market, say.

Not everything takes a pipe. Dropdown, Tags and Footage nodes accept no CSV pipes today, so footage is wired on the canvas: connect the right video and image assets to the template directly, and treat the sheet's working columns as the checklist for which asset belongs to which row. Each input also takes exactly one pipe, so there is never a quiet question about where a value came from. (On the Business+ plan an AI node can transform piped text per market, translation for instance, but that is a tutorial of its own.)

Step 4: auto-pairing keeps values together

Here is the trap in naive CSV to video tools: the cross product. Three markets and three headlines make nine combinations, and six of them are nonsense. Your UK ad must never render with "Économisez maintenant" on it.

Nubu closes the trap with auto-pairing, on by default and toggleable in the editor's gear menu. When a pipe generates new rows, the editor asks the CSV which values actually belong together: it reads row co-occurrence and draws one pipe per genuine pairing. UK connects to "Save now" because a row says so. FR connects to "Économisez maintenant" for the same reason. No pipe ever joins UK to the French line, because no row contains that combination.

Two properties make this trustworthy rather than magical:

  • The pipes are real, visible edges. You can trace every one, and you can delete one; a deleted pairing stays deleted rather than being silently redrawn behind your back.
  • The build engine double-checks anyway. At build time, any combination no CSV row supports is pruned (step 8), so even a hand-drawn mistake cannot ship a Frankenstein ad.

It is also why the canvas stays readable at scale: the same visual flow you would have drawn by hand for three variants, drawn for a hundred.

Step 5: route rows with If/Else

The example sheet has a Draft row that must not build. Rather than cleaning the sheet before every export, put the rule in the flow: add an If/Else node between the CSV node and the top of your chain.

An If/Else routes one piped column. Pipe market into it, then add a condition: status equals Approved. Conditions AND-combine, so adding a second condition means both must hold, and each condition tests a column from the CSV by straightforward comparison.

If/Else node routing rows on a status column, with live counts on the True and False branches

The node exposes True and False outputs, each with a live row count. Rows that satisfy every condition route True. Everything else routes False, and that includes anything unevaluable: a blank status cell, a malformed value, a row the comparison simply cannot read. Half-finished sheets fail safe; nothing sneaks into a build because a cell was empty.

Wire the True output onwards into the Market node. Downstream, only values from approved rows generate: ES never appears, and no combination backed only by the Draft row can survive the build. If you want to route a second column through the same rule, that column gets its own If/Else; each If/Else routes exactly one column. You can wire the False branch too, as a lane for work-in-progress variants, though most flows leave it unconnected.

Step 6: connect the template and the Output

The right side of the flow is the same whether your data is piped or typed: a Template node and an Output node. The available nodes reference lists the whole catalogue.

The full flow canvas: CSV node into If/Else, dimensions and text, wired through a template to an Output

The Template node is your design: an After Effects project packaged with the Nubu Builder plugin and uploaded to your template library. If your motion designer has not packaged one yet, the After Effects automation guide covers that side of the workflow. On the canvas, the node lists the template's fields (the text layers, colours and footage slots the designer exposed) and its output compositions, the actual sizes it renders. Pipe the headline Text node into the matching text field, and wire footage straight to its slots. If the template exposes more than one output composition, a vertical and a square cut for instance, each one you wire multiplies the build.

The Output node turns a rendered video into an ad. Pick the platform and placement, and the node reveals exactly the ad copy fields that placement accepts, validated live as you type or pipe: character limits, banned characters, URL shape. A wrong value rings the field, the pipe and the source row while you are still in the editor. Give cta the same treatment as headline, a Text node piped from the column and connected to the call to action field; auto-pairing keeps each market's CTA with its market.

Output node showing ad copy fields and the UTM parameters section

Scroll down the Output node and you reach the UTM section, half generated and half yours. utm_source, utm_campaign and utm_content arrive as locked rows, derived for you; utm_content is assembled from the flow, placement, market, language, version, duration and dimensions, normalised into one string, so every individual ad is traceable in analytics without anyone typing anything. utm_medium and utm_term stay editable. The node also keeps the whole link honest: the destination URL plus every UTM parameter must stay under 2,000 characters, checked live in the editor and again at build.

One more guard worth knowing about: an Output that nothing feeds is a live error and a build refusal, never a silent skip. Empty ads do not ship quietly.

Step 7: preview exactly what will build

Before anything renders, connect the Output into a Preview node. It tables every creative the current graph will produce: one row per ad with its resolved market, language and copy, enumerated by the same engine a real build uses, with nothing written and nothing rendered.

Preview node listing the exact creatives a build will produce, one row per ad

For the example sheet the table shows exactly three rows: UK, FR and DE. The duplicate UK row collapsed into one, the Draft row routed False, and nothing else appeared. If the table surprises you, fix the graph, not the output; the table is the contract.

Each preview row also carries a Render preview action, which queues a real render of that single creative through the exact production pipeline, hidden from your campaign. Use it to watch one finished video with real data in it before committing to a hundred. It is not wasted work either: when you later build, a creative whose content matches a preview reuses that render instead of rendering again.

If you would rather follow the rest with your own sheet than read along, creating an account takes a minute, and the data nodes unlock on the Starter plan (see pricing).

Step 8: build

Press Build. Validation runs first, entirely up front: any error keeps the editor open with the offending node ringed and the pipe labelled, so a broken flow costs you seconds, not renders. Then the build carries on in the background and you can close the editor.

What the build does with your data is the part worth understanding:

  • It expands variants the classic way, market by language by version, then prunes every row-impossible combination: any pairing of values that no surviving CSV row contains is removed. The build double-checks auto-pairing's work for itself, and it is what makes the cross product a non-issue.
  • It re-reads the CSV and verifies every piped value still exists in its routed column, so the build can never run on assumptions the file no longer supports.
  • If two creatives come out identical after pruning, the build refuses and asks you to add a distinguishing dimension, rather than silently rendering twins.
  • Every creative gets a deterministic identity derived from what feeds it. Build the same unchanged flow twice and the second build matches the first's rows instead of duplicating them. Rows already queued, rendering or rendered are protected and never touched; change their content and the change lands as a new revision, not an overwrite.
  • A single build caps at 5,000 creatives.

Because generated values always come from the file itself, replacing the CSV is safe by construction. Upload next week's export and every generated row, count and pairing re-derives from the new file; stale values are impossible. And if the new file drops a value your flow still points at, because you removed the DE rows say, the affected pipe wears a "Value gone" label in the editor and the build refuses until you resolve it. Nothing fails silently in either direction.

The full build reference lives in the docs at building a creative.

Review and approve

A build creates creatives, not renders. Every ad lands in review, and a human approves it before a render is queued. The gate is deliberate: at one video, review is a formality; at a hundred, it is the only place a wrong price or a swapped headline gets caught before it is baked into pixels.

The approve drawer showing a creative's resolved copy, media and dimensions

Open any creative and the drawer shows everything the row resolved to: the copy per field, the media, the dimensions, the destination link. Approve it and the creative moves to queued, then rendering, then rendered; a failure keeps its row and its error message rather than vanishing. Teams review together too: the drawer carries threaded comments with timecode links, so feedback lands on the exact frame it is about.

The gate keeps working after render as well. A rendered creative can still be edited, and a real content change sends it back through the queue to re-render, rather than leaving a stale video wearing new copy.

What comes out the other end

The renders grid fills as the queue drains: one finished video for every sheet row that survived routing, each traceable back to the exact values that made it.

The renders grid filled with finished video ads across markets and languages

Downloads arrive ready for handover. Multi-file downloads arrive as one ready-assembled ZIP, and render downloads include a manifest.csv: one row per ad listing the delivered file name, platform, placement, market, language, version, duration, status, when it rendered, every ad copy field, tags, and all five UTM parameters. It closes the loop. A spreadsheet went in; a spreadsheet comes out with a video attached to every row, carrying everything a media buyer needs to place each ad by hand.

On the Business+ plan you can skip the by-hand part. Connect your Meta and Google accounts and push creatives straight from Nubu: ads arrive paused, one paused ad per creative on Meta and Demand Gen, and Performance Max outputs assemble into a paused asset group, so nothing spends a penny until someone turns it on. Delivery today covers Meta and Google; everything else takes the manifest route.

Other ways to get from CSV to video

Nubu is not the only way to do this, and depending on who you are it may not be the right one.

Plainly is a managed service built specifically for data-driven After Effects rendering: you upload an AE project, define what changes per video, and batch-render variations from a CSV or through an API. If your team lives in After Effects and mainly wants renders at scale rather than a campaign workflow, it is a strong choice, and their own CSV tutorial is one of the better guides on this subject. What stays yours to assemble is everything around the render: review, approval, UTM discipline and getting the ads into platforms.

nexrender is the open source route: render automation for After Effects that you run on your own machines. Jobs are JSON descriptions, a worker farm renders them, and it costs nothing but engineering time, of which it will consume a real amount, because you own the queue, the render machines, the storage and every integration. For a developer team that wants total control, nexrender is excellent. For a marketing team, it is not a product; it is a project.

Creatomate and Shotstack are cloud video APIs with their own template and edit formats rather than After Effects. You describe a video in JSON, or build a template in their editors, then generate variations from data in code. Both are made for developers embedding video generation inside their own software, and both are good at it. That is also the honest dividing line: Nubu has no public API today, so if you need renders inside your own product, an API-first tool is the better fit. If you need a campaign your whole team can see, review and ship, that is the job Nubu is built for.

One spreadsheet in, one campaign out

The whole loop, at speed: one row per ad in a CSV; a CSV node exposes the columns; pipes generate the values; auto-pairing and If/Else keep every combination true to the rows; a template and an Output define what renders and where it will run; Preview shows you the exact list before you commit; Build creates deterministic, reviewable creatives; approval gates the queue; and out the other end come rendered videos with a manifest that turns the results back into a spreadsheet.

Next week, when the campaign changes, you rebuild nothing by hand. Update the sheet, export it, replace the file in the CSV node, and build again: new rows become new ads, unchanged rows match their existing renders, and removed values announce themselves instead of lingering.

Start with your own sheet: create a free account and the CSV workflow is there from the Starter plan up (pricing).

More from the blog

EU AI Act and AI generated ads: what to do now
ai
compliance
workflow

EU AI Act and AI generated ads: what to do now

The EU AI Act's transparency rules for AI generated ads are live. What changed, what counts as AI creative, and the workflow to run this month.

12 minute read
AI proposes, humans approve: safe ad automation
ai assistant
safety
opinion

AI proposes, humans approve: safe ad automation

Policy is not architecture. Nubu's assistant cannot render, publish, spend or delete: every change is a card you approve, with the evidence attached.

14 minute read