How to Auto-Generate a Narrated Demo Video on Every Pull Request
Every PR tells a story. Most teams tell it in words. This one records it. A 20-line GitHub Actions workflow that generates a narrated MP4 demo on every PR — attached directly to the thread.
With a 20-line GitHub Actions workflow and the PageBolt video API, you can automatically generate a narrated MP4 demo every time someone opens a pull request — showing the actual feature, with an AI voice walking through it, attached directly to the PR thread.
Here's how to set it up.
What you'll end up with
A GitHub Actions job that:
- Calls the PageBolt video API with a hardcoded walkthrough of your app
- Downloads the MP4 recording (with audio narration)
- Uploads it as a GitHub Actions artifact
- Posts a PR comment with a direct download link
The video is generated fresh on every PR. The steps are fixed — this works best for features with a stable URL and consistent UI.
The API call
PageBolt's /v1/video endpoint accepts a list of browser steps and returns a binary MP4. Pass audioGuide to add AI voice narration synced to each step.
curl -X POST https://api.pagebolt.dev/v1/video \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{ "action": "navigate", "url": "https://staging.yourapp.com", "note": "Opening the app" },
{ "action": "click", "selector": "#create-btn", "note": "Creating a new record" },
{ "action": "fill", "selector": "#name-input", "value": "Demo item" },
{ "action": "click", "selector": "#submit-btn", "note": "Submitting the form" },
{ "action": "wait", "ms": 1200 },
{ "action": "screenshot", "name": "result" }
],
"audioGuide": {
"enabled": true,
"voice": "emma",
"script": "Welcome to the demo. {{1}} We click Create to open the form. {{3}} Fill in the name and submit. {{5}} The record is saved."
},
"pace": "slow",
"frame": { "enabled": true, "style": "macos" }
}' \
--output demo.mp4
That's the full call. No CLI, no special action — just curl. The --output demo.mp4 flag writes the binary response directly to disk.
The audioGuide.script field uses {{N}} markers synchronized to step numbers. The AI voice narrates as each step executes.
The GitHub Actions workflow
name: PR Demo Video
on:
pull_request:
types: [opened, synchronize]
jobs:
record-demo:
runs-on: ubuntu-latest
steps:
- name: Record demo video
run: |
curl -X POST https://api.pagebolt.dev/v1/video \
-H "x-api-key: ${{ secrets.PAGEBOLT_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"steps": [
{ "action": "navigate", "url": "https://staging.yourapp.com", "note": "Opening the app" },
{ "action": "click", "selector": "#create-btn", "note": "Starting a new record" },
{ "action": "fill", "selector": "#name-input", "value": "Demo item" },
{ "action": "click", "selector": "#submit-btn", "note": "Submitting" },
{ "action": "wait", "ms": 1200 },
{ "action": "screenshot", "name": "result" }
],
"audioGuide": {
"enabled": true,
"voice": "emma",
"script": "Welcome. {{1}} Click Create to open the form. {{3}} Fill in the name and submit. {{5}} Done."
},
"pace": "slow",
"frame": { "enabled": true, "style": "macos" }
}' \
--output demo.mp4
- name: Upload video artifact
uses: actions/upload-artifact@v4
with:
name: pr-demo-${{ github.event.pull_request.number }}
path: demo.mp4
retention-days: 14
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const runUrl = `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Demo video\n\nA narrated walkthrough was recorded for this PR.\n\n[Download demo.mp4](${runUrl}) — available under the **Artifacts** section of this run (requires GitHub login).\n\n*Generated by PageBolt*`
});
Add your API key to GitHub Secrets as PAGEBOLT_API_KEY and you're done.
What reviewers see
When the workflow completes, the bot posts a comment with a link directly to the Actions run. Reviewers click through to the Artifacts panel and download the MP4. GitHub keeps artifacts for 14 days by default.
The video shows the actual UI, in the browser, with the AI narrator explaining what's happening. For features that are hard to describe in text — drag-and-drop flows, animations, multi-step forms — this makes the PR self-documenting.
Customizing the steps
The steps array maps directly to what PageBolt's browser does:
navigate— go to a URLclick— click an element by CSS selectorfill— type into an inputhover— hover over an elementscroll— scroll to a positionwait— pause for a given number of millisecondsscreenshot— capture a frame (these get embedded in the video timeline)
If your staging URL changes per PR (e.g., Vercel preview deployments), pass it as an environment variable:
- name: Record demo video
env:
STAGING_URL: ${{ github.event.deployment.payload.web_url }}
run: |
curl -X POST https://api.pagebolt.dev/v1/video \
-H "x-api-key: ${{ secrets.PAGEBOLT_API_KEY }}" \
-H "Content-Type: application/json" \
-d "{
\"steps\": [
{ \"action\": \"navigate\", \"url\": \"$STAGING_URL\" },
{ \"action\": \"screenshot\", \"name\": \"home\" }
]
}" \
--output demo.mp4
Adding narration
The audioGuide parameter is where the video goes from useful to genuinely impressive. Instead of a silent screen recording, reviewers hear a voice walking through exactly what changed and why it matters.
Voices available: ava, andrew, emma, brian, aria, guy, jenny (Azure), or alloy, echo, fable, nova, onyx, shimmer (OpenAI). Switch providers with the provider field:
"audioGuide": {
"enabled": true,
"provider": "openai",
"voice": "nova",
"script": "Here's the new checkout flow. {{1}} We open the cart. {{2}} The discount is applied automatically. {{3}} Checkout completes in one click."
}
Automated video demos don't require a custom CI plugin or a dedicated recording service. One curl call, one artifact upload, one PR comment. The whole thing runs in under 30 seconds per PR.
Try it free
100 requests/month, no credit card. Add your API key to GitHub Secrets and your next PR gets a narrated demo video automatically.
Get API Key — Free