How to Build a Website Screenshot Cron Job with GitHub Actions

Automate visual monitoring and website archiving on a schedule for zero infrastructure cost.

📋 Table of Contents

Why Use GitHub Actions for Cron Jobs?

If you need to capture a screenshot of a dashboard every morning, track competitor pricing daily, or maintain a visual archive of your homepage over time, setting up dedicated server infrastructure just for cron jobs is overkill.

GitHub Actions provides a free, generous tier for running scheduled workflows using the schedule event trigger. By combining GitHub Actions with a Screenshot API, you can build a highly reliable, zero-maintenance screenshot automation pipeline.

The GitHub Actions Workflow File

Create a file in your repository at .github/workflows/screenshot-cron.yml. We'll configure it to run every day at midnight UTC:

name: Daily Website Screenshot
on:
  schedule:
    - cron: '0 0 * * *' # Runs every day at 00:00 UTC
  workflow_dispatch: # Allows manual triggering

jobs:
  capture:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install Dependencies
        run: npm ci

      - name: Run Screenshot Script
        env:
          SNAPAPI_KEY: ${{ secrets.SNAPAPI_KEY }}
        run: node scripts/capture.js

      - name: Commit and Push Changes
        run: |
          git config --global user.name "GitHub Action Bot"
          git config --global user.email "[email protected]"
          git add screenshots/
          git commit -m "Automated screenshot capture" || echo "No changes to commit"
          git push

Node.js Script Implementation

Next, we write the scripts/capture.js file that actually makes the request. Using SnapAPI ensures our GitHub Action completes in seconds rather than spending minutes installing headless browsers.

const fs = require('fs');
const path = require('path');
const https = require('https');

const API_KEY = process.env.SNAPAPI_KEY;
const TARGET_URL = 'https://news.ycombinator.com';
const DATE_STR = new Date().toISOString().split('T')[0];
const OUTPUT_FILE = path.join(__dirname, '../screenshots', `snapshot-${DATE_STR}.png`);

async function capture() {
  // Ensure directory exists
  fs.mkdirSync(path.join(__dirname, '../screenshots'), { recursive: true });

  const apiUrl = `https://snapapi.alterra-solutions.com/v1/screenshot?url=${encodeURIComponent(TARGET_URL)}&api_key=${API_KEY}&full_page=true`;

  console.log('Fetching screenshot...');
  
  const file = fs.createWriteStream(OUTPUT_FILE);
  https.get(apiUrl, (response) => {
    if (response.statusCode === 200) {
      response.pipe(file);
      file.on('finish', () => {
        file.close();
        console.log(`Screenshot saved to ${OUTPUT_FILE}`);
      });
    } else {
      console.error(`Error: Request failed with status code ${response.statusCode}`);
      process.exit(1);
    }
  }).on('error', (err) => {
    console.error(`Error: ${err.message}`);
    process.exit(1);
  });
}

capture();

Saving & Committing Results

In the workflow provided above, the final step uses Git commands to commit the newly generated PNG file from the screenshots/ directory back into the repository.

Alternatively, if you don't want to bloat your Git repository with large images, you can modify the workflow to use GitHub Actions Setup AWS CLI and sync the resulting images directly to an Amazon S3 bucket, or simply upload them as workflow artifacts using the actions/upload-artifact step.

Automate Your Screenshots Today

Get 100 free API requests per month to use with your GitHub Actions cron jobs.

Get Started Free →