How to Use Screenshot API with Next.js
Build screenshot-powered features into your Next.js application -- from dynamic OG images to link preview generators and visual testing.
2026-03-14 -- 10 min readNext.js is the most popular React framework, and it pairs perfectly with a screenshot API. Whether you need dynamic OG images, link preview thumbnails, or visual regression testing, this guide shows you how to integrate ScreenshotAPI into your Next.js project.
Installation
First, install our Node.js SDK:
npm install screenshotapi-nodeAdd your API key to .env.local:
SCREENSHOTAPI_KEY=sk_live_your_api_key_hereUse Case 1: Dynamic OG Images via API Route
Generate Open Graph images on-the-fly for your blog posts or product pages. Create an API route that captures a screenshot of a template page:
// app/api/og/route.js
import ScreenshotAPI from 'screenshotapi-node';
const client = new ScreenshotAPI(process.env.SCREENSHOTAPI_KEY);
export async function GET(request) {
const { searchParams } = new URL(request.url);
const title = searchParams.get('title') || 'My Page';
// Capture a screenshot of your OG template page
const templateUrl = `${process.env.NEXT_PUBLIC_URL}/og-template?title=${encodeURIComponent(title)}`;
const screenshot = await client.screenshot(templateUrl, {
width: 1200,
height: 630,
format: 'png',
});
return new Response(screenshot, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'public, max-age=86400, s-maxage=86400',
},
});
}Then reference it in your page metadata:
// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
openGraph: {
images: [`/api/og?title=${encodeURIComponent(post.title)}`],
},
};
}Use Case 2: Link Preview Component
Build a component that shows a visual preview of any URL, similar to what Slack and Discord show when you paste a link:
// app/api/preview/route.js
import ScreenshotAPI from 'screenshotapi-node';
const client = new ScreenshotAPI(process.env.SCREENSHOTAPI_KEY);
export async function GET(request) {
const { searchParams } = new URL(request.url);
const url = searchParams.get('url');
if (!url) {
return Response.json({ error: 'url is required' }, { status: 400 });
}
const screenshot = await client.screenshot(url, {
width: 1280,
height: 800,
format: 'jpeg',
quality: 80,
blockAds: true,
blockCookieBanners: true,
outputWidth: 400, // Thumbnail size
});
return new Response(screenshot, {
headers: {
'Content-Type': 'image/jpeg',
'Cache-Control': 'public, max-age=3600',
},
});
}Use it in a React component:
// components/LinkPreview.jsx
'use client';
import { useState } from 'react';
import Image from 'next/image';
export default function LinkPreview({ url }) {
const previewUrl = `/api/preview?url=${encodeURIComponent(url)}`;
const [error, setError] = useState(false);
if (error) return <a href={url}>{url}</a>;
return (
<a href={url} className="block border rounded-lg overflow-hidden hover:shadow-lg transition">
<Image
src={previewUrl}
alt={`Preview of ${url}`}
width={400}
height={250}
onError={() => setError(true)}
/>
<div className="p-3">
<p className="text-sm text-slate-500 truncate">{url}</p>
</div>
</a>
);
}Use Case 3: PDF Generation from Server Components
Generate PDFs of any page directly from a Next.js server action:
// app/api/pdf/route.js
import ScreenshotAPI from 'screenshotapi-node';
const client = new ScreenshotAPI(process.env.SCREENSHOTAPI_KEY);
export async function POST(request) {
const { url } = await request.json();
const pdf = await client.pdf(url, {
format: 'A4',
background: true,
});
return new Response(pdf, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename="page.pdf"',
},
});
}Use Case 4: Visual Regression Testing in CI
Compare screenshots of your Next.js pages across deployments to catch visual bugs:
// scripts/visual-test.mjs
import ScreenshotAPI from 'screenshotapi-node';
import fs from 'fs';
const client = new ScreenshotAPI(process.env.SCREENSHOTAPI_KEY);
const baseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: 'http://localhost:3000';
const pages = ['/', '/pricing', '/docs', '/blog'];
for (const page of pages) {
const screenshot = await client.screenshot(`${baseUrl}${page}`, {
width: 1280,
height: 800,
format: 'png',
wait: 2000,
blockCookieBanners: true,
});
const filename = page === '/' ? 'home' : page.slice(1).replace(/\//g, '-');
fs.writeFileSync(`screenshots/${filename}.png`, screenshot);
console.log(`Captured: ${page}`);
}Use Case 5: Async Screenshots with Webhooks
For pages that take a long time to render, use async mode with a webhook callback:
// app/api/screenshot/async/route.js
import ScreenshotAPI from 'screenshotapi-node';
const client = new ScreenshotAPI(process.env.SCREENSHOTAPI_KEY);
export async function POST(request) {
const { url } = await request.json();
const job = await client.screenshotAsync(
url,
`${process.env.NEXT_PUBLIC_URL}/api/screenshot/webhook`,
{ width: 1920, height: 1080, format: 'png' }
);
return Response.json({ jobId: job.jobId, status: 'processing' });
}
// app/api/screenshot/webhook/route.js
export async function POST(request) {
const data = await request.json();
console.log('Screenshot ready:', data);
// Store result, notify user, etc.
return Response.json({ received: true });
}Best Practices for Next.js Integration
1. Cache aggressively
Screenshots are expensive to generate. Use Next.js response caching and set appropriate Cache-Control headers:
// Set 24-hour cache for OG images
'Cache-Control': 'public, max-age=86400, s-maxage=86400, stale-while-revalidate=3600'2. Use environment variables
Never hardcode API keys. Use .env.local for local development and set environment variables in your Vercel project settings for production.
3. Handle errors gracefully
import { ScreenshotAPIError } from 'screenshotapi-node';
try {
const screenshot = await client.screenshot(url);
return new Response(screenshot, { headers: { 'Content-Type': 'image/png' } });
} catch (err) {
if (err instanceof ScreenshotAPIError) {
if (err.statusCode === 429) {
return Response.json({ error: 'Rate limited, try again later' }, { status: 429 });
}
return Response.json({ error: err.message }, { status: err.statusCode });
}
return Response.json({ error: 'Screenshot failed' }, { status: 500 });
}4. Use the SDK timeout
Set a reasonable timeout to avoid hanging requests, especially in serverless environments where function execution time is limited:
const client = new ScreenshotAPI(process.env.SCREENSHOTAPI_KEY, {
timeout: 15000, // 15 seconds (Vercel free tier has 10s limit)
});Pricing for Next.js Apps
Our free tier includes 100 screenshots per month -- enough for development and small projects. For production apps generating OG images or link previews at scale, the Pro plan ($29/mo) gives you 10,000 screenshots per month.
Ready to integrate?
Get your free API key and start building screenshot features into your Next.js app today.
Next Steps
- Full API Documentation -- all endpoints and parameters
- Build Link Previews -- detailed tutorial
- OG Image Generator -- advanced OG image patterns
- Visual Regression Testing -- CI/CD integration guide