{"id":25543475,"url":"https://github.com/guibranco/github-screenshot-action","last_synced_at":"2026-05-10T04:40:23.338Z","repository":{"id":346293500,"uuid":"1186427623","full_name":"guibranco/github-screenshot-action","owner":"guibranco","description":"📸 A reusable GitHub Action to capture, monitor, and version website screenshots from a JSON list with parallel execution, retries, and cron-based change detection","archived":false,"fork":false,"pushed_at":"2026-04-20T05:35:27.000Z","size":453,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T07:37:35.014Z","etag":null,"topics":["gha","github-actions","githubactions","screenshot"],"latest_commit_sha":null,"homepage":"http://guilherme.stracini.com.br/github-screenshot-action/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guibranco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-19T16:02:39.000Z","updated_at":"2026-04-20T05:33:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/guibranco/github-screenshot-action","commit_stats":null,"previous_names":["guibranco/github-screenshot-action"],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/guibranco/github-screenshot-action","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guibranco%2Fgithub-screenshot-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guibranco%2Fgithub-screenshot-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guibranco%2Fgithub-screenshot-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guibranco%2Fgithub-screenshot-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guibranco","download_url":"https://codeload.github.com/guibranco/github-screenshot-action/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guibranco%2Fgithub-screenshot-action/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32326125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gha","github-actions","githubactions","screenshot"],"created_at":"2025-02-20T07:19:34.275Z","updated_at":"2026-04-27T07:02:49.254Z","avatar_url":"https://github.com/guibranco.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/guibranco/github-screenshot-action/main/logo.png\" alt=\"logo\" width=\"120\" height=\"120\" /\u003e\n\u003c/p\u003e\n\n# 📸 github-screenshot-action\n\n**Capture, monitor, and version website screenshots — automatically.**\n\nA reusable GitHub Action that takes screenshots of websites from a JSON list, with parallel execution, retry logic, cron scheduling, and automated PR creation.\n\n[![GitHub release](https://img.shields.io/github/v/release/guibranco/github-screenshot-action?color=7c3aed\u0026style=flat-square)](https://github.com/guibranco/github-screenshot-action/releases)\n[![License: MIT](https://img.shields.io/badge/license-MIT-22c55e?style=flat-square)](LICENSE)\n[![Docker Image](https://img.shields.io/badge/ghcr.io-guibranco%2Fgithub--screenshot--action-0ea5e9?style=flat-square\u0026logo=docker)](https://ghcr.io/guibranco/github-screenshot-action)\n[![Maintained](https://img.shields.io/badge/maintained-yes-f59e0b?style=flat-square)](https://github.com/guibranco/github-screenshot-action)\n\n---\n\n## ✨ Features\n\n| Feature | Description |\n|---|---|\n| 📄 **JSON-driven** | Define all your target sites in a simple JSON file — no code changes needed |\n| ⚡ **Parallel execution** | Configurable concurrency to capture multiple sites simultaneously |\n| 🔁 **Retry \u0026 timeout** | Automatically retries failed captures with configurable limits |\n| 🕐 **Cron scheduling** | Run on any schedule to monitor visual changes over time |\n| 🌿 **Branch isolation** | Screenshots are committed to a dedicated branch, keeping `main` clean |\n| 🔀 **Automated PRs** | Optionally open a pull request automatically after each monitoring run |\n| 🐳 **Pre-built Docker image** | No cold build — uses a pre-published image from GHCR for fast startup |\n| 🔐 **Chromium-based** | Full Puppeteer + Chromium stack for accurate, real-browser rendering |\n| ⏳ **Wait strategies** | Wait for full page load, network idle, or DOM ready before capturing |\n| 🟥 **Square mode** | Optionally clip output to a square for thumbnails or social previews |\n\n---\n\n## 🚀 Quick Start\n\n### 1. Create your sites file\n\nAdd a `sites.json` file to your repository:\n\n```json\n[\n  { \"name\": \"homepage\", \"url\": \"https://example.com\" },\n  { \"name\": \"dashboard\", \"url\": \"https://app.example.com/dashboard\" },\n  { \"name\": \"pricing\", \"url\": \"https://example.com/pricing\" }\n]\n```\n\nEach entry requires a `url` and a `name`. The `name` becomes the screenshot filename (e.g. `homepage.png`).\n\n### 2. Create your workflow\n\n```yaml\nname: Website monitoring\n\non:\n  schedule:\n    - cron: \"0 */6 * * *\"  # every 6 hours\n  workflow_dispatch:\n\njobs:\n  monitor:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Run screenshot monitoring\n        uses: guibranco/github-screenshot-action@v2.0.17\n        with:\n          json_file: \"sites.json\"\n          output_dir: \"screenshots/\"\n          concurrency: \"5\"\n          retries: \"2\"\n          timeout_ms: \"20000\"\n          create_pr: \"true\"\n          branch_name: \"monitor/screenshots\"\n          wait_until: \"networkidle0\"\n          square: \"false\"\n          viewport_width: \"1280\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n```\n\n---\n\n## ⚙️ Inputs\n\n| Input | Required | Default | Description |\n|---|---|---|---|\n| `json_file` | ✅ | `screenshots.json` | Path to the JSON file listing sites to capture |\n| `output_dir` | ✅ | `screenshots` | Directory where `.png` files will be saved |\n| `concurrency` | ❌ | `3` | Number of screenshots to take in parallel |\n| `retries` | ❌ | `2` | How many times to retry a failed screenshot |\n| `timeout_ms` | ❌ | `30000` | Page load timeout per site in milliseconds |\n| `create_pr` | ❌ | `false` | If `true`, opens a PR after committing screenshots |\n| `branch_name` | ❌ | `monitor/screenshots` | Branch to commit screenshots to |\n| `wait_until` | ❌ | `load` | Page load event to wait for before capturing. See [Wait Strategies](#wait-strategies) |\n| `square` | ❌ | `false` | If `true`, clips the output to a square using `viewport_width` as the side length |\n| `viewport_width` | ❌ | `1280` | Viewport width in pixels. Also controls the square size when `square` is `true` |\n\n---\n\n## 📁 JSON File Format\n\n```json\n[\n  {\n    \"name\": \"landing-page\",\n    \"url\": \"https://example.com\"\n  },\n  {\n    \"name\": \"login\",\n    \"url\": \"https://example.com/login\"\n  }\n]\n```\n\n- **`name`** — used as the output filename (`name.png`). Use lowercase, hyphen-separated values for clean filenames.\n- **`url`** — full URL to capture. If the protocol is omitted, `https://` is prepended automatically.\n\n---\n\n## 🔀 PR Automation\n\nWhen `create_pr: \"true\"`, the action will:\n\n1. Check out (or create) the branch specified in `branch_name`\n2. Capture all screenshots and write them to `output_dir`\n3. Commit any changed or new `.png` files with `[skip ci]` to avoid re-triggering workflows\n4. Force-push the branch\n5. Open a pull request against `main` — or skip silently if a PR already exists\n\nThis gives you a clean, reviewable diff of visual changes over time.\n\n\u003e **Note:** The workflow needs `GITHUB_TOKEN` passed via `env` for PR creation and branch push to work.\n\n```yaml\nenv:\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n```\n\n---\n\n## ⏳ Wait Strategies\n\nThe `wait_until` input controls when Puppeteer considers the page ready to capture. Choose based on how dynamic the target site is:\n\n| Value | Waits until... | Best for |\n|---|---|---|\n| `domcontentloaded` | HTML is parsed, no assets waited on | Simple static pages |\n| `load` | All resources loaded (default) | Most standard websites |\n| `networkidle2` | No more than 2 requests in flight for 500ms | Pages with background polling |\n| `networkidle0` | Zero network requests for 500ms | SPAs and lazy-loaded content |\n\n\u003e **Tip:** `networkidle0` produces the most complete captures but is the slowest. If a site has continuous background requests (analytics, websockets), use `networkidle2` to avoid hitting the timeout.\n\n---\n\n## 🟥 Square Mode\n\nWhen `square: \"true\"`, the action sets a square viewport and clips the output to `viewport_width × viewport_width` pixels. Full-page scrolling is disabled in this mode.\n\n```yaml\nsquare: \"true\"\nviewport_width: \"1280\"  # produces a 1280×1280 PNG\n```\n\nThis is useful for generating consistent thumbnails, social preview images, or monitoring dashboards where uniform dimensions are required.\n\n\u003e **Note:** `square` and full-page capture are mutually exclusive. When `square` is enabled, only the top portion of the page visible within the square viewport is captured.\n\n---\n\n## 🗓️ Scheduling Examples\n\n```yaml\n# Every 6 hours\n- cron: \"0 */6 * * *\"\n\n# Once a day at midnight UTC\n- cron: \"0 0 * * *\"\n\n# Every Monday at 8am UTC\n- cron: \"0 8 * * 1\"\n\n# Every hour during business hours (9–17) on weekdays\n- cron: \"0 9-17 * * 1-5\"\n```\n\n---\n\n## 🏗️ Architecture\n\n```\nsites.json\n    │\n    ▼\nparser.ts ──► loadItems()\n                    │\n                    ▼\n            screenshot.ts ──► Puppeteer + pLimit (parallel)\n                    │              │\n                    │         setViewport(width, height)\n                    │         goto(url, { waitUntil })\n                    │         screenshot({ fullPage | clip })\n                    │\n                    ▼\n              output_dir/*.png\n                    │\n                    ▼\n              git.ts ──► checkout branch\n                    │    git add -f / commit\n                    │    git push --force\n                    │    GitHub API PR (optional)\n                    ▼\n             Pull Request / Branch\n```\n\n---\n\n## 🐳 Docker Image\n\nThis action uses a **pre-built Docker image** published to GitHub Container Registry, so there is no build step at runtime.\n\n```\nghcr.io/guibranco/github-screenshot-action:\u003cversion\u003e\n```\n\nThe image includes:\n\n- `node:24-slim` base\n- Chromium and all required system dependencies\n- Pre-compiled TypeScript output in `dist/`\n\nNew images are published automatically on every release via the `release.yml` workflow.\n\n---\n\n## 🔒 Permissions\n\nYour workflow needs the following permissions for full functionality:\n\n```yaml\npermissions:\n  contents: write       # to push the screenshot branch\n  pull-requests: write  # to open PRs\n```\n\nIf you are using a classic `GITHUB_TOKEN` without an explicit `permissions` block, make sure your repository's **Actions settings** allow workflows to create pull requests.\n\n---\n\n## 🛠️ Development\n\n### Prerequisites\n\n- Node.js 24+\n- npm\n\n### Setup\n\n```bash\ngit clone https://github.com/guibranco/github-screenshot-action.git\ncd github-screenshot-action\nnpm install\n```\n\n### Build\n\n```bash\nnpm run build\n```\n\nOutput is written to `dist/`.\n\n### Project Structure\n\n```\n├── src/\n│   ├── main.ts          # Entry point — orchestrates the full run\n│   ├── parser.ts        # Reads and validates sites.json\n│   ├── screenshot.ts    # Puppeteer screenshot logic with concurrency\n│   ├── git.ts           # Git operations: commit, branch, PR creation\n│   └── logger.ts        # Emoji-prefixed console logger\n├── Dockerfile           # Pre-built image definition\n├── entrypoint.sh        # Docker entrypoint\n├── action.yml           # Action metadata\n└── sites.json           # Example sites file\n```\n\n### Publishing a new version\n\n1. Merge your changes to `main`\n2. The `release.yml` workflow automatically determines the next version via GitVersion\n3. It builds and pushes the Docker image to GHCR tagged as `vX.Y.Z` and `latest`\n4. It opens a PR updating the `image:` tag in `action.yml` — merge it to complete the release\n\n---\n\n## 📄 License\n\nMIT © [Guilherme Branco Stracini](https://github.com/guibranco)\n\n---\n\nMade with ❤️ and ☕ — contributions welcome via [issues](https://github.com/guibranco/github-screenshot-action/issues) and [pull requests](https://github.com/guibranco/github-screenshot-action/pulls).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguibranco%2Fgithub-screenshot-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguibranco%2Fgithub-screenshot-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguibranco%2Fgithub-screenshot-action/lists"}