Skip to content

twocaretcat/astro-snapshot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

28 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“Έ Astro Snapshot

Project category Language Repository size Project license Semantic Release

Latest release View package on JSR View package on JSR View package on npmjs

An Astro integration for generating screenshots of your pages automatically at build time


Warning

This is currently an experimental project or proof-of-concept. It may contain bugs or incomplete features, and is not intended for production use. Breaking changes may be made at any time. Consider more stable alternatives for critical applications.

πŸ‘‹ About

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

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
deno run -A astro add astro-snapshot
πŸ₯– Bun
bunx astro add astro-snapshot
🟒 npm
npx astro add astro-snapshot
🟧 pnpm
pnpm astro add astro-snapshot
🧢 yarn
yarn astro add astro-snapshot
πŸ–‡ vlt
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
deno add jsr:@twocaretcat/astro-snapshot     # JSR (recommended)
deno add npm:@twocaretcat/astro-snapshot     # npm
πŸ₯– Bun
bunx jsr add @twocaretcat/astro-snapshot     # JSR
bun add @twocaretcat/astro-snapshot          # npm
🟒 npm
npx jsr add @twocaretcat/astro-snapshot      # JSR
npm install @twocaretcat/astro-snapshot      # npm
🟧 pnpm
pnpm i jsr:@twocaretcat/astro-snapshot       # JSR
pnpm add @twocaretcat/astro-snapshot         # npm
🧢 yarn
yarn add jsr:@twocaretcat/astro-snapshot     # JSR
yarn add @twocaretcat/astro-snapshot         # npm
πŸ–‡ vlt
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

Full Configuration Example

// 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)

						// 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,
							},
						},
					},
				],
			},

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

			// 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 greatly appreciated. See the contribution guide for more details.

🧾 License

Copyright Β© 2025 John Goodliff.

This project is licensed under the MIT License. See LICENSE for details.

We are not affiliated with or endorsed by Astro.

πŸ–‡οΈ Related

Recommended

Used By

  • πŸ‘€ 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

  • 🌐 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!

Sponsor this project

  •  

Packages

No packages published

Contributors 2

  •  
  •