DEV Community

Vitalii Holben
Vitalii Holben

Posted on

How to Screenshot Dynamic Content That Changes on Every Page Load

Some pages look different every time you load them. Randomized hero banners, A/B test variants, personalized product recommendations, rotating testimonials. If you're automating screenshots for testing or documentation, this is a problem.

You capture a baseline. You capture again tomorrow. The diff lights up red — not because anything broke, but because the carousel rotated and a different testimonial is showing.

The two types of dynamic content

There's server-side dynamic (different HTML on each request) and client-side dynamic (same HTML, JavaScript shuffles things around after load). The fix is different for each.

Server-side: you need to control the request. Pass a seed parameter, set a cookie, or hit a specific URL variant. If the page personalizes based on geo-IP, you need to pin your request to a consistent location.

Client-side: you need to run JavaScript before or after the page renders to freeze the randomization.

Freezing Math.random

A lot of front-end randomization uses Math.random(). Override it before the page loads:

await page.evaluateOnNewDocument(() => {
  let seed = 42;
  Math.random = () => {
    seed = (seed * 16807) % 2147483647;
    return (seed - 1) / 2147483646;
  };
});
Enter fullscreen mode Exit fullscreen mode

Now every "random" value is deterministic. The carousel always shows the same slide. The A/B test always picks the same variant. Your screenshots become comparable.

Handling date/time displays

Pages that show "Posted 3 hours ago" or "Last updated: August 3, 2026" will always diff because the timestamp changes. Two options:

Option 1: Freeze the clock

await page.evaluateOnNewDocument(() => {
  const fixed = new Date('2026-01-15T12:00:00Z');
  const OrigDate = Date;
  Date = class extends OrigDate {
    constructor(...args) {
      if (args.length === 0) return super(fixed);
      return super(...args);
    }
    static now() { return fixed.getTime(); }
  };
});
Enter fullscreen mode Exit fullscreen mode

Option 2: Mask the regions

If freezing the clock breaks page logic (timers, session management), mask the date regions in your diff comparison instead. Mark those areas as "ignore" in your visual diff tool.

I prefer option 1 for screenshot capture and option 2 for visual regression testing. Depends on whether you need the screenshot to look realistic or just be consistent.

CSS animations and transitions

An animated element captured mid-transition looks different every time. Kill all animations before capture:

await page.addStyleTag({
  content: `
    *, *::before, *::after {
      animation-duration: 0s !important;
      animation-delay: 0s !important;
      transition-duration: 0s !important;
      transition-delay: 0s !important;
    }
  `
});
Enter fullscreen mode Exit fullscreen mode

This one saved me a ton of debugging. Had a landing page where a fade-in animation on the hero image made every screenshot slightly different in opacity. Took me a while to figure out it wasn't a rendering bug.

Lazy-loaded images and intersection observers

Content that loads on scroll won't appear in a screenshot if the viewport never scrolls to it. For full-page screenshots, scroll the page programmatically first:

await page.evaluate(async () => {
  await new Promise((resolve) => {
    let totalHeight = 0;
    const distance = 300;
    const timer = setInterval(() => {
      window.scrollBy(0, distance);
      totalHeight += distance;
      if (totalHeight >= document.body.scrollHeight) {
        clearInterval(timer);
        window.scrollTo(0, 0);
        resolve();
      }
    }, 100);
  });
});
Enter fullscreen mode Exit fullscreen mode

Scroll to the bottom, trigger all the lazy loads, scroll back to top, then capture. Not elegant but it works reliably.

When you can't control the content

Sometimes you're screenshotting third-party pages you don't own. You can't inject seeds or override Math.random. In that case, accept that the screenshots will vary and adjust your comparison threshold.

Instead of pixel-perfect diffs, use structural comparison. Did the layout change? Did elements move? Is text content different? A 2-3% pixel difference from a rotated banner is noise. A 15% difference from a missing navigation bar is a real issue.

The goal isn't identical screenshots — it's catching meaningful changes while ignoring expected variation.

Top comments (0)