DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

GitHub Actions Screenshots: Auto-Capture Deploy Evidence (5-Minute Setup)

GitHub Actions Screenshots: Auto-Capture Deploy Evidence (5-Minute Setup)

In regulated industries, "prove what shipped" isn't optional — it's compliance. When you deploy to production, auditors want evidence: screenshots of the UI state, configuration pages, deployment logs, environment settings.

Most teams solve this manually: engineers take screenshots, attach them to Slack, lose them when the thread archives. There's a better way: automatically capture screenshots in GitHub Actions and attach them to every PR.

Here's how to set it up in 5 minutes.

The Problem: Manual Screenshot Chaos

Right now, your team probably:

  • Deploys to staging manually and takes screenshots
  • Posts them to Slack (where they disappear in 90 days)
  • Or writes them to a shared folder (that nobody actually accesses)
  • Auditors ask "what did you ship?" → panic → search Slack archives

The evidence trail is broken.

The Solution: Automated Screenshots in GitHub Actions

Here's a GitHub Actions workflow that:

  1. Runs after deployment
  2. Takes a screenshot of your app
  3. Attaches it to the PR
  4. Sends a notification to your team
name: Deploy & Screenshot

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Deploy to Staging
        run: |
          # Your deployment commands
          npm run build
          npm run deploy:staging

      - name: Wait for Deploy
        run: sleep 30

      - name: Capture Screenshots
        env:
          PAGEBOLT_API_KEY: ${{ secrets.PAGEBOLT_API_KEY }}
        run: |
          node capture-screenshots.js

      - name: Upload Screenshots to PR
        uses: actions/upload-artifact@v3
        with:
          name: deploy-screenshots
          path: screenshots/

      - name: Comment on PR
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const screenshots = fs.readdirSync('screenshots/');

            let comment = '## šŸ“ø Deployment Screenshots\n\n';
            screenshots.forEach(file => {
              comment += `- [${file}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }})\n`;
            });

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: comment
            });
Enter fullscreen mode Exit fullscreen mode

The Screenshot Capture Script

Create capture-screenshots.js:

const fetch = require('node-fetch');
const fs = require('fs');
const path = require('path');

const PAGEBOLT_API_KEY = process.env.PAGEBOLT_API_KEY;
const STAGING_URL = process.env.STAGING_URL || 'https://staging.example.com';

async function captureScreenshots() {
  const screenshots = [
    {
      name: 'homepage.png',
      url: `${STAGING_URL}/`,
      viewport: { width: 1280, height: 720 }
    },
    {
      name: 'dashboard.png',
      url: `${STAGING_URL}/dashboard`,
      viewport: { width: 1280, height: 720 }
    },
    {
      name: 'settings.png',
      url: `${STAGING_URL}/settings`,
      viewport: { width: 1280, height: 720 }
    }
  ];

  const dir = 'screenshots';
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }

  for (const screenshot of screenshots) {
    try {
      console.log(`Capturing ${screenshot.name}...`);

      const response = await fetch('https://api.pagebolt.com/v1/screenshot', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${PAGEBOLT_API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          url: screenshot.url,
          viewport: screenshot.viewport,
          format: 'png'
        })
      });

      if (!response.ok) {
        console.error(`Failed to capture ${screenshot.name}: ${response.statusText}`);
        continue;
      }

      const buffer = await response.buffer();
      fs.writeFileSync(path.join(dir, screenshot.name), buffer);
      console.log(`āœ“ Saved ${screenshot.name}`);
    } catch (error) {
      console.error(`Error capturing ${screenshot.name}:`, error.message);
    }
  }

  console.log(`\nāœ“ All screenshots captured and saved to ${dir}/`);
}

captureScreenshots().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Real-World Example: Compliance Evidence

For regulated industries (fintech, healthcare, insurance), this workflow creates an audit trail:

// capture-screenshots.js with compliance metadata
async function captureWithMetadata() {
  const metadata = {
    timestamp: new Date().toISOString(),
    commit: process.env.GITHUB_SHA,
    branch: process.env.GITHUB_REF,
    environment: 'staging',
    version: require('./package.json').version
  };

  const response = await fetch('https://api.pagebolt.com/v1/screenshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.PAGEBOLT_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: 'https://staging.example.com/dashboard',
      viewport: { width: 1280, height: 720 },
      format: 'png',
      // Metadata persists with the screenshot
      metadata: metadata
    })
  });

  const buffer = await response.buffer();

  // Save with metadata in filename
  const filename = `screenshot-${metadata.timestamp.replace(/[:.]/g, '-')}.png`;
  fs.writeFileSync(path.join('screenshots', filename), buffer);

  console.log(`āœ“ Screenshot saved with compliance metadata`);
}
Enter fullscreen mode Exit fullscreen mode

Environment Setup

Add to GitHub Secrets:

PAGEBOLT_API_KEY: pf_live_xxx
STAGING_URL: https://staging.example.com
Enter fullscreen mode Exit fullscreen mode

Why This Beats Manual Screenshots

Manual approach:

  • Engineer screenshots locally (5 min per deploy)
  • Posts to Slack (lost after 90 days)
  • Audit asks "what shipped?" → dig through archives
  • No timestamp, no commit metadata, no proof

Automated approach:

  • Zero manual work per deploy
  • Screenshots attached to PR (permanent record)
  • Metadata (commit, timestamp, environment) embedded
  • Audit asks "what shipped?" → GitHub link + screenshot = instant proof
  • Cost: $29-79/month vs. 5 minutes Ɨ $150/hr Ɨ weekly deploys = $1,560/month in engineer time

For teams shipping frequently (10+ deploys/week), automated screenshots save money and create compliance evidence simultaneously.

Next Steps

  1. Copy the workflow YAML to .github/workflows/deploy-screenshots.yml
  2. Copy capture-screenshots.js to your repo root
  3. Add PAGEBOLT_API_KEY to GitHub Secrets
  4. Deploy → see screenshots auto-attached to PR
  5. Auditors see proof of what shipped āœ“

Start free at pagebolt.dev/pricing — 100 screenshots/month, no credit card required.


For regulated teams: Screenshot automation + GitHub PR history = SOC 2 / compliance-grade deployment evidence. No manual work. No lost screenshots. Just proof.

Top comments (0)