How to create a visual changelog from screenshots of website releases
Build a useful visual changelog with repeatable screenshots, reviewed comparisons, clear release notes, and an automated publishing workflow.
A visual changelog is a dated record of meaningful website changes, illustrated with comparable screenshots from successive releases. Build one by choosing representative pages, capturing them in a stable environment, reviewing each difference, adding a short explanation, and publishing the approved entries in a maintained archive.
The screenshots are evidence, not the changelog by themselves. Readers need to know which page changed, when it changed, what is different, and why that difference matters.
1. Decide what belongs in the changelog
Start with a small set of pages that represent important visitor journeys. Common choices include the home page, product or feature pages, pricing, and a task-completion page such as checkout confirmation or account setup. Add pages when a release changes them; do not try to capture every URL by default.
| Record for each capture | Why it matters |
|---|---|
| Page URL and page or feature name | Lets you tie the image to a place readers recognize. |
| Release date, version, or commit | Identifies when the captured state was current. |
| Viewport dimensions and device scale | Different widths and pixel densities can change layout and text wrapping. |
| Browser and capture environment | Rendering can differ across browser and host configurations. |
| Locale, account state, and other relevant state | Helps reproduce localized or authenticated pages consistently. |
| Steps to reach the state | Needed for pages behind a flow, modal, or interaction. |
Choose a default viewport and state for each page. If mobile layout is a meaningful part of the release, capture it as a separate, consistently named view rather than comparing it to desktop.
2. Capture comparable screenshots
For each release, use the same URLs, browser version, viewport, locale, authentication state, and page preparation steps. Capture after the page has settled. If a page loads images lazily, scroll through it or use a full-page capture method that triggers those images before saving.
Manual captures are quick to start and can work for a small number of pages. Automated browser capture is easier to repeat for a recurring release process. Playwright Test provides toHaveScreenshot(): an initial run can create reference screenshots, and later runs compare against them. See the Playwright visual comparisons documentation for setup and configuration.
A minimal Playwright Test example:
import { test, expect } from '@playwright/test';
test('capture the pricing page', async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 1000 });
await page.goto('https://example.com/pricing', { waitUntil: 'networkidle' });
await expect(page).toHaveScreenshot('pricing.png', { fullPage: true });
});
Run this from a Playwright Test project with the browser installed. On the first run, inspect and commit the generated baseline intentionally; later runs compare the page with that baseline. Avoid refreshing baselines automatically when the comparison fails: review the change first so a regression does not silently replace the evidence.
Organize originals by release and page, for example screenshots/2026-10-04/pricing-desktop.png. Keep the previous approved capture and the new capture together until the review is complete.
3. Reduce visual noise before comparing
A screenshot can change for reasons unrelated to the release. Rotating banners, timestamps, personalized recommendations, animation, live counters, and asynchronous content can create noise. Where possible, use stable test data, disable animation, freeze changing content, or mask a known dynamic region in the comparison tool. Record any masking so reviewers know what is excluded.
Keep the capture environment stable. Playwright warns that browser rendering may vary with the host OS, version, settings, hardware, power source, headless mode, and other factors. If the environment changed between releases, document it and review apparent differences manually rather than treating every pixel change as a product change. See the official Playwright guidance.
Cookie and consent banners can also obscure the page. If they are not the subject of the release, use the same consent state for both captures or remove the overlay from both in a consistent, documented way. Do not remove an element from just one side of a comparison.
4. Compare images and review the differences
Pick a comparison format that suits the review:
- Side by side: straightforward for readers and reviewers, especially when the change affects layout or content.
- Overlay: useful for spotting alignment and geometry shifts by placing one image over another.
- Visual regression diff: highlights changed pixels and can be part of an automated check, but still needs human review.
Pixel differences are prompts for investigation, not proof that a user-visible change matters. Check that each difference is intentional, visible to readers, and associated with the correct release. Reject accidental captures, environment noise, and unexplained rendering changes. Approve baseline updates through the same review process as other release changes.
- Confirm both images show the same URL, viewport, state, and locale.
- Inspect highlighted areas at full size; verify whether the difference is content, layout, or rendering noise.
- Check the change against the release or commit that supposedly introduced it.
- Approve the comparison only when the new capture is reproducible and the change is understood.
5. Write an entry that explains the change
Give each entry enough context to make sense without requiring readers to decode a diff. A practical entry includes:
- A date or version.
- The affected page, feature, or journey.
- A before-and-after view or focused comparison.
- A short, plain-language explanation of what changed and its practical effect.
- A link to detailed release notes when more context is useful.
For example: “October 4, 2026 · Pricing page — The plan comparison now keeps the included limits beside each plan, so visitors can compare allowances without switching sections.” Write only what the release actually changed. The image supports the explanation; it should not replace it.
6. Publish and maintain the archive
A static site is a simple option when entries are reviewed in a repository and the archive can be public. A CMS or hosted changelog may fit better when nontechnical editors need a publishing workflow or access controls. Choose based on who reviews entries, how publication is triggered, whether content needs restricted access, and how custom domains are managed.
GitHub’s official tutorial shows how to publish a GitHub Pages site with GitHub Actions on pushes to main. The workflow checks out the repository, prepares Pages, uploads an artifact, and deploys it. See GitHub’s custom workflow guide. The same principle works with other static hosts: store approved entry data and images with the site, then deploy when changes are merged.
Keep the public archive easy to scan. Sort entries by date, link each to a stable release or page, use descriptive image alt text, and make sure images remain available after deployment. For every release, a lightweight checklist helps:
- Capture the agreed pages and states in the standard environment.
- Review diffs and reject noise or accidental captures.
- Write a concise explanation and attach the correct release identifier.
- Publish the entry and confirm its images and links load.
7. Capture with a screenshot API
Automated browser tooling is useful when you need to reproduce flows and control browser state. A screenshot API can simplify captures for public pages when a URL, viewport, and output image are enough. ScreenshotNeo is a website screenshot API and MCP server; its capture options include full-page screenshots, viewport and device settings, waits, custom headers and cookies, and custom CSS or JavaScript. See the ScreenshotNeo API documentation for request parameters.
For an API capture, preserve the same URL and capture settings across releases, save the returned image with the release metadata, and review it against the prior approved image. API capture does not remove the need to control page state or review the diff.
Or skip the browser setup
Make one request to capture a page as an image:
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,
)
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}`);
Cookie banners are accepted like a visitor and removed before the shot, along with 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan. See the docs for options and sign up free for 1,000 screenshots a month with no card.
Performance, reliability, and cost
Keep the initial page set focused, then add coverage when a release changes another important journey. Full-page captures and multiple viewports increase the number and size of files, while screenshots of carefully chosen representative pages keep review manageable. For reliable comparisons, prioritize repeatable state and environment over capturing more pages.
Browser-based capture has setup and maintenance costs: browser installation, scripts, state preparation, and keeping baselines reviewable. Manual capture has little setup but takes repeated effort and is easier to perform inconsistently. A screenshot API reduces browser setup for URL-based captures, but the team still needs to retain images, metadata, and a human review step. For ScreenshotNeo, the stated plans are Free at 1,000 shots/month, Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free. Only clean shots are billed.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Large diff despite no intended design change | Browser, host, viewport, font, or page state changed. | Compare capture metadata, restore the standard environment, and rerun before approving a baseline. |
| Images or lower-page content are missing | Lazy-loaded resources were not requested before capture. | Use a full-page capture that loads content as it scrolls, or explicitly scroll through the page before taking the screenshot. |
| Text or layout moves between runs | Dynamic content, personalized state, or a rotating banner changed. | Use stable test data, consistent login and locale, and freeze or mask the dynamic region on both captures. |
| Screenshot shows a consent dialog or popup | The stored consent state differs, or the overlay is part of the page state. | Set the same consent state for both captures, or consistently remove the overlay from both using a documented method. |
| Automated capture times out or is blank | The page is slow, navigation never settles, or a bot check blocks the capture. | Check the URL and load state, use an appropriate wait condition, and inspect the page manually. Treat a failed capture as unresolved rather than as a valid baseline. |
| Diff highlights harmless antialiasing or animation | Rendering variation or motion created pixel-level noise. | Standardize the environment, disable animation where possible, and configure a suitable mask or comparison threshold. Review any remaining change manually. |
| Published entry has the wrong image or release | Capture files were not tied clearly to release metadata. | Use stable release-and-page filenames, keep metadata with the image, and verify the entry links before deployment. |
FAQ
How many pages should the first changelog cover?
Start with a few pages that represent your main visitor journeys. Expand when releases affect other important pages or states.
Should every visual difference be published?
No. Publish changes that are intentional and useful to readers, with a short explanation. Keep rendering noise and internal-only changes out of the public record.
Can I use visual regression tests as the changelog?
They can help find differences, but test output does not explain the release or its user impact. Curate the results and write a reader-facing entry.
What if the site changes between captures without a code release?
Record the capture date and relevant source of change, such as content or configuration, if it matters to readers. Avoid implying that every difference came from a software release.


