VideoFlowcodeGitHubTry itCoreRenderersReact Video EditorPlaygroundExamplesDocscodeGitHubTry it
← Back to Blog

How to Generate Personalized Video Ads from a CSV with TypeScript

July 8, 2026 · By VideoFlowLearn how to build a high-performance video generation pipeline that turns CSV data into personalized 1080p MP4 ads using VideoFlow and TypeScript.How to Generate Personalized Video Ads from a CSV with TypeScript

How to Generate Personalized Video Ads from a CSV with TypeScript

Scaling video production for marketing is a notorious bottleneck. If you need to generate 500 variations of a video ad—each with a different customer name, local branch photo, or specific discount code—manual editing is out of the question. You need a pipeline that treats video like data.

In this tutorial, we will build a high-performance video generation pipeline that takes a standard CSV file and produces 1080p MP4 ads using VideoFlow and TypeScript. Unlike traditional solutions that rely on fragile FFmpeg shell scripts, we will use a typed, programmatic builder that renders identically in the browser and on the server.

The Architecture of Programmatic Video

When building personalized video ads, the goal is to separate the template from the data. We define the visual structure once—backgrounds, transitions, effects, and timing—and then inject variables at runtime.

A technical diagram showing a CSV file being parsed into a JSON structure, which then feeds into a VideoFlow builder block.

VideoFlow makes this trivial because every project compiles to a portable VideoJSON document. This means you can preview your template in the Playground and then deploy it to a Node.js worker for batch processing.

Step 1: Parsing the CSV Data

First, let's assume we have a leads.csv file with columns for name, city, and profile_image. We can use a standard parser to turn these into a typed array of objects.

interface Lead {
  name: string;
  city: string;
  imageUrl: string;
}

// Imagine parsing your CSV here...
const leads: Lead[] = [
  { name: 'Sarah', city: 'London', imageUrl: 'https://assets.dev/sarah.jpg' },
  { name: 'Alex', city: 'Berlin', imageUrl: 'https://assets.dev/alex.jpg' },
];

Step 2: Defining the Video Template

Now, we create a function that takes a Lead and returns a VideoFlow instance. This is where we define the cinematic look of our ad. We'll use the VideoFlow core API to layer our visuals.

import VideoFlow from '@videoflow/core';

function createAdTemplate(lead: Lead) {
  const $ = new VideoFlow({ width: 1080, height: 1920, fps: 30 });

  // 1. Add a background video with a blur effect
  const bg = $.addVideo(
    { fit: 'cover', opacity: 0.8 },
    { source: 'https://assets.dev/marketing-bg.mp4' }
  );

  // 2. Add the personalized lead image
  const avatar = $.addImage(
    { 
      position: [0.5, 0.4], 
      scale: 0.8, 
      effects: [{ effect: 'bloom', params: { strength: 0.4 } }] 
    },
    { 
      source: lead.imageUrl, 
      transitionIn: { transition: 'blurResolve', duration: '800ms' } 
    }
  );

  // 3. Add personalized text with normalized coordinates
  const title = $.addText({
    text: `Hey ${lead.name}!`,
    fontSize: 8, // 8% of project width
    color: '#FF5A1F',
    position: [0.5, 0.65],
    fontWeight: 700
  });

  title.fadeIn('500ms');
  $.wait('3s');
  title.fadeOut('500ms');

  return $;
}

In the snippet above, notice how we use normalized coordinates ([0.5, 0.65]) and em-based sizing (fontSize: 8). This ensures that if you decide to change your ad from a vertical TikTok format to a square Instagram post, your layout remains perfectly scaled without manual math.

Step 3: Batch Rendering on the Server

With our template ready, we can loop through our CSV data and trigger the server-side renderer. VideoFlow's @videoflow/renderer-server uses headless Chromium via Playwright, meaning it handles complex GLSL effects and WebCodecs without requiring you to manage local FFmpeg binaries.

import '@videoflow/renderer-server';

async function runBatch() {
  for (const lead of leads) {
    const $ = createAdTemplate(lead);
    const filename = `ad-${lead.name.toLowerCase()}.mp4`;

    console.log(`Rendering ${filename}...`);
    
    await $.renderVideo({
      outputType: 'file',
      output: `./renders/${filename}`,
    });
  }
}

Why VideoFlow for Ad Personalization?

Automating video at scale requires a tool that is both developer-friendly and visually capable. While you could attempt this with FFmpeg, you would lose access to high-level cinematic primitives like the 27 built-in transitions and 42 GLSL effects that VideoFlow provides out of the box.

A grid of three mobile-sized video previews, each showing a different personalized ad.

Compared to proprietary platforms, VideoFlow is Apache-2.0 open source. This means you own your pipeline entirely. There are no per-render fees, no vendor lock-in, and you can run the rendering logic on your own infrastructure—whether that's a Lambda function, a dedicated GPU server, or even directly in the user's browser using @videoflow/renderer-browser.

For teams that need to build an internal tool for their marketing department, you can even drop in the React Video Editor. It allows non-technical users to tweak the template visually while still saving the result as the same portable VideoJSON your automated pipeline uses.

Conclusion

Generating personalized video ads from a CSV transforms video from a creative bottleneck into a scalable data asset. By leveraging TypeScript and VideoFlow, you can build a robust automation engine that delivers high-quality, cinematic content to every lead in your database.

Ready to start building? Head over to the VideoFlow GitHub to see the source, or try out your first template in the interactive Playground.

VideoFlow

Open-source toolkit for composing videos from code.

Product

CoreRenderersReact Video EditorPlayground

Learn

DocsAPI referenceExamplesvs. Remotionvs. FFmpeg

Project

GitHubLicenseContactTermsPrivacy

From the blog

All posts →How to Generate Personalized Video Ads from a CSV with TypeScriptHow to Render MP4 Videos in Node.js without FFmpegThe Three-Renderer Rule: Unifying Your Video Rendering PipelineHow to Automate Loom-style Product Demos with TypeScriptAutomated Podcast Audiogram Generator: Turning Audio into Viral Video with TypeScriptHow to Turn Markdown Changelogs into Automated Product Update VideosAutomating Personalized Onboarding Videos with VideoFlow and TypeScriptAutomated Video Subtitles: A Developer's Guide to the VideoFlow Captions Layer
© 2026 VideoFlow. Apache-2.0 core.