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

node-html2img-render-server

v1.1.1

Published

A server for converting HTML to images with Playwright - allows direct HTML input and returns screenshots for visual testing

Downloads

21

Readme

npm npm npm github ci

node-html2img-render-server

A server for converting HTML to images with Playwright - allows direct HTML input and returns screenshots for visual testing.

Overview

This service solves the common challenge in visual regression testing where different environments produce slightly different renderings (due to anti-aliasing, font rendering differences, etc.). By offloading rendering to a dedicated service with a consistent environment, tests can produce reliable, reproducible results regardless of where the tests themselves run.

Features

  • Direct HTML Rendering: Submit raw HTML, CSS, and JavaScript for rendering instead of relying on URL access
  • Consistent Environment: Ensures identical rendering across all test runs
  • Asset Injection: Support for fonts, images, and other assets
  • Flexible Screenshot Options: Configurable viewport, element selection, and waiting conditions
  • Multiple Image Formats: Support for both PNG and JPEG output formats
  • API Key Authentication: Secure access with API key authentication
  • Containerized: Runs in Docker for maximum consistency and portability
  • Observability: Built-in OpenTelemetry instrumentation with Elastic APM support

Quick Start

Option 1: Run with npx (No Installation Required)

# Run the server directly with npx
npx node-html2img-render-server

# The server will start with a random API key (shown in console)
# and open a demo page in your browser

For CLI options and advanced usage, see CLI.md.

Option 2: Running with Docker

# Pull the image
docker pull walterra/node-html2img-render-server

# Run the service without telemetry
docker run -p 3000:3000 -e API_KEY=your-api-key walterra/node-html2img-render-server

# Run with OpenTelemetry (for monitoring with Elastic APM)
docker run -p 3000:3000 \
  -e API_KEY=your-api-key \
  -e OTEL_SERVICE_NAME=node-html2img-render-server \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=your-elastic-apm-endpoint \
  -e OTEL_EXPORTER_OTLP_HEADERS="Authorization=ApiKey your-elastic-api-key" \
  walterra/node-html2img-render-server

Basic Usage

# Render HTML to an image
curl -X POST "http://localhost:3000/render?apiKey=your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<div style=\"padding: 20px; background-color: #f0f0f0;\">Hello World</div>"
  }' \
  --output hello.png

See EXAMPLES.md for more detailed usage examples.

API

Render Endpoint

POST /render

Request Body

{
  "html": "<div class='card'>Hello World</div>",
  "css": ".card { border: 1px solid #ccc; padding: 16px; }",
  "javascript": "document.querySelector('.card').addEventListener('click', () => console.log('clicked'));",
  "viewport": {
    "width": 1280,
    "height": 720,
    "deviceScaleFactor": 1
  },
  "waitForSelector": ".card",
  "clipSelector": ".card",
  "assets": {
    "font.woff2": "base64encodedcontent",
    "image.png": "base64encodedcontent"
  },
  "fonts": [
    {
      "name": "CustomFont",
      "data": "base64encodedfontwoff2data",
      "weight": "400",
      "style": "normal"
    }
  ],
  "format": "png", // "png" or "jpeg"
  "quality": 90, // JPEG quality (1-100)
  "responseFormat": "image" // "image" or "json"
}

Response Formats

Default: Direct Image Response (responseFormat = "image")

By default, the service returns the rendered image directly as binary data with Content-Type: image/png. Metadata is embedded in the image's EXIF data and also provided via HTTP headers:

  • X-Screenshot-ID: Unique ID for the screenshot
  • X-Rendering-Time: Time taken to render in milliseconds
  • X-Browser-Version: Browser version used for rendering
  • X-Rendered-At: ISO timestamp when the image was rendered
  • X-Viewport-Width: Viewport width used
  • X-Viewport-Height: Viewport height used
  • X-Viewport-DeviceScaleFactor: Device scale factor used
JSON Response (responseFormat = "json")

When responseFormat is set to "json", the response is:

{
  "image": "base64encodedimagecontent",
  "contentType": "image/png",
  "metadata": {
    "screenshotId": "550e8400-e29b-41d4-a716-446655440000",
    "renderedAt": "2025-05-02T12:34:56.789Z",
    "viewport": { "width": 1280, "height": 720, "deviceScaleFactor": 1 },
    "browserVersion": "Chromium 120.0.6099.109",
    "renderingTime": 345
  }
}

Integration with Testing Frameworks

Jest with jest-image-snapshot

const axios = require('axios');
const { toMatchImageSnapshot } = require('jest-image-snapshot');
expect.extend({ toMatchImageSnapshot });

// API key should be loaded from environment variables
const apiKey = process.env.RENDER_SERVICE_API_KEY;

test('component renders correctly', async () => {
  // Call the render service with default responseFormat (image)
  const response = await axios.post(
    `http://localhost:3000/render?apiKey=${apiKey}`,
    {
      html: '<div class="card">Product Title</div>',
      css: '.card { border: 1px solid #ccc; }',
      viewport: { width: 500, height: 300 }
    },
    {
      responseType: 'arraybuffer' // Important: tell axios to expect binary data
    }
  );

  // The response.data is already the image buffer
  const buffer = Buffer.from(response.data);

  // Compare with baseline image
  expect(buffer).toMatchImageSnapshot();
});

Testing Different Image Formats

When testing different image formats (PNG and JPEG), you can use snapshot testing to verify the visual output remains consistent:

test('should render with different formats', async () => {
  // Test PNG format
  const pngResponse = await axios.post(
    `http://localhost:3000/render?apiKey=${apiKey}`,
    {
      html: '<div class="card">Product Title</div>',
      format: 'png' // Explicit format (default is PNG)
    },
    {
      responseType: 'arraybuffer'
    }
  );

  // Test JPEG format with quality setting
  const jpegResponse = await axios.post(
    `http://localhost:3000/render?apiKey=${apiKey}`,
    {
      html: '<div class="card">Product Title</div>',
      format: 'jpeg',
      quality: 90 // Quality setting for JPEG (1-100)
    },
    {
      responseType: 'arraybuffer'
    }
  );

  // Compare both formats against their respective baselines
  expect(Buffer.from(pngResponse.data)).toMatchImageSnapshot({
    customSnapshotIdentifier: 'png-format-test'
  });

  expect(Buffer.from(jpegResponse.data)).toMatchImageSnapshot({
    customSnapshotIdentifier: 'jpeg-format-test'
  });
});

Note that JPEG format is lossy compression, so snapshot comparisons should account for expected quality differences.

Benefits Over URL-based Approaches

  • No Public Endpoints Required: Test components or pages not publicly accessible
  • Simplified Testing Setup: No need to deploy test versions of your application
  • Component-Level Testing: Test individual components without a full application
  • Consistent Styling: Apply specific styles without affecting the entire application
  • Faster Test Execution: Eliminates need to navigate to pages before taking screenshots

Security Considerations

  • API key authentication required for all endpoints
  • Runs in a sandboxed environment with limited capabilities
  • Implements timeouts to prevent resource exhaustion
  • Validates input to prevent malicious HTML/JavaScript
  • Rate limiting to prevent abuse

Documentation

  • EXAMPLES.md - Detailed usage examples with curl and JavaScript
  • DEVELOPMENT.md - Information for developers who want to modify or contribute to this service
  • CLI.md - Command-line interface documentation and options
  • Observability - Details on telemetry, logging, tracing, and Elastic APM integration