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

@twocaretcat/astro-snapshot

v2.1.0

Published

An Astro integration for generating screenshots of your pages automatically at build time. Perfect for creating social images, content previews, dynamic icons, and more!

Readme

👋 About

Generate screenshots of your Astro pages automatically at build time with Astro Snapshot. Perfect for creating social images, content previews, dynamic icons, and more!.

This integration was inspired by a similar plugin I wrote for Gatsby called Gatsby Plugin: Component to Image and astro-selfie. Compared to astro-selfie, this integration exposes a lot more configuration options that allow you to completely customize how images are generated.

Features

  • 🚀 Works with any page : Generate one or more images from any valid Astro page
    • Not limited by presets or available integration options like other solutions
    • Not limited by types of JSX elements or CSS properties supported by Satori
    • Use whatever front-end framework you want
  • 📷 Configurable output filetypes: Generate PNG, JPEG, or WebP images with arbitrary dimensions
    • Formats are automatically detected from the file extension
    • Pass though options to Puppeteer for precise control of image quality, encoding speed, and more
  • 📂 Customizable output paths: Full control over paths of the generated images
    • Save images to the public directory to include them in the build, unprocessed
    • Save images to the dist directory if you don't want to include theme in source control
    • Save them in the src dir for further compression or importing into components*
    • Or save them somewhere else, your choice
  • 🎛️ Default options: Reuse the same options for multiple images
    • Provide defaults for all options and override them on a per-image basis
  • 🔧 TypeScript support: Full type safety for all options and functions
    • No need to worry about typos or incorrect config values

Use cases

  • 🏞️ Social images: Use your existing front-end components to generate Open Graph images and/or Twitter cards for your blog posts or other content
  • 📰 Content previews: Generate screenshots of your website for use in documentation, marketing materials
  • 🖼️ Favicons: Dynamically generate favicons for your website

How it works

[!IMPORTANT] Note that, because this plugin runs after the build completes, you will not be able to import the generated images into your components or perform any further operations with them in the same build cycle.

You can, however, use them in the next build, provided they are not overwritten. If you do this, make sure to account for the images not existing the first time you perform a build (i.e. use a placeholder image or catch errors from import statements).

After the Astro build completes, this plugin uses Puppeteer to render the pages in a headless browser and save screenshots of the rendered content as images

📦 Installation

[!TIP] If you see any warnings like Cannot find package 'puppeteer' after adding the integration, your package manager may not have installed peer dependencies for you. If this happens, install Puppeteer manually like so:

npm install puppeteer

This package is available on both JSR and npm. It's also support the astro add command to update your astro.config.js automatically.

Automatic (w/ astro add)

[!NOTE] This grabs the package from npm. If you want to use the JSR version, you will need to install it manually.

We can use the Astro CLI to install the integration automatically using your preferred package manager:

deno run -A astro add astro-snapshot
bunx astro add astro-snapshot
npx astro add astro-snapshot
pnpm astro add astro-snapshot
yarn astro add astro-snapshot
vlt astro add astro-snapshot

If you run into any issues, try the manual installation steps below.

Manual

[!TIP] JSR has some advantages if you're using TypeScript or Deno:

  • It ships typed, modern ESM code by default
  • No need for separate type declarations
  • Faster, leaner installs without extraneous files

You can use JSR with your favorite package manager.

First, install it using your preferred package manager:

deno add jsr:@twocaretcat/astro-snapshot     # JSR (recommended)
deno add npm:@twocaretcat/astro-snapshot     # npm
bunx jsr add @twocaretcat/astro-snapshot     # JSR
bun add @twocaretcat/astro-snapshot          # npm
npx jsr add @twocaretcat/astro-snapshot      # JSR
npm install @twocaretcat/astro-snapshot      # npm
pnpm i jsr:@twocaretcat/astro-snapshot       # JSR
pnpm add @twocaretcat/astro-snapshot         # npm
yarn add jsr:@twocaretcat/astro-snapshot     # JSR
yarn add @twocaretcat/astro-snapshot         # npm
vlt install jsr:@twocaretcat/astro-snapshot  # JSR
vlt install @twocaretcat/astro-snapshot      # npm

Then, apply the integration to your astro.config.* file using the integrations property:

// astro.config.mjs
import { defineConfig } from 'astro/config';
+import snapshot from 'astro-snapshot';

export default defineConfig({
  // ...
-  integrations: [],
+  integrations: [snapshot()],
});

