Screenshot API with Next.js App Router: Complete Guide
Next.js App Router introduced a fundamentally new model for React server components, route handlers, and server actions. Integrating SnapAPI into an App Router project differs from the Pages Router approach in important ways. This guide covers every integration pattern for Next.js 13+ with the App Router.
Route Handler for Server-Side Capture
Create a Route Handler at app/api/screenshot/route.ts to keep your API key server-side and never exposed to the browser:
import { NextRequest, NextResponse } from "next/server"
export async function GET(request: NextRequest) {
const url = request.nextUrl.searchParams.get("url")
if (!url) return NextResponse.json({ error: "url required" }, { status: 400 })
const params = new URLSearchParams({
access_key: process.env.SNAPAPI_KEY!,
url,
response_type: "json",
width: "1280",
full_page: "true"
})
const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`, {
next: { revalidate: 3600 }
})
const data = await res.json()
return NextResponse.json(data)
}
Server Component Integration
In App Router, Server Components can call the SnapAPI endpoint directly during server-side rendering. This is ideal for generating OG images or page previews at render time with built-in caching:
async function getScreenshot(url: string) {
const params = new URLSearchParams({
access_key: process.env.SNAPAPI_KEY!,
url,
response_type: "json"
})
const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`, {
next: { revalidate: 86400 }
})
const data = await res.json()
return data.url as string
}
export default async function PreviewCard({ pageUrl }: { pageUrl: string }) {
const imgUrl = await getScreenshot(pageUrl)
return
}
OG Image Generation with ImageResponse
For dynamic OG images, combine Next.js ImageResponse with SnapAPI. Create app/og/route.tsx:
import { ImageResponse } from "next/og"
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const targetUrl = searchParams.get("url") ?? ""
const params = new URLSearchParams({
access_key: process.env.SNAPAPI_KEY!,
url: targetUrl,
response_type: "json",
width: "1200", height: "630"
})
const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
const { url: screenshotUrl } = await res.json()
return new ImageResponse(
,
{ width: 1200, height: 630 }
)
}
Server Actions for Form-Based Capture
Use Server Actions to trigger screenshot captures from client components without building a separate API endpoint:
"use server"
import { revalidatePath } from "next/cache"
export async function captureAction(formData: FormData) {
const url = formData.get("url") as string
const params = new URLSearchParams({
access_key: process.env.SNAPAPI_KEY!,
url, response_type: "json"
})
const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
const data = await res.json()
await db.captures.create({ data: { url, screenshotUrl: data.url } })
revalidatePath("/captures")
}
Caching Strategy in App Router
Next.js App Router fetch caching integrates naturally with SnapAPI calls. Pass next.revalidate in seconds to set ISR-style cache TTL. For screenshot URLs that rarely change, cache for 24 hours: next: revalidate: 86400. For pages that update frequently such as news articles or live dashboards, use a shorter TTL like 300 seconds or opt out of caching entirely with next: revalidate: 0. For on-demand revalidation, call revalidateTag or revalidatePath after your content updates to purge stale screenshots.
Environment Variables
Add SNAPAPI_KEY to your .env.local file. In Next.js App Router, environment variables without the NEXT_PUBLIC_ prefix are only available on the server, which is exactly right for API keys. Never prefix your SnapAPI key with NEXT_PUBLIC_ as this would expose it in the browser bundle. Configure the variable in your Vercel, Netlify, or cloud deployment environment settings dashboard for production deployments.
TypeScript Types
interface SnapAPIResponse {
url: string
width: number
height: number
format: string
size: number
took: number
}
async function screenshot(pageUrl: string): Promise {
const params = new URLSearchParams({
access_key: process.env.SNAPAPI_KEY!,
url: pageUrl,
response_type: "json"
})
const res = await fetch(`https://snapapi.pics/api/screenshot?${params}`)
if (!res.ok) throw new Error("SnapAPI error: " + res.status)
return res.json()
}
Get Started Free
SnapAPI works out of the box with Next.js App Router. Add your API key to .env.local, create a Route Handler, and your first screenshot is ready in under ten minutes. Free tier includes 200 captures per month. Paid plans start at $19 per month for 5,000 screenshots.
Get Free API Key