Screenshot API Express.js Guide 2026

Integrate SnapAPI into Express.js with axios, middleware patterns, Redis caching, and production deployment. Full Node.js code examples for backend applications.

Get Free API Key

Calling SnapAPI from Express.js with Axios

Express.js route handlers call SnapAPI using the axios library with the API key from an environment variable. Create a utility module that configures an axios instance with the SnapAPI base URL and authorization header, then exports screenshot, scrape, and extract functions that other modules can import. This centralized client module ensures the API key is loaded once, the axios configuration is consistent across all SnapAPI calls in the application, and adding logging or retry logic requires changing only one location. Use async/await in route handlers for clean error propagation: if the SnapAPI call throws an error, the async route handler catches it and passes it to Express's error handling middleware via next(err).

// lib/snapapi.js
const axios = require("axios")

const client = axios.create({
  baseURL: "https://api.snapapi.pics",
  headers: { Authorization: `Bearer ${process.env.SNAPAPI_KEY}` },
  timeout: 30000,
  responseType: "arraybuffer",
})

async function screenshot(url, opts = {}) {
  const { data } = await client.get("/screenshot", {
    params: { url, format: opts.format || "png",
              ...(opts.fullPage ? { full_page: "true" } : {}),
              ...(opts.delay ? { delay: opts.delay } : {}) },
  })
  return Buffer.from(data)
}

async function scrape(url) {
  const { data } = await client.get("/scrape",
    { params: { url }, responseType: "json" })
  return data
}

module.exports = { screenshot, scrape }

// routes/screenshot.js
const { Router } = require("express")
const { screenshot } = require("../lib/snapapi")

const router = Router()

router.get("/", async (req, res, next) => {
  const { url } = req.query
  if (!url) return res.status(400).json({ error: "url required" })
  try {
    const img = await screenshot(url, { fullPage: true })
    res.set("Content-Type", "image/png").send(img)
  } catch (err) {
    next(err)
  }
})

module.exports = router

Express.js Screenshot API with Redis Caching

Add Redis caching to the Express screenshot route to avoid redundant SnapAPI calls for frequently requested URLs. Use the ioredis client to connect to Redis and implement a caching middleware that checks the cache before calling SnapAPI. The cache key is the SHA-256 hash of the URL and format parameters, and the cached value is the screenshot buffer stored as a base64 string with a TTL of one hour. For applications where screenshot content changes infrequently relative to the request rate, this caching reduces SnapAPI usage by the cache hit rate percentage, significantly extending the value of each plan tier. Implement cache invalidation endpoints that allow specific URLs to be purged from the cache manually when you know the page content has changed and want subsequent requests to generate a fresh screenshot.

const Redis = require("ioredis")
const crypto = require("crypto")
const redis = new Redis(process.env.REDIS_URL)

const CACHE_TTL = 3600 // 1 hour

function cacheKey(url, format) {
  return "snap:" + crypto.createHash("sha256")
    .update(url + format).digest("hex")
}

router.get("/cached", async (req, res, next) => {
  const { url, format = "png" } = req.query
  if (!url) return res.status(400).json({ error: "url required" })
  const key = cacheKey(url, format)
  try {
    const cached = await redis.get(key)
    if (cached) {
      const buf = Buffer.from(cached, "base64")
      return res.set("X-Cache", "HIT")
        .set("Content-Type", `image/${format}`)
        .send(buf)
    }
    const img = await screenshot(url, { format })
    await redis.setex(key, CACHE_TTL, img.toString("base64"))
    res.set("X-Cache", "MISS")
      .set("Content-Type", `image/${format}`)
      .send(img)
  } catch (err) { next(err) }
})

Express.js Screenshot API with Rate Limiting

Protect your Express screenshot endpoint from abuse using the express-rate-limit middleware with a Redis store for distributed rate limit tracking across multiple Express instances. Configure a rate limiter that allows ten screenshot requests per minute per IP address for public-facing endpoints, returning a 429 status with the Retry-After header when the limit is exceeded. For authenticated endpoints, use the user ID as the rate limit key rather than the IP address to enforce per-user limits that are consistent across IP addresses. Add a rate limit header to successful responses showing the remaining request count and the reset time so clients can adapt their request rate proactively rather than waiting for a 429 response.

