Using SnapAPI with Remix: Screenshot and PDF Generation in Full-Stack React Apps
April 2026 — 7 min read
Remix is a full-stack React framework that uses web platform primitives -- loaders, actions, and fetch -- to build fast, resilient web applications. Its server-side rendering model and nested routing architecture make it an excellent foundation for applications that need to generate screenshots and PDFs as part of their core functionality. In this tutorial, you will integrate SnapAPI into a Remix application to add screenshot and PDF generation to a resource route, protect it with server-side authentication, and stream the result back to the browser with minimal memory overhead.
Why Resource Routes for Screenshot Generation
Remix's resource routes are server-side route handlers that do not render any UI component. They export only a loader or action function and return a Response object directly. This makes them ideal for API-style endpoints within your Remix application. A screenshot generation endpoint fits naturally as a resource route: it receives a URL parameter, calls SnapAPI on the server side where your API key is secure, and streams the binary response back to the client. No client-side JavaScript is involved in the capture process, and the API key never appears in the browser.
Setting Up the Resource Route
Create a file at app/routes/api.screenshot.tsx. This filename maps to the URL /api/screenshot in your Remix application. Export a loader function that extracts the target URL from the request's query parameters, validates it using a URL constructor wrapped in a try-catch block, and rejects any URL that uses the file or data scheme. Then call SnapAPI using the native fetch API with your key stored in an environment variable. Remix's built-in environment variable support via the process.env object makes this straightforward in server-side route code.
Streaming the SnapAPI Response
Once the SnapAPI fetch call resolves, pipe the response body directly into the Response returned by your loader. Remix loaders can return any valid Response object, including one constructed from a ReadableStream. By passing the SnapAPI response body as the Response body, you avoid buffering the entire PNG or PDF in server memory before sending it to the client. Set the Content-Type header to match the SnapAPI response Content-Type, and add a Content-Disposition header if you want the browser to download the file rather than display it inline.
Authentication with Remix Sessions
Screenshot generation endpoints that call external APIs on behalf of users must be protected against unauthorized access. Remix's session management utilities make server-side session validation clean and composable. In your resource route loader, call your session validation utility before making the SnapAPI request. If the session is invalid or expired, return a 401 Response immediately. If the session is valid, proceed with the SnapAPI call. Because session validation happens entirely on the server within the loader function, there is no way for a client to bypass it by modifying JavaScript.
Triggering Screenshots from Remix Actions
For use cases where screenshot generation should be triggered by a form submission or a button click, Remix actions are the right tool. An action function in a Remix route handles POST requests to that route's URL. Your action can receive a URL submitted via a standard HTML form, validate and sanitize it, call SnapAPI, store the resulting image in cloud storage, and redirect the user to a success page with the screenshot URL as a query parameter. The entire flow uses standard web platform primitives -- HTML forms, HTTP redirects, and fetch -- with no custom client-side JavaScript required.
Caching with Remix and HTTP Headers
SnapAPI calls cost API credits and take one to five seconds to complete. Caching screenshot responses reduces both cost and latency for repeated requests. In Remix resource routes, set Cache-Control headers on the returned Response to instruct Cloudflare, CDN edge nodes, or the browser to cache the screenshot for an appropriate duration. For static marketing pages, a cache duration of one hour is conservative and effective. For dynamic dashboards, a shorter duration of sixty seconds prevents stale images while still reducing SnapAPI call volume during traffic spikes. Remix's deployment adapters for Cloudflare Workers and Vercel automatically propagate these cache headers to the appropriate CDN layer.