A screenshot API client for Node.js applications
The official @snapshot-site/sdk package wraps Snapshot Site's screenshot, analysis, and comparison workflows in one SnapshotSiteClient. It is intended for Node.js code that can protect an API key: application servers, server routes, workers, scheduled scripts, and CI jobs.
The SDK requires Node.js 20.9 or later and ships as CommonJS with bundled type declarations. TypeScript users get typed request and response surfaces, while JavaScript applications can call the same runtime client without adopting TypeScript.
Use raw HTTP when a platform cannot run the package or when avoiding dependencies is a firm requirement. Use the SDK when a shared client, types, and consistent method names reduce repeated request plumbing across a Node.js codebase.
Configure the client securely
Create the client once with a server-side API key and reuse it in the scope appropriate for the application. Read the value from process.env.SNAPSHOT_SITE_API_KEY or a secret manager. Do not add it to a public environment variable, browser bundle, error response, or repository file.
import { SnapshotSiteClient } from "@snapshot-site/sdk";
export const snapshotSite = new SnapshotSiteClient({
apiKey: process.env.SNAPSHOT_SITE_API_KEY!,
});
Validate that the environment variable exists during application startup. A non-null assertion satisfies TypeScript but does not create the value at runtime. Failing early produces a clearer deployment error than waiting for the first screenshot request.
Keep the SDK on the server
In a full-stack framework, place the configured client in server-only code. A Next.js route handler, server action, queue worker, or backend service can call it and return only the result the user is authorized to see. Browser-side code should call your server, not Snapshot Site with a private key.
Choose the method by workflow
screenshot() for rendered assets
Use client.screenshot() when the application needs a website image or document. Keep width explicit, set fullSize when the entire scrollable page matters, and choose the output format according to the consumer. The full-page screenshot guide covers long-page timing and cleanup decisions.
analyze() for structured page insights
Use client.analyze() when a rendered page should also produce summary or quality information. Request only the analysis options the workflow uses, and preserve the source screenshot when a reviewer may need to inspect the evidence.
compare() for visual differences
Use client.compare() with two controlled sources to receive before, after, and diff information. Keep capture settings identical across both states. The Visual Diff API page explains baselines, mismatch thresholds, and false-positive control.
Organize a production integration
Keep capture configuration close to the use case instead of scattering raw objects across the application. A documentation job, social-preview generator, and release comparison require different widths, formats, and timing. Named configuration builders make those decisions reviewable.
const documentationCapture = (url: string) => ({
url,
format: "webp" as const,
width: 1440,
fullSize: true,
hideCookie: true,
delay: 2,
});
const result = await snapshotSite.screenshot(
documentationCapture("https://example.com/docs/start"),
);
Validate user-supplied URLs before building a request. If the product is intended to capture only approved sites, enforce an allowlist in your application. Avoid logging URLs containing credentials, private identifiers, or sensitive query parameters.
Error handling and retries
Treat every remote call as a fallible application operation. Wrap jobs with context that identifies the sanitized URL and workflow, and decide which failures should be retried. Invalid input and authorization failures need correction; repeated retries do not fix them.
For a batch, record success or failure per URL. Use a queue or small worker pool rather than launching an unbounded Promise.all. Bounded concurrency protects application memory, respects service limits, and lets the job resume without repeating completed work.
for (const url of urls) {
try {
const result = await snapshotSite.screenshot({ url, format: "webp" });
await saveResult(url, result);
} catch (error) {
await recordFailure(url, error);
}
}
Sequential code is intentionally simple; introduce concurrency only after measuring the real workload and defining retry behavior.
Performance practices
Cache outputs that remain valid instead of capturing the same stable page on every application request. Use viewport screenshots when only the fold is needed and full-page mode when content completeness matters. Choose a deliberate delay based on page behavior rather than adding a large wait to every request.
For scheduled jobs, prevent overlapping runs over the same URL set. Store enough configuration with the result to reproduce it later. If an image will be compared, keep width, timing, cookie handling, and other visual settings stable.
Common Node.js integration mistakes
- Importing a configured SDK client into browser-bundled code.
- Assuming a TypeScript non-null assertion validates an environment variable.
- Launching thousands of requests in one unbounded
Promise.all.
- Retrying invalid requests indefinitely.
- Logging the API key or sensitive target URLs.
- Recreating the same stable capture instead of caching it.
- Comparing images produced with different settings.
Use the API documentation as the endpoint source of truth and the package README for runtime compatibility. Start with one typed server-side call, then extract shared configuration as the integration grows.