🕹️ Usage

Configure the Integration

Add the integration to your astro.config.mjs or astro.config.ts file and configure it like so:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import snapshot from 'astro-snapshot';

export default defineConfig({
	integrations: [
		snapshot({
			pages: {
				// Single screenshot for homepage
				'/': [
					{
						outputPath: 'public/og/home.png',
					},
				],
				// Multiple screenshots for about page (different sizes)
				'/about': [
					{
						outputPath: 'public/og/about-og.png',
						width: 1200,
						height: 630,
					},
					{
						outputPath: 'public/og/about-square.jpg',
						width: 1080,
						height: 1080,
					},
					{
						outputPath: 'public/og/about-twitter.png',
						width: 1200,
						height: 675,
					},
				],
			},
		}),
	],
});

🤖 Advanced Usage

Kitchen Sink

Here's an example with all available configuration options:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import snapshot from 'astro-snapshot';

export default defineConfig({
	integrations: [
		snapshot({
			// Pages to screenshot (required)
			pages: {
				'/': [
					{
						outputPath: 'public/og/home.png',
						width: 1200, // Viewport width (default: 1200)
						height: 630, // Viewport height (default: 630)
						overwrite: true, // Overwrite existing screenshots (default: false)

						// Puppeteer page.goto() options
						gotoOptions: {
							waitUntil: 'networkidle0',
							timeout: 30000,
						},

						// Puppeteer page.screenshot() options
						screenshotOptions: {
							quality: 95, // For jpeg only
							fullPage: false,
							clip: { // Capture specific region
								x: 0,
								y: 0,
								width: 1200,
								height: 630,
							},
						},

						// Puppeteer page.setViewport() options
						setViewportOptions: {
							deviceScaleFactor: 2, // Higher resolution screenshots
							isMobile: false,
							hasTouch: false,
							isLandscape: true,
						},
					},
				],
			},

			// Default config for all screenshots (optional)
			defaults: {
				width: 1200,
				height: 630,
				overwrite: true,
				gotoOptions: {
					waitUntil: 'networkidle2',
				},
				setViewportOptions: {
					deviceScaleFactor: 2,
				},
			},

			// Port for preview server (default: 4322)
			port: 4322,

			// Puppeteer launch options
			launchOptions: {
				headless: true,
				args: ['--no-sandbox', '--disable-setuid-sandbox'],
			},
		}),
	],
});

Multiple Formats for Social Media

[!TIP] If you need to reference output paths in your pages, define the config in a common place and import it into your pages as needed. The integration doesn't provide any methods for getting the output paths, so you'll need to manage that yourself.

Generate optimized images for different platforms:

// astro.config.mjs
const socialMediaSizes = {
	og: { width: 1200, height: 630 }, // OpenGraph
	twitter: { width: 1200, height: 600 }, // Twitter
	linkedin: { width: 1200, height: 627 }, // LinkedIn
	instagram: { width: 1080, height: 1080 }, // Instagram
};

export default defineConfig({
	integrations: [
		snapshot({
			pages: {
				'/': Object.entries(socialMediaSizes).map(([platform, dims]) => ({
					outputPath: `public/social/${platform}.png`,
					...dims,
				})),
			},
		}),
	],
});

Dynamic Blog Post Screenshots

Generate screenshots for all blog posts:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import snapshot from 'astro-snapshot';

// Get all blog post slugs (implement based on your setup)
const blogPosts = await getBlogPostSlugs();

// Create config for each blog post
const blogPages = Object.fromEntries(
	blogPosts.map((slug) => [
		`/blog/${slug}`,
		[
			{
				outputPath: `public/og/blog/${slug}.png`,
				width: 1200,
				height: 630,
			},
			{
				outputPath: `public/og/blog/${slug}-square.jpg`,
				width: 1080,
				height: 1080,
			},
		],
	]),
);

export default defineConfig({
	integrations: [
		snapshot({
			pages: {
				'/': [{ outputPath: 'public/og/home.png' }],
				'/about': [{ outputPath: 'public/og/about.png' }],
				...blogPages,
			},
		}),
	],
});

Conditional Screenshot Generation

[!TIP] Optimize build performance by conditionally generating screenshots based on environment variables or build mode.

Control when screenshots are generated:

// astro.config.mjs
const isDevelopment = process.env.NODE_ENV === 'development';
const shouldGenerateScreenshots = process.env.GENERATE_SCREENSHOTS === 'true';

