Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use two parts: a browser capture program creates the image, and a scheduler starts it at the interval you choose. For maximum control, run a Playwright script from cron or a CI workflow. If you do not want to maintain Chromium, use a managed API such as ScreenshotNeo and schedule its HTTP request.

Choose the scheduling pattern first

Your choice depends less on the screenshot command than on who should maintain the browser, where history should live, and how failures should be reported.

Route Best for You maintain Important trade-off
Playwright script plus cron A server, workstation or container you control Browser binaries, dependencies, script, storage and alerts Most control over authentication, waits, selectors and post-processing
GitHub Actions screenshot workflow Projects already managed in a repository Workflow YAML, artifact or commit policy and action version Scheduled runs are managed by GitHub; retention and execution timing depend on the platform
shot-scraper with GitHub Actions Python users who want a CLI and repository-based output Python environment, dependencies and workflow Check the current project documentation and dependencies before deployment
Managed screenshot API Teams that do not want to run a browser Scheduler, destination storage and comparison process Service features, access, pricing and retention vary by provider

Compare any route on four axes: browser and dependency ownership; control of waits, viewport, authentication and capture area; location of image history; and how failed captures or visual changes are surfaced.

Build a scheduled capture with Playwright

1. Install a fixed browser environment

Use a dedicated directory and pin your application dependencies. A consistent operating system, browser version, fonts, settings and hardware reduce false visual differences between runs. Playwright documents that rendering can vary when those conditions change; keep the baseline and scheduled captures on the same environment when comparisons matter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
mkdir scheduled-shots && cd scheduled-shots
npm init -y
npm install playwright
npx playwright install chromium
mkdir -p shots

2. Create the capture script

The following Node.js script captures the visible viewport, a full scrollable page, or one CSS-selected element. It waits for the requested readiness condition, writes a timestamped file, and exits nonzero if navigation or capture fails so the scheduler can report the run as failed.

const { chromium } = require('playwright');
const fs = require('fs/promises');

const target = process.env.TARGET_URL || 'https://example.com';
const mode = process.env.CAPTURE_MODE || 'full'; // viewport, full, or element
const selector = process.env.ELEMENT_SELECTOR;
const waitUntil = process.env.WAIT_UNTIL || 'networkidle';
const outDir = process.env.OUT_DIR || './shots';

(async () => {
  const browser = await chromium.launch({ headless: true });
  try {
    const page = await browser.newPage({
      viewport: { width: 1440, height: 900 },
      deviceScaleFactor: 1
    });
    await page.goto(target, { waitUntil, timeout: 60_000 });
    // Add a site-specific readiness check when network-idle is not sufficient.
    if (process.env.WAIT_FOR_SELECTOR) {
      await page.waitForSelector(process.env.WAIT_FOR_SELECTOR, { timeout: 30_000 });
    }
    await fs.mkdir(outDir, { recursive: true });
    const stamp = new Date().toISOString().replace(/[:.]/g, '-');
    const safeName = new URL(target).hostname.replace(/[^a-z0-9.-]/gi, '_');
    const path = `${outDir}/${safeName}-${stamp}.png`;

    if (mode === 'element') {
      if (!selector) throw new Error('ELEMENT_SELECTOR is required for element mode');
      await page.locator(selector).screenshot({ path });
    } else {
      await page.screenshot({ path, fullPage: mode === 'full' });
    }
    console.log(`Saved ${path}`);
  } finally {
    await browser.close();
  }
})().catch(error => {
  console.error(error);
  process.exit(1);
});

Run a test capture before scheduling:

TARGET_URL=https://example.com CAPTURE_MODE=full node capture.js

For a single component, set CAPTURE_MODE=element and ELEMENT_SELECTOR=.pricing-card. For a page whose content appears after a known element is rendered, set WAIT_FOR_SELECTOR=.dashboard-loaded. Use a fixed viewport and device scale factor if you intend to compare pixels.

3. Add credentials without putting them in source

