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.