export default defineConfig({
	integrations: [
		// Only add integration when needed
		...(shouldGenerateScreenshots || !isDevelopment
			? [
				snapshot({
					pages: {
						'/': [{ outputPath: 'public/og/home.png' }],
					},
				}),
			]
			: []),
	],
});

Custom Viewport Configurations

Different viewports for different purposes:

// astro.config.mjs
const viewports = {
	desktop: { width: 1920, height: 1080 },
	tablet: { width: 768, height: 1024 },
	mobile: { width: 375, height: 667 },
};

export default defineConfig({
	integrations: [
		snapshot({
			pages: {
				'/': Object.entries(viewports).map(([device, dims]) => ({
					outputPath: `public/previews/${device}.png`,
					...dims,
				})),
			},
		}),
	],
});

Waiting for Dynamic Content

Handle pages with animations or lazy-loaded content:

// astro.config.mjs
export default defineConfig({
	integrations: [
		snapshot({
			pages: {
				'/dashboard': [
					{
						outputPath: 'public/og/dashboard.png',
						gotoOptions: {
							waitUntil: 'networkidle0', // Wait for all network requests
							timeout: 60000, // Increase timeout
						},
					},
				],
			},
		}),
	],
});

📚 API Reference

SnapshotIntegrationConfig

| Property | Type | Required | Default | Description | | --------------- | ------------------------------------ | -------- | -------------------- | --------------------------------------- | | pages | Record<string, ScreenshotConfig[]> | ✅ | - | Map of page paths to screenshot configs | | defaults | Partial<ScreenshotConfig> | ❌ | {} | Default config for all screenshots | | launchOptions | PuppeteerLaunchOptions | ❌ | { headless: true } | Puppeteer launch options | | port | number | ❌ | 4322 | Preview server port |

ScreenshotConfig

| Property | Type | Required | Default | Description | | ------------------- | ------------------- | -------- | ------------------------------- | --------------------------------- | | outputPath | string | ✅ | - | Output path with format extension | | width | number | ❌ | 1200 | Viewport width in pixels | | height | number | ❌ | 630 | Viewport height in pixels | | gotoOptions | GoToOptions | ❌ | { waitUntil: 'networkidle2' } | Puppeteer goto options | | screenshotOptions | ScreenshotOptions | ❌ | {} | Puppeteer screenshot options |

Supported Formats

The format is automatically detected from the file extension in outputPath:

  • .png - PNG format
  • .jpg / .jpeg - JPEG format
  • .webp - WebP format

❓ FAQ

Screenshots not generating

  1. Check that pages are correctly specified in config
  2. Ensure Puppeteer dependencies are installed
  3. Verify the build completes without errors
  4. Check console output for screenshot generation logs

Permission errors

On some systems, Puppeteer may need additional configuration:

launchOptions: {
	args: ['--no-sandbox', '--disable-setuid-sandbox'];
}

Memory issues with many screenshots

Process pages in batches or increase Node memory:

NODE_OPTIONS="--max-old-space-size=4096" npm run build

Docker deployment

Add these args for containerized environments:

launchOptions: {
	args: [
		'--no-sandbox',
		'--disable-setuid-sandbox',
		'--disable-dev-shm-usage',
		'--disable-gpu',
	];
}

🤝 Contributing

Pull requests, bug reports, feature requests, and other kinds of contributions are welcome. See the contribution guide for more details.

🧾 License

Copyright © 2025 John Goodliff (@twocaretcat).

This project is licensed under the MIT license. See the license for more details.

We are not affiliated with or endorsed by Astro.

🖇️ Related

Recommended

Other projects you might like:

Used By

Notable projects that depend on this one:

  • 👤 Tally: A free online tool to count the number of characters, words, paragraphs, and lines in your text. Tally uses this integration to generate social images.

Alternatives

Similar projects you might want to use instead:

  • 🌐 astro-selfie: A similar integration that automatically generates images for every page.

💕 Funding

Find this project useful? Sponsoring me will help me cover costs and commit more time to open-source.

If you can't donate but still want to contribute, don't worry. There are many other ways to help out, like:

  • 📢 reporting (submitting feature requests & bug reports)
  • 👨‍💻 coding (implementing features & fixing bugs)
  • 📝 writing (documenting & translating)
  • 💬 spreading the word
  • ⭐ starring the project

I appreciate the support!