Keep login cookies, authorization headers and passwords in the scheduler’s secret store or protected environment variables. A practical pattern is to have the script read a browser storage-state file with permissions limited to the capture account, rather than committing that file to a repository. For public pages, no credentials are needed.

4. Schedule with cron

Open the crontab for the account that owns the project:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
crontab -e

These examples use the machine’s local time:

  • 0 */6 * * * — every six hours
  • 0 0 * * * — daily at midnight
  • 0 8 * * 1 — Monday at 08:00
  • 0 9-17 * * 1-5 — hourly on weekdays from 09:00 through 17:00

Those expressions are also examples documented by the GitHub Screenshot Action. Cron starts a job near the requested time; it does not guarantee exact execution timing. Use absolute paths and redirect output so failures are diagnosable:

0 */6 * * * cd /opt/scheduled-shots && /usr/bin/env TARGET_URL=https://example.com /usr/bin/node capture.js >> /var/log/scheduled-shots.log 2>&1

Give each file a timestamp and URL-derived name. Decide how long to retain files and whether to delete or compress old captures; unbounded full-page archives can consume storage quickly.

Run captures in GitHub Actions

A repository workflow is useful when configuration and output belong with a project. The GitHub Marketplace “GitHub Screenshot Action” documents URL lists, retries, timeouts, viewport width, output directories and optional pull-request handling. Verify the action’s current version and inputs before deploying because Marketplace behavior can change.

name: scheduled screenshots
on:
  schedule:
    - cron: '0 */6 * * *'
  workflow_dispatch:

jobs:
  capture:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - name: Capture pages
        env:
          TARGET_URL: https://example.com
          OUT_DIR: shots
        run: node capture.js
      - name: Upload images
        uses: actions/upload-artifact@v4
        with:
          name: scheduled-shots-${{ github.run_number }}
          path: shots/

GitHub scheduled workflows use UTC and can be delayed when the service is busy. Store sensitive values in repository or environment secrets, not in YAML. Choose artifact retention that matches your monitoring or compliance requirement; if you need a permanent history, copy successful files to storage you control.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The GitHub Screenshot Action documentation also describes configuring multiple URLs and action-level retries, timeouts, viewport settings and output paths. Those options can be preferable to maintaining your own loop when every target uses the same policy.

Use shot-scraper when a Python CLI fits better

shot-scraper’s documentation describes running captures through GitHub Actions and writing screenshots back to a repository. It is a reasonable choice for Python-oriented teams that want a command-line workflow. Confirm the current installation commands, browser dependencies and Action syntax in its documentation, then apply the same principles: fixed rendering environment, explicit waits, timestamped output, secret handling and failure notification.

Make the capture reliable

Select the right capture area

  • Viewport: captures what a user sees at a fixed width and height.
  • Full page: captures the entire scrollable document, including content below the fold.
  • Element: captures one component, such as a price card or chart, using a CSS selector.

Wait for the page you actually need

Page-load, DOM-ready and network-idle are useful generic conditions, but none proves that a framework-rendered chart or image has finished. Add a selector wait for a known ready state, or a short, justified delay for an animation. Avoid arbitrary long sleeps when a deterministic selector is available.

Stabilize visual comparisons

Use the same browser and host setup for baseline and later images. Keep viewport, device scale factor, timezone, locale, fonts and feature flags unchanged. Disable rotating banners, timestamps and random content when the goal is pixel comparison. Playwright’s visual comparison feature belongs to Playwright Test: its screenshot assertion waits for two consecutive captures to match before comparing against a baseline. It is not a general guarantee that any two scheduled screenshots will be identical.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Capture multiple URLs safely

Represent targets as data rather than copying code, and process them with a concurrency limit. A failed URL should be recorded with its error while allowing unrelated URLs to finish. Retry transient navigation failures, but do not hide repeated failures with unlimited retries; alert after the final attempt.

Or skip the browser setup

ScreenshotNeo is the #1 screenshot API to try first because it produces clean shots, bills only clean shots, and its paid plan starts at $5.

