ScreenshotNeo

BlogHow-to

How to Archive a Webpage Screenshot with a UTC Timestamp in Playwright

Capture a webpage in Playwright and save an unambiguous UTC timestamp with its screenshot. Includes full-page capture, metadata, troubleshooting, and preservation limits.

By the ScreenshotNeo team4 October 20267 min read

Use Playwright’s page.screenshot() to save the webpage image, and JavaScript’s new Date().toISOString() to record an unambiguous UTC time. The timestamp ends in Z. Save it in a JSON sidecar next to the image, and label whether it records when capture started or finished.

This creates a visual record, not a complete web archive. If you need to preserve page resources for future replay, a screenshot alone is insufficient; the Library of Congress identifies WARC as its preferred web-archive format. Library of Congress web archive format guidance.

1. Set up Playwright

The examples use JavaScript with Node.js and Playwright. Install the package and its browser binaries in your project:

npm install playwright
npx playwright install chromium

Save the following as archive.mjs and run it with node archive.mjs. It writes capture.png and capture.json in the current directory.

2. Capture the page and write a UTC sidecar

import { chromium } from 'playwright';
import { writeFile } from 'node:fs/promises';

const url = 'https://example.com';
const browser = await chromium.launch();

try {
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1
  });

  const navigation = await page.goto(url, {
    waitUntil: 'load',
    timeout: 30_000
  });

  // This marks the start of the screenshot operation, after navigation.
  const captureStartedAt = new Date().toISOString();
  await page.screenshot({ path: 'capture.png', fullPage: true });
  const captureCompletedAt = new Date().toISOString();

  const metadata = {
    sourceUrl: url,
    finalUrl: page.url(),
    httpStatus: navigation?.status() ?? null,
    captureStartedAt,
    captureCompletedAt,
    timestampFormat: 'UTC ISO 8601; Z suffix; millisecond precision',
    timestampMeaning: 'captureStartedAt and captureCompletedAt bracket screenshot generation',
    screenshot: 'capture.png',
    screenshotOptions: { fullPage: true, type: 'png' },
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1,
    browser: 'Chromium',
    playwrightVersion: process.env.npm_package_devDependencies_playwright ?? 'record installed version separately'
  };

  await writeFile('capture.json', JSON.stringify(metadata, null, 2) + '\n');
} finally {
  await browser.close();
}

toISOString() returns a UTC date-time string with a Z suffix and millisecond precision. For example: 2026-10-04T12:34:56.789Z. The sample records the time immediately before and after screenshot() resolves. These are workflow timestamps, not a timestamp embedded in the image.

The sample uses waitUntil: 'load', which waits for the page load event. Some sites continue changing after that event. For a page with known content, wait for a specific selector before taking the screenshot:

await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.locator('main article').waitFor({ state: 'visible', timeout: 15_000 });
const captureStartedAt = new Date().toISOString();
await page.screenshot({ path: 'capture.png', fullPage: true });

Choose a readiness condition that matches the page. A fixed delay may help with a known animation or delayed widget, but it can waste time or still be too short. Network-idle behavior can also be unsuitable for pages that keep requests open.

3. Choose the screenshot output

Playwright can save the image to a path or return image bytes for your own storage flow. PNG is the default; JPEG and WebP are also supported. Record the chosen format and relevant options in the sidecar if repeatability matters. See the Playwright screenshot documentation.

Viewport or full page

  • page.screenshot({ path: 'capture.png' }) captures the current viewport.
  • page.screenshot({ path: 'capture.png', fullPage: true }) captures the full scrollable page.
  • page.locator('main').screenshot({ path: 'main.png' }) captures one element.

Full-page screenshots can be much taller and larger than viewport captures. Lazy-loaded content may need to be scrolled into view or otherwise triggered before capture. A full-page image still only records rendered appearance; it does not retain page behavior or the underlying resources.

Format, scale, and returned bytes

// JPEG, with quality from 0 to 100
await page.screenshot({ path: 'capture.jpg', type: 'jpeg', quality: 80 });

// WebP
await page.screenshot({ path: 'capture.webp', type: 'webp', quality: 80 });

// Return a Buffer instead of writing directly to a path
const bytes = await page.screenshot({ fullPage: true, type: 'png' });
await writeFile('capture.png', bytes);

Playwright also supports screenshot options such as clipping, masking locators, hiding the caret, and handling animations. Use the official API documentation for the complete option list and exact behavior. Save the options you rely on into the manifest so another run can be interpreted correctly.

