TL;DR: Manually re-recording demos after every deploy is one of the most common time sinks in developer-led growth. With screencli, you can add a single GitHub Actions step that runs after each deploy, drives your app with an AI agent, and produces a polished, shareable demo video — with no human involved. Fresh demos on every release, for free.
Why Demo Videos Go Stale
Demo videos go stale because nobody regenerates them. The feature ships, the UI changes by one pixel, the button moves, and the old recording sits on the landing page showing a version of the product that no longer exists.
According to Walnut’s 2025 State of the Demo report, 62% of SaaS teams update their demos less than once a quarter — even when they ship weekly. The bottleneck isn’t motivation. It’s the 30–90 minutes it takes to re-record, trim, and re-upload a polished video every time something changes.
The fix is treating demo videos the same way you treat test coverage: generate them automatically as part of your release process.
GitHub Actions already runs on every deploy. GitHub Copilot’s coding agent now ships with Playwright MCP auto-configured for browser interactions. The tooling is there. The missing piece is the recording layer — and that’s what screencli adds.
The Architecture
The pattern is straightforward:
- Your deploy step finishes — staging or production environment is live
- screencli step fires — the AI agent navigates your app and records the session
- Composed video uploads — a polished MP4 with a hosted link is produced
- Link is posted — as a PR comment, Slack message, release note, or all three
No human touches a screen recorder. No editor. No retakes.
Here’s what the full pipeline looks like:
# .github/workflows/demo.yml
name: Generate Demo Video
on:
push:
branches: [main]
release:
types: [published]
jobs:
demo:
runs-on: ubuntu-latest
needs: deploy # Wait for deploy job to finish
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Record demo video
env:
SCREENCLI_TOKEN: ${{ secrets.SCREENCLI_TOKEN }}
run: |
npx screencli record https://your-app.com \
--prompt "Navigate to the dashboard, filter by last 30 days, and export the monthly report" \
--output recordings/demo.mp4 \
--upload
- name: Post demo link to PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const meta = JSON.parse(fs.readFileSync('recordings/demo.mp4.json', 'utf8'));
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `**Demo video generated:** ${meta.url}\n\nGenerated automatically by screencli.`
});
The SCREENCLI_TOKEN is your screencli API key, saved as a GitHub Actions secret. The --upload flag pushes the composed video to screencli’s cloud and writes a JSON file with the shareable URL.
Step-by-Step Setup
Step 1: Install screencli and authenticate
# Install globally (optional — npx works too)
npm install -g screencli
# Authenticate with screencli cloud
npx screencli login
Sign in with GitHub. You get 10 free recordings per month on the free tier, or 100/month on the $12/month Pro plan. After login, your token is saved to ~/.screencli/config.json.
Step 2: Create the secret
In your GitHub repo: Settings → Secrets and variables → Actions → New repository secret
- Name:
SCREENCLI_TOKEN - Value: run
npx screencli tokenin your terminal to get the value
Step 3: Write your demo prompt
The prompt is the most important variable. Write it like you’re describing the demo to a junior developer who will click through the UI:
# Too vague — agent may take a wrong path
--prompt "Show the dashboard"
# Better — specific flow with observable outcomes
--prompt "Click 'Sign in with GitHub', wait for the dashboard,
click the 'Last 30 days' filter, then click 'Export CSV'"
Start with a public page to verify the recording works before adding auth. Then layer in --auth for pages behind login walls (see Step 4).
Step 4: Handle authentication
Most demos require a logged-in state. Use screencli’s auth handoff to capture a session once, then replay it:
# One-time: log in manually and save the session
npx screencli record https://app.example.com \
--prompt "Show the analytics dashboard" \
--login \
--auth myapp
This opens a browser, lets you log in manually, then hands off to the AI agent. The session is saved to ~/.screencli/auth/myapp.json.
For CI, commit the auth state to an encrypted secret:
# Encode the auth file
cat ~/.screencli/auth/myapp.json | base64
Add the base64 output as a GitHub secret (SCREENCLI_AUTH_MYAPP), then decode it in CI before recording:
- name: Restore auth session
run: |
mkdir -p ~/.screencli/auth
echo "${{ secrets.SCREENCLI_AUTH_MYAPP }}" | base64 -d > ~/.screencli/auth/myapp.json
- name: Record authenticated demo
env:
SCREENCLI_TOKEN: ${{ secrets.SCREENCLI_TOKEN }}
run: |
npx screencli record https://app.example.com \
--prompt "Navigate to the analytics dashboard and show the Q1 summary" \
--auth myapp \
--upload
Your credentials are never visible in the recording. The auth session is scoped to the saved state file, not baked into the video.
What the Output Looks Like
Every screencli recording produces:
composed.mp4— A 1920×1080 MP4 with gradient background, rounded corners, drop shadow, auto-zoom to each action, click highlights, and smooth cursor trails. No raw browser chrome.- A hosted shareable link —
https://screencli.sh/v/{id}— ready to paste into a PR, changelog, or tweet metadata.json— Timestamps, action log, chapter markers
The video is post-processed by a single FFmpeg pass: idle time between actions is trimmed (a 3-minute navigation session becomes a 30-second video), the camera auto-zooms into the area where the agent clicks, and a gradient background frames the browser window.
You can override the background gradient per workflow:
run: |
npx screencli record https://your-app.com \
--prompt "Walk through the onboarding flow" \
--background midnight \
--upload
Available gradients: midnight, ember, forest, nebula, slate, copper.
Platform Exports Built In
If you need format-specific exports alongside the default MP4, add an export step:
- name: Export for social
run: |
# Twitter-optimized clip
npx screencli export ./recordings \
--preset twitter \
--output recordings/demo-twitter.mp4
# GitHub README GIF
npx screencli export ./recordings \
--preset github-gif \
--output recordings/demo.gif
| Preset | Resolution | Format | Use case |
|---|---|---|---|
youtube | 1920×1080 | mp4 | Full walkthrough, changelog |
twitter | 1280×720 | mp4 | Social clip |
instagram | 1080×1920 | mp4 | Vertical story |
tiktok | 1080×1920 | mp4 | Short-form |
linkedin | 1080×1080 | mp4 | Square post |
github-gif | 800×450 | gif | README / PR |
GIF export uses a two-pass palettegen process for clean colors and small file sizes — no additional tools needed.
Practical Patterns
Pattern 1: Record on every release tag
Only trigger demo recording when you cut a release, not on every commit:
on:
release:
types: [published]
This keeps recording costs down on the free tier (10 recordings/month) and ensures recordings are tied to versioned releases rather than every WIP commit.
Pattern 2: One workflow, multiple demos
Record multiple flows in a single job — each gets its own output and link:
- name: Record onboarding demo
run: |
npx screencli record https://your-app.com \
--prompt "Click Sign Up, fill in the form, confirm email, reach dashboard" \
--output recordings/onboarding.mp4 \
--upload
- name: Record checkout demo
run: |
npx screencli record https://your-app.com \
--prompt "Add an item to cart, proceed to checkout, complete purchase" \
--auth myapp \
--output recordings/checkout.mp4 \
--upload
Each step runs sequentially and produces its own link.
Pattern 3: Update your README automatically
Parse the output JSON and update your README.md with the latest demo link using a GitHub Actions step:
- name: Update README demo link
run: |
DEMO_URL=$(jq -r '.url' recordings/demo.mp4.json)
sed -i "s|<!-- DEMO_URL -->.*|<!-- DEMO_URL --> ${DEMO_URL}|" README.md
git config user.email "actions@github.com"
git config user.name "GitHub Actions"
git add README.md
git commit -m "chore: update demo video [skip ci]"
git push
Your README always links to the latest recording. No manual updates.
screencli vs. Manual Recording in a Release Workflow
The comparison is stark when you count the actual time cost across a team shipping twice a week:
| Approach | Setup per cycle | Recording time | Editing time | Total per release |
|---|---|---|---|---|
| Manual (Loom/Screen Studio) | 5 min | 10–20 min | 10–30 min | 25–55 min |
| GitHub Actions + screencli | 0 min (automated) | ~90 sec | 0 min | ~90 sec |
| Playwright raw video | 0 min | ~90 sec | Manual pipeline | 10–20 min |
At two releases per week, manual recording costs 50–110 minutes per week on demo maintenance alone. GitHub Actions + screencli reduces that to near zero.
The contrast with Playwright’s built-in video recording is also worth noting: Playwright can record test runs, but the output is raw — no effects, no hosting, no post-production. screencli wraps Playwright’s engine and adds the full post-processing pipeline (auto-zoom, click highlights, gradient background, idle trimming) and cloud hosting on top.
Who This Is For
Solo founders shipping fast: Your changelog needs fresh demos every week. This workflow generates them in the background while you sleep.
Developer advocates: Record the same flows across staging environments automatically. A CI trigger means you always have a current recording for documentation.
QA engineers: Capture not just test results but test sessions — a recording of the agent navigating through a flow is a shareable artifact that developers can watch and reproduce.
Open-source maintainers: Keep your README GIF current with zero effort. Every release tag generates a fresh demo.gif and commits it automatically.
FAQ
Does screencli work on GitHub Actions’ Ubuntu runners?
Yes. screencli runs headless on any Linux environment with Node.js 18+ installed. The npx playwright install --with-deps chromium step handles the browser dependencies. The entire pipeline runs in a standard ubuntu-latest runner.
How do I keep auth sessions from expiring in CI?
screencli saves browser state (cookies, localStorage) to the auth file. Most sessions persist 30–90 days. When they expire, re-run the --login command locally to refresh the auth file, re-encode it, and update the GitHub secret.
What’s the token cost per recording?
Each screencli cloud recording costs 1 credit (covering up to 10 agent steps). The free tier includes 10 credits/month. With a direct ANTHROPIC_API_KEY set as a CI secret, recording uses your own Anthropic account — typically $0.01–$0.05 per session with Claude Haiku.
Can I trigger recordings on staging before production deploys? Yes. Set the URL in your workflow to point at your staging environment and add the recording step between your staging and production deploy steps. Use the shareable link as a visual sanity check before cutting a release.
Does screencli support multi-step flows with conditionals? The AI agent handles common conditional flows (like checking whether a user is already logged in before navigating). For complex branching, break flows into separate recordings with explicit prompts — one recording per distinct flow is more reliable than one recording trying to cover every path.
What about Loom for CI/CD? Loom has no CI/CD integration or headless mode. It requires a human operating a browser. Post-Atlassian acquisition, Loom’s pricing has also increased significantly — the Business plan is now $15/user/month, with Enterprise migration still incomplete as of mid-2026. For automated demo generation in a pipeline, screencli is the only purpose-built option.
Run your first automated demo: npx screencli record https://your-app.com -p "Walk through the key feature flow" → screencli.sh