npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

screenshot-helper

v2.0.1

Published

A helper for taking automated web screenshots using Playwright.

Downloads

67

Readme

screenshot-helper

Automate high-quality screenshots of web pages for testing, visual review, and documentation.

screenshot-helper is a flexible Node.js utility designed to programmatically capture screenshots of web apps with minimal boilerplate. It supports scenario lists, custom setup and cleanup logic, device presets, and easy integration into your QA or CI flows.


Features

  • Automates screenshots from a scenario configuration
  • Works with Playwright to simulate real browser environments (desktop/mobile, etc.)
  • Supports UI interaction setup (before) and post-setup cleanup (cleanup)
  • Granular capture: full-page, clipped to element, function-based, etc.
  • Use filters to selectively run a subset of scenarios
  • Strong integration for visual testing and asset generation
  • Errors in scenarios (including Playwright errors) are always caught: process never crashes, errors are highlighted and remaining scenarios continue.
  • Full ES module (ESM) support everywhere; tested with Vitest.

Installation

npm install screenshot-helper

For development/contributors:

npm install --save-dev vitest

Running the Tests

This project uses Vitest for all unit and integration tests and supports top-level import/export JavaScript syntax out of the box. No Babel or legacy Jest config is needed with Node.js (>=18).

npm test

Or run a single test file:

npx vitest run test/your.test.js

Basic Usage

Define your scenarios and call the runner. Each scenario can have:

  • name: Unique name for the output file
  • route: URL path (relative to your baseURL)
  • group: (optional) explicit grouping key for deterministic grouped numbering
  • full: Capture the entire page (true) or just the viewport (false)
  • selector: (optional) CSS selector for element-only screenshots
  • before: (optional) Async function for custom setup (e.g., open a modal, wait for element)
  • cleanup: (optional) Async function for removing overlays/ads/etc before the screenshot
import launchScreenshotsRunner from 'screenshot-helper';

const baseURL = 'http://localhost:8888';
const outputDir = 'screenshots'; // optional
const onEvent = (event) => {
  // optional structured event hook for app integration
  console.log(event);
};
const devices = {
  desktop: { viewport: { width: 1280, height: 1080 }, deviceScaleFactor: 2 },
  mobile: { viewport: { width: 375, height: 812 }, deviceScaleFactor: 2 }
};
const loadTimeoutMs = 8000; // optional: max wait for networkidle before acting
const loadTimeoutAction = 'continue'; // or 'skip' to abandon the scenario
const debug = true; // optional: verbose logging for stuck runs

const scenarioData = [
  {
    name: 'simple-homepage',
    route: '/',
    full: true
  },
  {
    name: 'cookie-banner',
    route: '/',
    selector: '#cookie-consent-banner',
    before: async (page, locator, device) => {
      await page.waitForFunction(() => !!window.cookieconsent);
      await page.evaluate(() => window.cookieconsent.show());
      // device is now available as a third argument (e.g. 'desktop' or 'mobile')
      if (device === 'mobile') {
        // special handling for mobile...
      }
      if (!await locator.isVisible()) return false; // skip screenshot if banner is not visible
    }
  },
  {
    name: 'third-party-capture',
    route: '/external-widget-demo',
    before: async page => {
      await page.click('#widget-opener');
    },
    cleanup: async page => {
      await page.evaluate(() => {
        let el = document.querySelector('.third-party-banner');
        if (el) el.remove();
      });
    },
    full: true
  }
];

// Optionally pass a filter to only run a subset of scenarios
const filter = process.argv[2];

// To provide HTTP Basic Auth credentials to all requests
const httpCredentials = {
  username: 'yourUsername',
  password: 'yourPassword',
};

const summary = await launchScreenshotsRunner({
  scenarioData,
  baseURL,
  devices,
  filter,
  outputDir,
  onEvent,
  httpCredentials,
  loadTimeoutMs,
  loadTimeoutAction,
  debug
});

console.log(summary);

By default, runner status/debug logs are written to stderr so you can keep stdout clean for JSON output. For example, this captures only JSON summary to a file while still showing progress logs in the terminal:

node screenshots.js > summary.json

