← screencli   /   blog

Auto-Generate Demo Videos in Your CI/CD Pipeline

2026-04-01 · screencli
ci-cdgithub-actionsscreen-recordingdeveloper-toolsautomation

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:

  1. Your deploy step finishes — staging or production environment is live
  2. screencli step fires — the AI agent navigates your app and records the session
  3. Composed video uploads — a polished MP4 with a hosted link is produced
  4. 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

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:

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
PresetResolutionFormatUse case
youtube1920×1080mp4Full walkthrough, changelog
twitter1280×720mp4Social clip
instagram1080×1920mp4Vertical story
tiktok1080×1920mp4Short-form
linkedin1080×1080mp4Square post
github-gif800×450gifREADME / 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:

ApproachSetup per cycleRecording timeEditing timeTotal per release
Manual (Loom/Screen Studio)5 min10–20 min10–30 min25–55 min
GitHub Actions + screencli0 min (automated)~90 sec0 min~90 sec
Playwright raw video0 min~90 secManual pipeline10–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