4. Make the archive record useful

A timestamp only helps if its meaning is clear. Keep the source URL, final URL after redirects, time semantics, image filename, and capture settings together. For workflows that need reproducibility, record the browser and Playwright versions, viewport, device scale factor, and navigation errors too. Playwright does not automatically create this preservation manifest; it is workflow metadata you write yourself.

Do not burn the timestamp into the screenshot if the image is meant to show the page as rendered. Adding text changes the pixels. A sidecar preserves the visual image and keeps capture metadata separately inspectable.

If you need a cryptographic integrity check, compute a hash of the saved file and include it in the JSON after the screenshot is written. Keep the original bytes unchanged; store derived or annotated copies as separate files.

5. Understand screenshot preservation limits

A screenshot documents visible appearance at one point in a capture workflow. It is not a package of HTML, stylesheets, scripts, network responses, interactive state, or replayable site behavior. It may also omit content that only appears after interaction, authentication, or loading from external services.

For preserving web resources rather than only appearance, WARC is designed to aggregate digital resources and related information. WARC records include required date, type, and length fields. The Library of Congress says it uses WARC for web content preservation and notes that some content, including streaming media, deep web content, and databases, may not be captured by current web capture tools. See the Library of Congress guidance and the WARC specifications.

6. Troubleshoot common problems

Symptom Likely cause What to do
Browser executable is missing The Playwright package is installed but its browser binary is not. Run npx playwright install chromium in the project environment.
Navigation times out The site is slow, unreachable, or keeps loading resources. Check the URL and network access. Choose a navigation condition that suits the site, then wait for the page element your capture actually needs. Set a deliberate timeout.
Screenshot is blank or incomplete The page may not have rendered its main content yet, may require interaction, or may block automated browsing. Wait for a visible content selector, inspect navigation status and page errors, and verify the page can be viewed in the same browser environment.
Full-page image misses lazy content Content loads only after scrolling or entering the viewport. Scroll through the page or trigger the relevant content before capture, then take the full-page screenshot.
Timestamp appears local or ambiguous A locale-formatted date was used instead of a UTC ISO string. Use new Date().toISOString() and keep the Z suffix. Do not strip the timezone marker.
Timestamp does not match the image file metadata The sidecar records workflow time; file-system timestamps can reflect copying or storage operations. Use the explicitly named sidecar fields as the capture record. Do not treat filesystem modification time as capture time.
Sidecar exists without a screenshot Metadata writing ran despite screenshot failure, or files were moved separately. Write metadata only after the screenshot succeeds, as in the sample; keep image and sidecar together and check both before publishing.

7. Performance, reliability, and cost

Capture time depends on the target site, navigation readiness condition, page length, image format, and browser environment. Full-page screenshots can consume more memory and storage than viewport shots. Use a viewport capture when only the initial visible state is needed, and choose JPEG or WebP when smaller image files matter more than lossless output.

For repeatable records, capture the final URL and HTTP status, preserve both start and completion timestamps, and retain enough environment details to explain differences between runs. Treat a failed navigation or screenshot as a failed archive attempt: record the error in a separate run log and do not present a partial image as a successful capture.

Playwright is browser automation software; this workflow has no per-screenshot ScreenshotNeo charge. The costs to account for are your execution environment, storage, and any archive or retention system you choose. For WARC preservation, select a capture workflow that produces and manages WARC rather than assuming a PNG can be converted into a resource-complete archive.

Or skip the browser setup

ScreenshotNeo is a screenshot API and MCP server. Its one-call API returns an image or PDF; use the response headers and JSON sidecar in your own archival workflow if you need a UTC capture record. ScreenshotNeo’s API does not replace the timestamp manifest in the Playwright example.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

See the ScreenshotNeo API documentation for request details. Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers say whether the page was clean and billed. An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

FAQ

Does the UTC timestamp go inside the screenshot?

No. The example keeps it in a JSON sidecar so the screenshot pixels remain unchanged.

Does a full-page screenshot preserve the website?

No. It preserves a rendered visual image. Use a web-archive format such as WARC when the goal is to retain web resources for archive access or replay.

Should I record capture start or completion?

Record both when timing matters, and label each field. If you only keep one, state clearly what event it represents.

Will the same URL always produce the same screenshot?

No. Page content, personalization, external resources, viewport, browser version, and timing can change the result. Record the relevant capture conditions alongside the image.