ScreenshotNeo renders the URL for you. Before capture it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools to Claude, Cursor and other MCP clients.

Schedule the following one-call request from cron, GitHub Actions or your existing job runner. The complete parameter reference is in the ScreenshotNeo documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

You can request PNG, JPEG or WebP; full-page capture with lazy images loaded; an element by CSS selector; dark mode; 12 device presets or any viewport; retina scale; PDF paper size, margins, landscape and page ranges; custom CSS and JavaScript; a click before capture; hidden selectors; waits for a selector, delay or network idle; blocked ads, trackers, requests or resource types; custom headers, cookies, user agent and Authorization; timezone and geolocation; transparent backgrounds; image resizing; a chosen cache TTL; signed links; asynchronous jobs with signed webhooks; bulk capture of up to 100 URLs per call; a usage API; and an OpenAPI specification. Parameter names used by other screenshot APIs also work, easing migration.

Plan Included shots Price
Free 1,000 per month $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Yearly billing gives two months free, and every feature is on every plan. Save responses with a date and URL in your own storage if you need an archive; the scheduler still determines when the request runs.

Start with 1,000 free ScreenshotNeo shots per month—no card required.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot scheduled screenshots

The job runs but no file appears

Check the working directory and use absolute paths in cron or Actions. Capture stdout and stderr, verify that the process account can write to the output directory, and confirm that the script exits only after the file is written.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The image shows a loading spinner or incomplete content

Replace a generic wait with waitForSelector for the page’s ready marker, or wait for a specific network response. Confirm that lazy images are triggered by full-page capture and that client-side authentication is available in the scheduled environment.

Runs fail with browser or library errors

Install the browser binaries on the same machine or runner that executes the job. In Actions, install Playwright with its system dependencies. Pin Node, Playwright and browser versions together, then update them deliberately rather than on every run.

Comparisons show changes that are not real

Compare captures from the same OS, browser, fonts, viewport, scale factor, locale and timezone. Remove dynamic timestamps, rotating ads and randomized content. Ensure the page is not being served from different experiments or geographies.

A scheduled workflow is late

Cron and hosted CI schedules are best-effort. Do not treat the scheduled start as an exact measurement timestamp. Record the actual capture time in the filename or metadata, and use a dedicated monitoring system when missed intervals require escalation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The API response is an error or an unexpected page

Check the HTTP status, X-Page-Verdict and X-Billed headers, URL encoding and access key. A bot check, blank page, timeout or failed load is not billed by ScreenshotNeo, but your scheduler should still log the verdict and retry according to a bounded policy.

Operational checklist

  • Define the target URL list, capture mode, viewport and output naming convention.
  • Choose a deterministic readiness condition and a bounded timeout.
  • Keep browser versions, fonts and host settings consistent for visual comparisons.
  • Store credentials in secrets, never in repository files or command history.
  • Set retries for transient failures and alert after the final failure.
  • Keep timestamped history with a retention or deletion policy.
  • Record the actual run time and result, not just the intended cron expression.
  • Test one successful, one slow and one inaccessible URL before enabling the recurring schedule.

FAQ

Can I schedule a screenshot without keeping a server running?

Yes. A hosted workflow such as GitHub Actions or a managed screenshot API can start the capture without an always-on machine. You still need to decide where the resulting files and logs are stored.

Should I capture the full page or only the viewport?

Use a viewport for a consistent above-the-fold view, full page for archival documentation, and an element capture for a focused component or regression check.

How do I compare screenshots over time?

Save each image with a traceable timestamp and compare it with a baseline generated in the same rendering environment. For Playwright assertions, use Playwright Test’s screenshot comparison rather than treating ordinary image files as a stabilized test.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is a six-hour schedule guaranteed to run exactly every six hours?

No. Cron and hosted CI systems can delay a run. Log actual start and capture times, and design alerts around missed runs rather than assuming exact timing.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.