Skip to main content

The Problem

Generic sales emails have notoriously low response rates. Personalized video consistently outperforms text — but recording a custom video for each prospect doesn’t scale past a handful per day.

How It Works

CRM/prospect data → Personalized prompt per contact → Batch generate → Deliver via email/LinkedIn
You define a prompt template with variables (name, company, pain point). For each prospect, the template fills in their details and Video Agent generates a personalized video.

Build It

1

Prepare your prospect data

Export from your CRM or create a structured list. Each entry needs enough context to personalize the video.
prospects = [
    {
        "name": "Sarah Chen",
        "company": "Acme Corp",
        "role": "VP of Marketing",
        "pain_point": "spending 40+ hours/month on video content creation",
        "value_prop": "cut video production time by 90% with AI-generated content",
    },
    {
        "name": "Marcus Johnson",
        "company": "TechStart Inc",
        "role": "Head of Sales",
        "pain_point": "low response rates on cold outreach",
        "value_prop": "personalized video messages that get 10x more replies",
    },
    # ...
]
2

Build a prompt template

The template should produce a video that feels personally recorded — not like a mail merge.
def build_outreach_prompt(prospect):
    return f"""Create a 30-second personalized sales video.

The presenter should speak directly to the viewer as if recording
a quick personal message. Warm, genuine, not salesy.

Script direction:
- Open: "Hi {prospect['name']}, I was looking at what {prospect['company']}
  is doing and had a quick thought for you."
- Problem: Briefly mention that many {prospect['role']}s are
  {prospect['pain_point']}.
- Solution: Share that there's a way to {prospect['value_prop']}.
- CTA: "Would love to show you how this works — mind if I send
  over a 5-minute demo? Just reply to this email."

Tone: Conversational and genuine. This should feel like a real person
who took 30 seconds to record a message, not a polished ad.
Keep it under 35 seconds. Landscape orientation.
"""
The key to personalized video: The prompt should include specific details about the prospect (company name, role, pain point) but the delivery should feel natural and unrehearsed. Avoid making it sound like a template — that defeats the purpose.
3

Generate videos in batch

Submit all videos with rate limit spacing.
import requests
import time

HEYGEN_API_KEY = "your-api-key"
jobs = []

for prospect in prospects:
    prompt = build_outreach_prompt(prospect)
    resp = requests.post(
        "https://api.heygen.com/v3/video-agents",
        headers={
            "X-Api-Key": HEYGEN_API_KEY,
            "Content-Type": "application/json",
        },
        json={"prompt": prompt},
    )
    data = resp.json()["data"]
    jobs.append({
        "prospect": prospect,
        "video_id": data["video_id"],
    })
    print(f"Submitted for {prospect['name']}: {data['video_id']}")
    time.sleep(5)
4

Collect results and deliver

Once all videos are rendered, pair each video URL with the prospect for delivery.
import time

for job in jobs:
    while True:
        resp = requests.get(
            f"https://api.heygen.com/v3/videos/{job['video_id']}",
            headers={"X-Api-Key": HEYGEN_API_KEY},
        ).json()["data"]

        if resp["status"] == "completed":
            job["video_url"] = resp["video_url"]
            job["thumbnail_url"] = resp["thumbnail_url"]
            print(f"Ready for {job['prospect']['name']}: {resp['video_url']}")
            break
        elif resp["status"] == "failed":
            job["video_url"] = None
            print(f"Failed for {job['prospect']['name']}")
            break

        time.sleep(10)

# Now you have a list of prospects with their personalized video URLs
# Feed this into your email/LinkedIn outreach tool

Delivery Strategies

ChannelHow to embedTips
EmailUse the thumbnail_url as a clickable image linking to video_urlGIF thumbnails get higher click rates than static images
LinkedInUpload the video directly or share the link in a messageVideo messages tend to get significantly higher response rates
Landing pageEmbed the video on a personalized page per prospectCombine with personalized page content for full experience
Sales platformMost platforms (Outreach, Salesloft, HubSpot) support video embedsCheck your platform’s video integration docs

Brand Consistency

When generating videos for many prospects, you want every video to feel on-brand:
  • Same avatar: Pass a specific avatar_id to ensure the same “salesperson” appears in every video. See Avatars to browse options.
  • Same voice: Pass a specific voice_id for consistent voice. See Voices.
  • Same style instructions: Include brand colors, background, and tone in every prompt.
def build_outreach_prompt(prospect):
    return f"""Create a 30-second personalized sales video.

Avatar: Use avatar look_id "josh_lite3_20230714".
Background: Clean, modern office with warm lighting.
Brand: Professional but approachable. No flashy graphics.

...rest of the prompt...
"""

Variations

  • Follow-up sequences: Generate a series of videos per prospect — intro, value prop, case study, final nudge
  • Event-triggered: Generate a welcome video when a prospect signs up for a trial or downloads a resource
  • Account-based marketing: Generate company-specific videos that reference the prospect’s recent news or achievements

Next Steps

Social Media Pipeline

Use similar batch techniques for social content.

Prompt Engineering

Craft prompts that make each video feel genuinely personal.