Scenario Configuration

  • name: string (required)
    Used for the output filename and reporting.
  • route: string (required)
    Path relative to baseURL
  • group: string | number Optional explicit group key for filename grouping. If omitted, grouping is inferred from the route URL without query/hash. If route is missing, the scenario falls back to a misc group.
  • full: boolean
    Capture the entire page (true) or just viewport/selector area (false)
  • selector: string
    CSS selector for element screenshot (optional; use type: 'element' for clarity)
  • before: (page, locator?) => Promise
    An async function run prior to the screenshot, for setup (e.g., open menus, wait for content)
  • cleanup: (page) => Promise
    An async function run just before the screenshot (after setup), ideal to remove overlays/ads, etc.
  • outputDir: string Optional output directory for generated screenshots. Defaults to screenshots.
  • outputPathBuilder: ({ outputDir, device, shotNum, shotLabel, groupId, groupKey, shotInGroup, scenarioName, scenario, type }) => string Optional filename/path builder. Defaults to grouped deterministic naming: outputDir/device-GG.SSS-name.png (for example desktop-01.002-home.png).
  • onEvent: (event) => void Optional structured event hook. Receives lifecycle events such as scenario-started, scenario-skipped, scenario-succeeded, and scenario-failed.
  • logger: object Optional logger override with log(...args) and error(...args) methods.

Scenario Types

screenshot-helper supports 3 scenario type modes for maximum control:

  • Default (Page)

    • Omit type, or use any unrecognized value.
    • Screenshots the full page or just the viewport (if full: true) after running optional before and cleanup hooks.
    • selector is ignored.
    • If full: true, the page is scrolled to capture the entire length.
  • Element (type: 'element')

    • Only screenshots the area of a specific DOM element, as matched by selector.
    • If full: true, the screenshot will output multiple PNG files ("tiles/fragments") per element, scrolling through both axes using Playwright. This pans through overflow within the selected element via element.scrollTo, so containers wider or taller than the viewport are robustly covered. Files are named with letter suffixes (e.g. ...001a-, ...001b-, etc).
    • Receives before(page, locator, device) and cleanup(page, locator, device) for custom setup/teardown.
  • Function (type: 'function')

    • For advanced/edge scenarios requiring full Playwright scripting.
    • Hooks are given both the page object and a locator for chaining or ignoring as you wish: before(page, locator, device).
    • Does not perform any screenshot by default—your hook code should perform interactions as needed. You can use these for setup, or for logic-only tasks that do not result directly in a screenshot.

Advanced Patterns

Use type: 'element' for element screenshots, or type: 'function' scenarios for full scriptable logic. You can chain Playwright's page and locator methods inside your hooks, interact with dynamic JS elements, or conditionally skip screenshots.


CLI Filtering

You can filter which scenarios are run by passing a substring as a CLI argument:

node screenshots.js homepage

Will only run scenarios whose name includes "homepage".

Load timeouts

  • loadTimeoutMs caps how long the runner waits for a page to reach networkidle before proceeding.
  • loadTimeoutAction controls behavior on timeout: 'skip' stops the scenario immediately, 'continue' runs hooks/screenshot even if the page never reached networkidle.
  • The same loadTimeoutMs is reused for asset waits (ensureAssetsLoaded), so hanging images/fonts won’t stall forever.

Debug logging

  • Pass debug: true to launchScreenshotsRunner to print step-by-step progress (navigation, load waits, hooks, and screenshot points) for each scenario/device. Useful when runs hang or stall.

Return value

  • launchScreenshotsRunner(...) now returns a summary object with aggregate counts and per-device scenario outcomes.

Structured events

Example onEvent payload:

{
  type: 'scenario-succeeded',
  device: 'desktop',
  scenarioName: 'homepage',
  scenarioType: 'page',
  status: 'succeeded',
  reason: null,
  filename: 'screenshots/desktop-01.001-homepage.png'
}

Testing

Run tests with:

npm test

Unit and integration tests are in [test/].


Contributing

PRs and suggestions welcome! Please open an issue first to discuss feature ideas or bugs.


License

ISC (see LICENSE file)


See also: