TypeScript Screenshot API Quick Start
Install the SnapAPI JavaScript SDK with npm and import the typed client in your TypeScript project. The SDK exports full TypeScript types for all request options and response objects, enabling IDE autocompletion and compile-time type checking for all SnapAPI parameters. Initialize the client with your API key from an environment variable and call the screenshot method with a typed options object.
import { SnapApiClient } from '@snapapi/client';
const client = new SnapApiClient({
apiKey: process.env.SNAPAPI_KEY!,
});
async function captureScreenshot(url: string): Promise {
const result = await client.screenshot({
url,
format: 'png',
fullPage: true,
width: 1280,
});
return result.image;
}
// Save to disk
import fs from 'fs/promises';
const image = await captureScreenshot('https://example.com');
await fs.writeFile('screenshot.png', image);
console.log('Captured', image.length, 'bytes');
Express Screenshot API Server
Express applications exposing screenshot endpoints define a route handler that validates the URL query parameter, calls the SnapAPI client, and sends the PNG bytes in the response with a Content-Type: image/png header. Use express-rate-limit middleware on the screenshot route to prevent individual clients from exhausting your SnapAPI plan's rate limit, setting the rate limit window and max requests to values that keep total traffic within the plan's per-second limit. Add a caching layer using node-cache or the ioredis Redis client to store screenshot results by URL with a configurable TTL, returning cached bytes for repeat requests without calling SnapAPI.
import express from 'express';
import rateLimit from 'express-rate-limit';
import { SnapApiClient } from '@snapapi/client';
import NodeCache from 'node-cache';
const app = express();
const client = new SnapApiClient({ apiKey: process.env.SNAPAPI_KEY! });
const cache = new NodeCache({ stdTTL: 86400 });
app.get('/screenshot', rateLimit({ windowMs: 60000, max: 30 }), async (req, res) => {
const { url } = req.query as { url: string };
if (!url) return res.status(400).json({ error: 'url required' });
const cached = cache.get(url);
if (cached) return res.set('Content-Type', 'image/png').send(cached);
const result = await client.screenshot({ url, fullPage: true });
cache.set(url, result.image);
res.set('Content-Type', 'image/png').send(result.image);
});
app.listen(3000);
Fastify Screenshot API with TypeBox Schema Validation
Fastify applications use TypeBox for JSON schema validation of screenshot API request parameters, providing compile-time type safety and runtime request validation in a single schema definition. Define a TypeBox schema for the screenshot request query parameters, register it with the Fastify route's schema option, and use the typed request object in the route handler without additional validation code. Fastify's built-in schema validation rejects requests with invalid or missing URL parameters before they reach the SnapAPI client, returning a typed 400 error response that matches your API contract. Fastify's async plugin system makes it clean to register the SnapAPI client as a shared Fastify plugin decorated onto the Fastify instance, making the typed client accessible in all route handlers through the Fastify decorator pattern without passing the client through handler arguments.
Bulk Screenshot Capture with p-limit
Node.js applications capturing screenshots for many URLs concurrently use the p-limit package to cap the number of simultaneous SnapAPI calls, preventing rate limit exhaustion while maximizing throughput. p-limit creates a concurrency-limited function wrapper that queues excess calls until running calls complete, exposing a clean async interface that is drop-in compatible with Promise.all. Map each URL to a p-limit-wrapped screenshot call, collect all the limited promises in an array, and await Promise.all to process all URLs concurrently at the configured limit.
import pLimit from 'p-limit';
import { SnapApiClient } from '@snapapi/client';
const client = new SnapApiClient({ apiKey: process.env.SNAPAPI_KEY! });
const limit = pLimit(5); // 5 concurrent SnapAPI calls
async function captureAll(urls: string[]) {
const tasks = urls.map(url =>
limit(() => client.screenshot({ url, format: 'png' }))
);
return Promise.allSettled(tasks);
}
const urls = ['https://example.com', 'https://news.ycombinator.com', ...];
const results = await captureAll(urls);
results.forEach((r, i) => {
if (r.status === 'fulfilled') console.log(urls[i], r.value.image.length, 'bytes');
else console.error(urls[i], r.reason.message);
});
Next.js Screenshot API Integration
Next.js applications generate screenshots in API routes and Server Actions using the SnapAPI JavaScript SDK. In the App Router, define a Route Handler in app/api/screenshot/route.ts that reads the URL from the request search params, calls the SnapAPI client, and returns a Response with the PNG bytes and the Content-Type: image/png header. Use Next.js's built-in caching for Route Handlers by exporting a revalidate constant that sets the cache duration for the route's responses, enabling Next.js's data cache to serve repeated screenshot requests for the same URL from cache without calling SnapAPI on every request. For Server Actions that generate screenshots as part of form submissions or user interactions, call the SnapAPI client directly from the Server Action function, upload the result to Vercel Blob or an S3-compatible storage provider, and return the storage URL to the client component for display.
// app/api/screenshot/route.ts
import { SnapApiClient } from '@snapapi/client';
import { NextRequest } from 'next/server';
export const revalidate = 86400; // cache 24 hours
const client = new SnapApiClient({ apiKey: process.env.SNAPAPI_KEY! });
export async function GET(req: NextRequest) {
const url = req.nextUrl.searchParams.get('url');
if (!url) return Response.json({ error: 'url required' }, { status: 400 });
const result = await client.screenshot({ url, fullPage: true, width: 1280 });
return new Response(result.image, {
headers: { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=86400' },
});
}
TypeScript Screenshot API with Bull Queue
Node.js TypeScript applications processing screenshot jobs at scale use Bull or BullMQ backed by Redis as the job queue, enabling durable asynchronous screenshot processing with automatic retries, job prioritization, and concurrency control. Define a ScreenshotJob TypeScript interface for the job payload, create a Bull queue with a concurrency limit that respects the SnapAPI rate limit, and define a processor function that calls the SnapAPI client and stores the result in S3 or your preferred storage layer. BullMQ's worker class handles the job polling, concurrency management, and retry logic with exponential backoff automatically, simplifying the worker implementation to the core screenshot and storage logic. Use Bull's job events to track screenshot job completion, failure, and stalling, publishing metrics from these events to your application's monitoring system to track queue health and screenshot throughput over time.
import { Queue, Worker } from 'bullmq';
import { SnapApiClient } from '@snapapi/client';
interface ScreenshotJob { url: string; recordId: string; }
const queue = new Queue('screenshots', { connection: { host: 'localhost' } });
const client = new SnapApiClient({ apiKey: process.env.SNAPAPI_KEY! });
const worker = new Worker('screenshots', async job => {
const result = await client.screenshot({ url: job.data.url, fullPage: true });
await uploadToS3(job.data.recordId, result.image); // your S3 upload
}, { connection: { host: 'localhost' }, concurrency: 5 });
// Enqueue a job
await queue.add('capture', { url: 'https://example.com', recordId: 'abc123' });
TypeScript Screenshot API Error Handling Best Practices
TypeScript's type system enables exhaustive error handling for SnapAPI integrations using discriminated union types that represent the full set of possible outcomes. Define a ScreenshotResult discriminated union with success and error variants, map SnapAPI SDK exceptions to error variants in a typed wrapper function, and use TypeScript's narrowing to handle each error variant explicitly at the call site. This approach makes error handling code visible and compile-time verified — a TypeScript error at the call site immediately flags unhandled error cases when new error variants are added to the union. For Express and Fastify route handlers, define a typed error handler middleware that receives SnapAPI errors from the route handler via next(error) and returns the appropriate HTTP response for each error type, centralizing error-to-HTTP-response mapping in a single typed middleware rather than duplicating it across route handlers.
TypeScript Screenshot API Testing with Jest and MSW
TypeScript screenshot service tests use Mock Service Worker to intercept SnapAPI HTTP requests at the network layer, enabling realistic integration tests that exercise the full request-response cycle without making real API calls. Configure an MSW server in Jest's setup file with a handler that returns a fixture PNG buffer for valid screenshot requests and a 429 response for rate limit simulation. TypeScript's type system ensures that MSW handler implementations match the SnapAPI endpoint's type signature, catching handler implementation mismatches at compile time. Test async screenshot workflows with Jest's fake timers to control the timing of retry delays and cache TTL expiration, enabling fast-running tests that cover time-dependent behavior without waiting for real time to pass. Use supertest to send HTTP requests to your Express or Fastify server in tests, asserting the response status, headers, and body type for each screenshot endpoint scenario.