Skip to content

Automated Updates ​

You've defined your screenshots locally. They capture your app perfectly. But your app keeps changing - new features, design tweaks, bug fixes. Running npx heroshot manually every time gets old fast.

The solution: let CI do it. Set up a workflow that regenerates screenshots automatically, commits them, and you never think about it again.

The Flow ​

Here's what happens:

  1. You set up screenshots locally with npx heroshot (the visual picker)
  2. You commit .heroshot/config.json to your repo
  3. A GitHub Action runs heroshot whenever you want
  4. Fresh screenshots get committed back to your repo

If your site needs login, there's one extra step - exporting your session key so CI can authenticate. More on that below.

Basic Setup (No Auth Required) ​

If your screenshots are on public pages, setup is simple. Create .github/workflows/heroshot.yml:

yaml
name: Update Screenshots

on:
  workflow_dispatch: # Manual trigger from Actions tab

jobs:
  screenshots:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Capture screenshots
        run: npx heroshot

      - name: Commit changes
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add heroshots/
          git diff --staged --quiet || git commit -m "chore: update screenshots"
          git push

That's it. Go to Actions → Update Screenshots → Run workflow. Your screenshots regenerate and commit.

Sites That Need Login ​

Here's where heroshot really shines. When you run heroshot config locally and log into your app, that session gets encrypted and saved to .heroshot/session.enc. The encryption key is derived from your machine by default.

For CI to decrypt that session, you need to export the key:

bash
npx heroshot session-key

This prints a ~44 character string. That's your session key - treat it like a password.

Add It to GitHub Secrets ​

Using the GitHub CLI:

bash
gh secret set HEROSHOT_SESSION_KEY
# Paste your key when prompted

Or manually: Repository → Settings → Secrets and variables → Actions → New repository secret.

Update the Workflow ​

Pass the key to heroshot:

yaml
- name: Capture screenshots
  run: npx heroshot
  env:
    HEROSHOT_SESSION_KEY: ${{ secrets.HEROSHOT_SESSION_KEY }}

Now CI can restore your authenticated session. No login scripts, no credential management, no flaky waits for login forms.

When to Trigger ​

Manual Only ​

Start here. Trigger from the Actions tab when you know things changed:

yaml
on:
  workflow_dispatch:

On a Schedule ​

Once you trust the setup, run it automatically. Daily, weekly, whatever fits:

yaml
on:
  workflow_dispatch:
  schedule:
    - cron: '0 6 * * 1' # Every Monday at 6 AM UTC

After Deployments ​

If you deploy via GitHub Actions, trigger screenshots after:

yaml
on:
  workflow_dispatch:
  workflow_run:
    workflows: ['Deploy']
    types: [completed]

On Push to Main ​

Aggressive, but ensures screenshots are always current:

yaml
on:
  workflow_dispatch:
  push:
    branches: [main]
    paths:
      - 'src/**' # Only when source changes
      - '!src/**/*.md' # Ignore docs

Full Workflow Example ​

Here's a complete workflow with auth, error handling, and PR creation instead of direct push:

yaml
name: Update Screenshots

on:
  workflow_dispatch:
  schedule:
    - cron: '0 6 * * 1' # Weekly on Monday

jobs:
  screenshots:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Capture screenshots
        run: npx heroshot --clean
        env:
          HEROSHOT_SESSION_KEY: ${{ secrets.HEROSHOT_SESSION_KEY }}

      - name: Check for changes
        id: changes
        run: |
          git add heroshots/
          if git diff --staged --quiet; then
            echo "changed=false" >> $GITHUB_OUTPUT
          else
            echo "changed=true" >> $GITHUB_OUTPUT
          fi

      - name: Create Pull Request
        if: steps.changes.outputs.changed == 'true'
        uses: peter-evans/create-pull-request@v6
        with:
          commit-message: 'chore: update screenshots'
          title: 'Update screenshots'
          body: 'Automated screenshot refresh by Heroshot'
          branch: heroshot-updates

This creates a PR instead of pushing directly - useful if you want to review changes before merging.

What Gets Committed ​

Only your screenshot images (the heroshots/ folder by default). The encrypted session file .heroshot/session.enc is already in your repo from when you first set things up - it doesn't change during CI runs.

Security Notes ​

Your session key is stored as a GitHub secret. It never appears in logs. Without it, the encrypted session file is useless.

The session file (.heroshot/session.enc) uses AES-256-GCM encryption. It's safe to commit - it contains no plaintext credentials.

Session expiry - If your app's sessions expire (most do eventually), you'll need to re-authenticate locally and commit the new session file. Run heroshot config --reset to clear the old session and log in fresh.

Debugging ​

If screenshots aren't updating as expected:

yaml
- name: Capture screenshots
  run: npx heroshot -v # Verbose output
  env:
    HEROSHOT_SESSION_KEY: ${{ secrets.HEROSHOT_SESSION_KEY }}

The -v flag shows what heroshot is doing - which URLs it's visiting, which selectors it's finding, what files it's writing.

Local Testing ​

Before pushing your workflow, test that the session key works:

bash
# Pretend to be CI - use the key explicitly instead of machine-derived
npx heroshot --session-key="your-key-here"

If this works locally, it'll work in CI.

Repository Size ​

One thing to watch: every time CI regenerates screenshots, Git stores new copies of those binary files. Over months of weekly updates, your repo can grow significantly.

If you have more than 20-30 screenshots or you're running automated updates frequently, consider using Git LFS. It keeps your repo lean by storing images separately.

See Version Control for a complete walkthrough of setting up Git LFS with Heroshot.