How to Auto-Generate a Narrated Demo Video for Your SaaS Product
You're launching a new feature.
Your co-founder spends three hours recording a Loom video. Thirty takes to get it right. Then two more hours editing, adding captions, uploading.
The video goes live. Three days later, you realize there's a bug in the flow. Back to Loom. Another three hours.
By the time you've done this ten times, you've spent 30+ hours recording demo videos—time you could have spent on literally anything else.
There's a better way.
The Problem: Demo Videos Are a Bottleneck
Loom is great for one-off recordings. But for SaaS, you need demo videos for:
- Landing page (product hero)
- Feature announcements
- Help docs (how to use X)
- Sales decks
- Changelog entries
- Customer success emails
- Tutorial content
That's dozens of videos. Dozens of hours in Loom.
Each video requires:
- Recording — "Let me click through this slowly while narrating" (10-30 minutes per take)
- Re-recording — "Oops, I said the wrong thing" (5-10 re-takes)
- Editing — Trim, crop, add captions, upload (1-2 hours)
- Waiting — Upload finishes, video processes, etc. (15-30 minutes)
Total time per video: 3-5 hours. For one feature.
And that's if you get it right on the first try.
The Solution: AI-Narrated Demo Videos in One API Call
What if you could define your demo as code?
Step 1: Navigate to homepage
Note: "This is our dashboard"
Step 2: Click Features button
Note: "Click here to see what's new"
Step 3: Fill in demo data
Note: "You can enter your data here"
Step 4: Submit form
Note: "One click to get results"
Step 5: Show results page
Note: "Here's what you get"
Then one API call:
- Records the video (5 browser steps)
- Adds AI narration (reads your notes)
- Syncs narration to each step
- Renders MP4
Total time: < 5 minutes.
No Loom. No manual recording. No editing. Just a script and an API call.
Here's the complete implementation:
import requests
import json
import time
PAGEBOLT_API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.pagebolt.dev/v1"
def record_demo_video(title, steps, narration_script, output_file):
"""
Record a narrated demo video by defining browser steps + narration script.
Args:
title: Video title (for logging)
steps: List of browser automation steps (navigate, click, fill, etc.)
narration_script: Full narration script with {{N}} markers for each step
output_file: Where to save the MP4
"""
print(f"🎬 Recording demo: {title}")
print(f"📝 Steps: {len(steps)}")
print(f"🎙️ Narration length: {len(narration_script)} chars\n")
# Build the video recording request
payload = {
"steps": steps,
"audioGuide": {
"enabled": True,
"script": narration_script,
"provider": "azure",
"voice": "ava",
"speed": 1.0
},
"format": "mp4",
"pace": "normal", # normal, slow, dramatic, cinematic
"cursor": {
"visible": True,
"style": "highlight",
"persist": True
},
"frame": {
"enabled": True,
"style": "macos"
},
"background": {
"enabled": True,
"type": "gradient",
"gradient": "ocean"
}
}
# Send to PageBolt
headers = {
"Authorization": f"Bearer {PAGEBOLT_API_KEY}",
"Content-Type": "application/json"
}
print("📡 Sending to PageBolt...\n")
response = requests.post(
f"{BASE_URL}/record-video",
json=payload,
headers=headers
)
if response.status_code != 200:
print(f"❌ Error: {response.status_code}")
print(response.text)
return False
# Save the video
with open(output_file, 'wb') as f:
f.write(response.content)
print(f"✅ Video saved: {output_file}")
print(f"📊 File size: {len(response.content) / (1024*1024):.1f} MB\n")
return True
# Example 1: Product Tour (5 steps, 60 seconds)
def product_tour_demo():
steps = [
{
"action": "navigate",
"url": "https://example-saas.com"
},
{
"action": "click",
"selector": "[data-testid='features-btn']",
"note": "Click to explore features"
},
{
"action": "scroll",
"y": 500,
"note": "See what's new this month"
},
{
"action": "click",
"selector": "[data-testid='pricing-btn']",
"note": "Check out our pricing"
},
{
"action": "click",
"selector": "[data-testid='signup-btn']",
"note": "Ready to get started?"
}
]
script = """Welcome to our platform. {{0}} This is where you manage everything. {{1}}
We just launched new features this month. {{2}} Check out our flexible pricing plans. {{3}}
Sign up in minutes and start using it today. {{4}}"""
record_demo_video(
"Product Tour",
steps,
script,
"product-tour.mp4"
)
# Example 2: Feature Demo (4 steps, 45 seconds)
def feature_demo():
"""Demo of a specific feature: bulk data import"""
steps = [
{
"action": "navigate",
"url": "https://example-saas.com/dashboard"
},
{
"action": "click",
"selector": "[data-testid='import-btn']",
"note": "Click Import to get started"
},
{
"action": "fill",
"selector": "[type='file']",
"value": "data.csv",
"note": "Upload your CSV file"
},
{
"action": "click",
"selector": "[data-testid='confirm-import']",
"note": "Confirm to import your data"
}
]
script = """Here's how to import your data in three clicks. {{0}} Click the Import button. {{1}}
Upload your CSV file. {{2}} And you're done! Your data is imported and ready to use. {{3}}"""
record_demo_video(
"Bulk Import Feature",
steps,
script,
"bulk-import-demo.mp4"
)
# Example 3: Customer Success (6 steps, complex workflow)
def customer_success_demo():
"""Demo for customer support: how to resolve a refund request"""
steps = [
{
"action": "navigate",
"url": "https://example-saas.com/admin/refunds"
},
{
"action": "click",
"selector": "[data-testid='filter-pending']",
"note": "Filter for pending refunds"
},
{
"action": "click",
"selector": "[data-testid='refund-row-1']",
"note": "Select a refund request"
},
{
"action": "scroll",
"y": 300,
"note": "Review the customer details"
},
{
"action": "click",
"selector": "[data-testid='approve-refund']",
"note": "Click Approve to process"
},
{
"action": "wait",
"ms": 2000,
"live": True,
"note": "Processing..."
}
]
script = """Let me walk you through processing a refund. {{0}} First, filter your refunds. {{1}}
Select the one you want to process. {{2}} Review the customer information. {{3}}
Click Approve and it's done. {{4}} The system will process it immediately. {{5}}"""
record_demo_video(
"Refund Processing Workflow",
steps,
script,
"refund-processing.mp4"
)
# Example 4: Interactive Tutorial (5 steps, educational)
def tutorial_demo():
"""Tutorial: how to set up integrations"""
steps = [
{
"action": "navigate",
"url": "https://example-saas.com/settings/integrations"
},
{
"action": "click",
"selector": "[data-integration='slack']",
"note": "Click the Slack integration"
},
{
"action": "click",
"selector": "[data-testid='connect-btn']",
"note": "Click Connect"
},
{
"action": "wait",
"ms": 3000,
"live": True,
"note": "Authorizing with Slack..."
},
{
"action": "click",
"selector": "[data-testid='close-modal']",
"note": "You're connected! Close this dialog"
}
]
script = """Setting up integrations is easy. {{0}} Go to Settings > Integrations. {{1}}
Click the service you want to connect. {{2}} Click Connect. {{3}} Authorize it with your account. {{4}}
That's it! Your integration is now live."""
record_demo_video(
"Integration Setup Tutorial",
steps,
script,
"integration-tutorial.mp4"
)
# Run all demos
if __name__ == "__main__":
print("=" * 60)
print("🎬 PageBolt Demo Video Generator")
print("=" * 60 + "\n")
product_tour_demo()
print("\n" + "-" * 60 + "\n")
feature_demo()
print("\n" + "-" * 60 + "\n")
customer_success_demo()
print("\n" + "-" * 60 + "\n")
tutorial_demo()
print("\n" + "=" * 60)
print("✅ All demos recorded!")
print("=" * 60)
What this code does:
- Defines browser steps (navigate, click, fill, scroll, wait)
- Adds a note to each step (what to say while this happens)
- Writes a narration script with
{{N}}markers synced to each step - Sends to PageBolt's
record_videoendpoint - Gets back an MP4 with AI voice + cursor highlights + browser frame
The narration script syncs automatically:
-
{{0}}fires during step 0 -
{{1}}fires during step 1 - And so on...
The voice reads each section while that step executes. No manual audio editing needed.
Real-World Example: See It In Action
Here's what the output looks like:
Video: https://streamable.com/do0vc5
What you see in the video:
- macOS browser frame
- Ocean gradient background
- Cursor highlights on each click
- AI voice narrating in real-time
- Perfect lip-sync between narration and action
- Professional, polished output
Total time to create this video: 5 minutes (define steps + script, hit send).
Time it would take in Loom: 2-3 hours (record, re-record, edit, export).
Use Cases & ROI
Use Case 1: Landing Page Hero
Record a 30-second product demo that auto-plays on your homepage.
Old workflow: Hire video editor, $300-500
New workflow: API call, $0.10
Savings: $300+ per video
Use Case 2: Feature Announcement
New feature ships. You announce it with a 2-minute demo video.
Old workflow: 3 hours recording + editing
New workflow: 5 minutes (write steps + script)
Savings: 2.75 hours per announcement
Use Case 3: Help Docs
10 help docs, each with a 1-minute demo video.
Old workflow: 30+ hours (3 hours per video)
New workflow: 50 minutes (5 minutes per video)
Savings: 25+ hours
Use Case 4: Sales Decks
Sales team uses 5 different demo videos in pitches.
Old workflow: 15 hours creating + updating
New workflow: 25 minutes creating + instant updates
Savings: 14.5 hours, plus instant updates when product changes
Production Tips
1. Write your script first — Narration should be conversational, not robotic:
❌ Bad: "This is the feature. Click the button."
✅ Good: "Here's the cool part. Just click here and watch."
2. Keep pacing natural — Default pace: "normal" works for most demos. Use "slow" for tutorials, "dramatic" for product launches.
3. Add waits strategically — Don't let the video race ahead:
{
"action": "click",
"selector": "[data-testid='submit']",
"note": "Click submit"
},
{
"action": "wait",
"ms": 2000, # Let the page load before next action
"live": True, # Show actual page rendering
"note": "Processing your request..."
}
4. Test with different viewports — Desktop (1920x1080) vs. tablet (768x1024) render differently. Record both if your product is responsive.
5. Update when product changes — Change one line of code, re-record the video. Instant updates. No manual editing.
Cost & Scale
| Plan | Videos/Month | 30-sec Video | 2-min Video | 5-min Video |
|---|---|---|---|---|
| Free | Limited | ✅ Yes (1) | ❌ No | ❌ No |
| Starter | 10 | ✅ Yes | ✅ Yes (3-4) | ⚠️ Limited |
| Growth | 100 | ✅ Yes | ✅ Yes (20+) | ✅ Yes (10+) |
| Scale | Unlimited | ✅ Yes | ✅ Yes | ✅ Yes |
A 2-minute demo = ~8 API calls (at 15 fps, ~120 frames per video).
One demo video per week = 4 videos/month = 32 API calls = Starter plan ($29/month).
One demo video per day = 30 videos/month = 240 API calls = Growth plan ($99/month).
The Differentiator
Every other screenshot/video API requires you to build the narration layer yourself. You upload pre-recorded audio. You sync timing manually. You edit afterward.
PageBolt's audioGuide with script + step notes does it in one call.
That's it. That's the product.
One API parameter. One narration script. One click. Professional demo video.
Ready to stop spending hours in Loom?
Record your first narrated demo in 5 minutes. Free tier lets you test. Growth plan covers a library of 20+ demo videos per month.
Top comments (0)