Get Started with SnapAPI in Express.js

Install axios and optionally ioredis for caching: npm install axios ioredis express-rate-limit. Set SNAPAPI_KEY in your .env file and load it with dotenv or your chosen environment variable management approach. Register at snapapi.pics/register for a free API key with two hundred monthly requests. The pattern described in this guide applies equally to standalone Express applications and to Express used as the web layer in larger Node.js applications with TypeScript, Fastify, or NestJS. For TypeScript Express projects, the axios and ioredis packages include TypeScript type definitions that provide full type safety without additional @types packages.

Express.js Screenshot API Error Handling Middleware

Express.js error handling middleware provides a centralized location for handling SnapAPI errors consistently across all screenshot-related routes. Define an error handling middleware at the end of your Express application's middleware stack that checks for SnapAPI-specific error types and maps them to appropriate HTTP responses. When SnapAPI returns a 429 status code indicating rate limiting, the error middleware should return a 503 Service Unavailable response to the client with a Retry-After header, indicating that the screenshot service is temporarily at capacity. When SnapAPI returns a 400 status code for an invalid URL, the error middleware should return a 422 Unprocessable Entity response to the client with a descriptive error message. When SnapAPI returns a 401 status code indicating an invalid API key, the error middleware should log an alert to your monitoring system and return a 502 Bad Gateway response, as this indicates a configuration problem that requires immediate attention from your operations team rather than a client-side error.

Express.js Screenshot API with TypeScript

TypeScript projects using Express benefit from typed interfaces for the SnapAPI request parameters and response types. Define a SnapApiOptions interface with optional properties for format, fullPage, delay, width, and height. Define a SnapApiScrapeResult interface with string fields for title, description, text, and html. Create a typed SnapApiClient class that wraps axios with generic method signatures that return the appropriate response type for each endpoint. Configure TypeScript's strict mode to catch type errors in the SnapAPI client usage at compile time rather than at runtime. For Express route handlers with TypeScript, use the Request and Response generics from @types/express to type the query parameters and response body, ensuring that the screenshot URL parameter is properly validated as a string before passing it to the SnapAPI client. The TypeScript types add minimal overhead but provide significant safety benefits in larger Express applications where SnapAPI calls are distributed across multiple route handlers and middleware functions.

Express.js Screenshot API Integration Testing

Integration tests for Express.js screenshot routes should verify the full request-response cycle including URL validation, SnapAPI call mocking, response format, and error handling. Use supertest to make HTTP requests to your Express app in tests without starting a real server. Mock the axios SnapAPI client using Jest's module mocking to return a small test PNG buffer without making real HTTP calls, keeping tests fast and independent of external services. Write test cases for the success path, the missing URL parameter error, the invalid URL format error, and the SnapAPI error response to ensure all code paths in the route handler are covered. For Redis caching integration tests, use ioredis-mock to provide an in-memory Redis mock that behaves identically to the real Redis client without requiring a running Redis instance in the test environment. Run these integration tests in your CI pipeline on every push to catch regressions in the screenshot endpoint behavior before they reach production.

Express.js Screenshot Service Deployment on AWS Lambda

Express.js screenshot services can be deployed as serverless functions on AWS Lambda using the serverless-http adapter, which wraps your Express app as a Lambda handler without requiring modifications to the Express code itself. This deployment model eliminates server management entirely and scales automatically to handle traffic spikes without pre-provisioning capacity. Configure the Lambda function with a timeout of at least thirty seconds to accommodate slow-rendering pages, and set the memory allocation to 512 megabytes or higher to ensure adequate memory for the axios HTTP client and response buffer handling. Use API Gateway as the HTTP trigger with proxy integration to route all requests to the Lambda function. Store the SNAPAPI_KEY as an encrypted AWS Systems Manager Parameter Store value and retrieve it at function startup using the AWS SDK, ensuring the key is not embedded in the deployment artifact. For screenshot services with consistent moderate traffic, a traditional EC2 or container-based deployment is more cost-efficient than Lambda due to Lambda's per-request pricing at sustained load.