Screenshot API Deno Guide 2026

Integrate SnapAPI into Deno and Deno Deploy applications using native fetch, Deno KV caching, Oak middleware, and Fresh framework server handlers.

Get Your Free API Key

Why Deno Is a Strong Choice for Screenshot Services

Deno's security model, built-in TypeScript support, and native Web API compatibility make it an excellent runtime for building screenshot services. Unlike Node.js, Deno requires explicit permission flags to access the network, file system, and environment variables — which means your screenshot service has a clearly defined and auditable security surface. The native fetch() API in Deno works identically to the browser fetch() API, making SnapAPI integration straightforward and portable. And Deno Deploy's global edge network means your screenshot service responds with minimal latency from any geographic region.

This guide covers native Deno integration with the fetch() API, Deno KV for distributed caching, Oak middleware framework for HTTP services, and the Fresh web framework for full-stack Deno applications.

Basic Deno Integration with Native fetch()

Deno's built-in fetch() makes SnapAPI calls trivial. Create a screenshot module:

// screenshot.ts
const SNAPAPI_KEY = Deno.env.get("SNAPAPI_KEY")!
const SNAPAPI_BASE = "https://api.snapapi.pics/v1"

export interface ScreenshotOptions {
  url: string
  width?: number
  height?: number
  format?: "png" | "jpeg" | "pdf"
  fullPage?: boolean
  delay?: number
}

export interface ScreenshotResult {
  url: string
  width: number
  height: number
  format: string
  timestamp: string
  size: number
}

export async function screenshot(opts: ScreenshotOptions): Promise {
  const res = await fetch(`${SNAPAPI_BASE}/screenshot`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": SNAPAPI_KEY,
    },
    body: JSON.stringify({
      url: opts.url,
      width: opts.width ?? 1280,
      height: opts.height ?? 800,
      format: opts.format ?? "png",
      full_page: opts.fullPage ?? false,
      delay: opts.delay,
    }),
  })
  if (!res.ok) {
    const err = await res.json()
    throw new Error(`SnapAPI error ${res.status}: ${err.message}`)
  }
  return res.json()
}

Deno KV Caching for Screenshot Results

Deno KV is a globally replicated key-value store built into Deno Deploy. Use it to cache screenshot results and avoid redundant API calls:

// screenshot_cached.ts
import { screenshot, type ScreenshotOptions } from "./screenshot.ts"

const kv = await Deno.openKv()
const TTL_MS = 60 * 60 * 1000 // 1 hour

export async function cachedScreenshot(opts: ScreenshotOptions) {
  const key = ["screenshot", JSON.stringify(opts)]
  const cached = await kv.get(key)
  if (cached.value) return cached.value

  const result = await screenshot(opts)
  await kv.set(key, result, { expireIn: TTL_MS })
  return result
}

Oak Middleware Screenshot Service

Oak is the most popular HTTP middleware framework for Deno. Build a full screenshot service endpoint:

// server.ts
import { Application, Router } from "https://deno.land/x/oak/mod.ts"
import { cachedScreenshot } from "./screenshot_cached.ts"

const router = new Router()

router.post("/screenshot", async (ctx) => {
  const body = await ctx.request.body({ type: "json" }).value
  if (!body.url) {
    ctx.response.status = 400
    ctx.response.body = { error: "url is required" }
    return
  }
  try {
    const result = await cachedScreenshot(body)
    ctx.response.body = result
  } catch (e) {
    ctx.response.status = 500
    ctx.response.body = { error: e.message }
  }
})

const app = new Application()
app.use(router.routes())
app.use(router.allowedMethods())

await app.listen({ port: 8000 })

Fresh Framework Integration

Fresh is Deno's island-architecture web framework for building full-stack applications. Add screenshot capability via a Fresh API route:

// routes/api/screenshot.ts
import { Handlers } from "$fresh/server.ts"
import { screenshot } from "../../screenshot.ts"

export const handler: Handlers = {
  async POST(req) {
    const body = await req.json()
    try {
      const result = await screenshot(body)
      return Response.json(result)
    } catch (e) {
      return Response.json({ error: e.message }, { status: 500 })
    }
  }
}

Deploying to Deno Deploy

Deploy your Deno screenshot service to Deno Deploy with a single command: deployctl deploy --project=my-screenshot-service server.ts. Set the SNAPAPI_KEY environment variable in the Deno Deploy project settings dashboard. Your screenshot service is instantly available globally across Deno Deploy's edge network, with requests automatically routed to the nearest edge location. Deno Deploy's free tier handles sufficient traffic for development and testing. For production workloads, Deno Deploy's Pro plan removes rate limits. Pair it with SnapAPI's $19/month plan for 5,000 captures, and you have a globally distributed screenshot service for under $25/month total. Sign up at snapapi.pics to get started.

Deno Permissions Model and API Key Security

