Screenshot API for Next.js: Complete Integration Guide
Next.js powers a significant share of modern web applications, from marketing sites and SaaS dashboards to full-stack platforms with complex server-side rendering requirements. If your Next.js application needs screenshot, scraping, or PDF generation capabilities, SnapAPI integrates cleanly with both the App Router and Pages Router paradigms. This guide covers Route Handlers, Server Actions, background queue integration, and testing patterns for Next.js applications.
Basic Integration with Route Handlers (App Router)
// app/api/screenshot/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
const { url, fullPage = false } = await request.json();
const response = await fetch("https://snapapi.pics/api/screenshot", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.SNAPAPI_KEY!,
},
body: JSON.stringify({ url, full_page: fullPage, format: "png" }),
});
if (!response.ok) {
return NextResponse.json({ error: "Screenshot failed" }, { status: 500 });
}
const data = await response.json();
return NextResponse.json({ screenshotUrl: data.url, capturedAt: data.captured_at });
}Server Actions for Form-Based Captures
// app/actions/screenshot.ts
"use server";
import { revalidatePath } from "next/cache";
export async function capturePageScreenshot(formData: FormData) {
const url = formData.get("url") as string;
const response = await fetch("https://snapapi.pics/api/screenshot", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.SNAPAPI_KEY!,
},
body: JSON.stringify({ url, format: "png", full_page: true }),
cache: "no-store",
});
const { url: screenshotUrl } = await response.json();
// Update database record
await db.pages.update({ where: { url }, data: { screenshotUrl } });
revalidatePath("/dashboard");
return { screenshotUrl };
}Service Class with Caching
// lib/snapapi.ts
import { unstable_cache } from "next/cache";
const SNAPAPI_URL = "https://snapapi.pics";
async function fetchScreenshot(url: string, options: Record = {}) {
const response = await fetch(`${SNAPAPI_URL}/api/screenshot`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.SNAPAPI_KEY!,
},
body: JSON.stringify({ url, format: "png", ...options }),
});
if (!response.ok) throw new Error(`SnapAPI error: ${response.status}`);
return response.json();
}
// Cached version using Next.js unstable_cache (15-minute TTL)
export const getCachedScreenshot = unstable_cache(
async (url: string) => fetchScreenshot(url),
["screenshot"],
{ revalidate: 900 } // 15 minutes
);
export async function generatePdf(url: string): Promise {
const data = await fetchScreenshot(url, { format: "pdf", full_page: true });
return data.url;
}
export async function extractData(url: string, fields: string[]): Promise> {
const response = await fetch(`${SNAPAPI_URL}/api/extract`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.SNAPAPI_KEY!,
},
body: JSON.stringify({ url, fields }),
});
const data = await response.json();
return data.data || {};
} Pages Router API Route
// pages/api/screenshot.ts
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") return res.status(405).end();
const { url } = req.body;
if (!url) return res.status(400).json({ error: "url required" });
const response = await fetch("https://snapapi.pics/api/screenshot", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.SNAPAPI_KEY!,
},
body: JSON.stringify({ url, format: "png" }),
});
const data = await response.json();
return res.status(200).json({ screenshotUrl: data.url });
}OG Image Generation with Next.js
One of the best applications of SnapAPI in Next.js is automated OG image generation for dynamic routes. When a blog post, product page, or profile page is published, trigger a SnapAPI call from your CMS webhook handler to capture the page and store the screenshot as the Open Graph image:
// app/api/webhooks/cms/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
const { pageUrl, slug } = await request.json();
// Capture OG image at 1200x630
const res = await fetch("https://snapapi.pics/api/screenshot", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": process.env.SNAPAPI_KEY! },
body: JSON.stringify({
url: pageUrl,
viewport_width: 1200,
viewport_height: 630,
format: "jpeg",
quality: 90
}),
});
const { url: ogImageUrl } = await res.json();
// Store in your CMS or database
await cms.updatePage({ slug, ogImage: ogImageUrl });
return NextResponse.json({ ogImageUrl });
}Environment Configuration
# .env.local
SNAPAPI_KEY=your_api_key_here
# .env.example (commit this, not .env.local)
SNAPAPI_KEY=your_snapapi_key_from_dashboardTesting with Jest and MSW
// __tests__/screenshot.test.ts
import { setupServer } from "msw/node";
import { http, HttpResponse } from "msw";
const server = setupServer(
http.post("https://snapapi.pics/api/screenshot", () => {
return HttpResponse.json({
url: "https://cdn.snapapi.pics/test/screenshot.png",
captured_at: "2026-04-04T10:00:00Z",
});
})
);
beforeAll(() => server.listen());
afterAll(() => server.close());
test("screenshot route returns url", async () => {
const res = await fetch("/api/screenshot", {
method: "POST",
body: JSON.stringify({ url: "https://example.com" }),
headers: { "Content-Type": "application/json" },
});
const data = await res.json();
expect(data.screenshotUrl).toContain("snapapi.pics");
});Getting Started
Create your free SnapAPI account at snapapi.pics/dashboard. Add your API key to your Next.js environment variables and you are ready to integrate. The free plan provides 200 monthly screenshots for development. The TypeScript SDK is available via npm: npm install snapapi-js. Starter plan ($19/month) for 5,000 captures; Growth plan ($79/month) for 50,000 with full extract and scrape access.