One of Deno's strongest security features is the explicit permissions model. When running your screenshot service locally, you must explicitly grant network access to the SnapAPI endpoint and environment variable access for your API key:

deno run   --allow-net=api.snapapi.pics   --allow-env=SNAPAPI_KEY   server.ts

This explicit permission grant means your screenshot service cannot accidentally access other network resources or environment variables beyond what is specified. In production on Deno Deploy, permissions are managed automatically and the isolation model prevents any server-side request forgery from your screenshot endpoint affecting other internal services. This security model is particularly valuable for screenshot services that accept user-provided URLs — the Deno runtime itself limits the network surface your code can access.

Streaming PDF Responses in Deno

For PDF generation endpoints where you want to stream the PDF binary directly to the client without buffering the entire file in memory, use Deno's streaming response capabilities:

// routes/api/pdf.ts (Fresh route)
import { Handlers } from "$fresh/server.ts"

export const handler: Handlers = {
  async POST(req) {
    const { url } = await req.json()
    const upstream = await fetch("https://api.snapapi.pics/v1/screenshot", {
      method: "POST",
      headers: {
        "X-API-Key": Deno.env.get("SNAPAPI_KEY")!,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ url, format: "pdf", full_page: true }),
    })
    return new Response(upstream.body, {
      headers: {
        "Content-Type": "application/pdf",
        "Content-Disposition": "attachment; filename=screenshot.pdf",
      },
    })
  }
}

Scheduled Screenshot Tasks with Deno Cron

Deno Deploy supports scheduled tasks via Deno.cron(), which allows you to run screenshot capture jobs on a defined schedule without external task schedulers:

// scheduled.ts
import { screenshot } from "./screenshot.ts"

// Capture dashboard screenshots every day at 8am UTC
Deno.cron("daily-dashboard-capture", "0 8 * * *", async () => {
  const dashboards = [
    "https://analytics.yourapp.com/dashboard/weekly",
    "https://analytics.yourapp.com/dashboard/revenue",
    "https://analytics.yourapp.com/dashboard/users",
  ]
  for (const url of dashboards) {
    try {
      const result = await screenshot({ url, width: 1440, height: 900, format: "png" })
      await storeToS3(result.url, new Date().toISOString().split("T")[0])
      console.log("Captured:", url, "->", result.url)
    } catch (e) {
      console.error("Failed:", url, e.message)
    }
  }
})

Testing Deno Screenshot Services

Deno's built-in test runner makes it straightforward to unit test your screenshot integration. Mock the fetch calls to avoid consuming API quota during development:

// screenshot_test.ts
import { assertEquals } from "https://deno.land/std/assert/mod.ts"
import { screenshot } from "./screenshot.ts"

const originalFetch = globalThis.fetch

Deno.test("screenshot returns image URL", async () => {
  globalThis.fetch = () => Promise.resolve(
    new Response(JSON.stringify({ url: "https://cdn.example.com/test.png" }), {
      status: 200, headers: { "Content-Type": "application/json" }
    })
  ) as any

  const result = await screenshot({ url: "https://example.com" })
  assertEquals(result.url, "https://cdn.example.com/test.png")
  globalThis.fetch = originalFetch
})

Run tests with deno test --allow-env=SNAPAPI_KEY screenshot_test.ts. Deno's test runner outputs clear pass/fail results with timing information, making it easy to identify slow screenshot integration tests and optimize them with proper mocking. Get your free API key at snapapi.pics and start building your Deno screenshot service today.

Integration Architecture and Technical Best Practices

The most effective SnapAPI integrations follow a few core architectural patterns that maximize reliability, minimize cost, and keep API quota usage efficient. First, always proxy SnapAPI calls through a server-side endpoint rather than calling the API directly from client-side code. This keeps your API key out of the browser bundle, allows you to add rate limiting and authentication at the proxy layer, and gives you a single point to add caching logic. Second, implement a cache layer — Redis, Memcached, or a CDN edge cache — keyed on a hash of the screenshot parameters. Cache TTL of one hour is appropriate for most use cases; shorter for rapidly changing pages, longer for static or slowly changing content. Third, implement exponential backoff retry logic for transient failures. SnapAPI's official SDK libraries include this by default; if you are using raw fetch() calls, add a retry wrapper that backs off on 429 and 503 responses. Fourth, store screenshot URLs rather than image bytes in your database. SnapAPI returns CDN-hosted URLs that serve images with proper cache headers — storing the URL and referencing it directly is more efficient than downloading and re-hosting the image. Fifth, monitor your quota consumption through the SnapAPI dashboard and set up alerts before you approach your monthly limit. Unexpected spikes in screenshot generation often indicate a bug in your automation logic — a loop that runs more iterations than intended, or a webhook that fires more frequently than expected. With these patterns in place, your SnapAPI integration will be production-ready, cost-efficient, and maintainable across your team. Sign up at snapapi.pics to get started with 200 free captures per month — no credit card required.