React Screenshot API Integration

Add website screenshots and thumbnail generation to your React app with ScreenshotAPI. Works with Vite, CRA, Remix, and any React setup.

Last updated: 2026-08-29

Try ScreenshotAPI free

200 free screenshots/month. No credit card required.

Start for free

Capture Website Screenshots in React with ScreenshotAPI

Displaying website thumbnails, link previews, and screenshot galleries in a React application is a common requirement for dashboards, CMS tools, and portfolio builders. Most solutions involve self-hosting Puppeteer, which brings significant complexity: large Docker images, memory-hungry processes, and browser crash recovery.

A React screenshot API integration with ScreenshotAPI removes that burden entirely. Your React frontend communicates with a lightweight backend proxy, which calls ScreenshotAPI to capture any URL as a PNG, JPEG, or WebP image.

Quick Start

  1. Create a free account to get your API key. 200 free screenshots per month are included to start.
  2. Set up a backend proxy (Express, Fastify, or any server) to keep your API key secret.
  3. Fetch screenshots from your React components via the proxy.

Installation

Install the official JavaScript SDK in your backend project:

bash
npm install screenshotapi-to

The package is screenshotapi-to — it is typed, has zero runtime dependencies, and works anywhere native fetch exists (Node 18+, Bun, Deno, Vercel Functions, Cloudflare Workers). See the JavaScript SDK reference for every option.

You do not need the SDK on the client side. The React frontend only talks to your proxy endpoint.

Backend Proxy Setup

Never expose your API key in client-side code. Create a simple proxy server instead:

typescript
// server/screenshot.ts import express from 'express' import { ScreenshotAPI, ScreenshotAPIError } from 'screenshotapi-to' const router = express.Router() const client = new ScreenshotAPI({ apiKey: process.env.SCREENSHOTAPI_KEY! }) router.get('/api/screenshot', async (req, res) => { const { url, width = '1280', height = '800', type = 'webp' } = req.query if (!url || typeof url !== 'string') { return res.status(400).json({ error: 'url parameter is required' }) } try { const shot = await client.screenshot({ url, width: Number(width), height: Number(height), type: type as 'png' | 'jpeg' | 'webp' }) res.set('Content-Type', shot.contentType) res.set('Cache-Control', 'public, max-age=86400') res.send(Buffer.from(shot.image)) } catch (error) { if (error instanceof ScreenshotAPIError) { return res .status(error.status || 502) .json({ error: error.message, code: error.code }) } res.status(500).json({ error: 'Internal server error' }) } }) export default router

screenshot() returns { image, contentType, metadata }, where metadata carries creditsRemaining, screenshotId, and durationMs — so you can log usage per request without a second call. The SDK throws typed errors (InvalidAPIKeyError, InsufficientCreditsError, ScreenshotFailedError, ScreenshotTimeoutError), each carrying status and code.

Basic React Example

With the proxy in place, displaying a screenshot in React is straightforward:

tsx
function WebsiteThumbnail({ url }: { url: string }) { const screenshotUrl = `/api/screenshot?url=${encodeURIComponent(url)}&width=1280&height=800&type=webp` return ( <div className="overflow-hidden rounded-lg border"> <img src={screenshotUrl} alt={`Screenshot of ${url}`} loading="lazy" className="h-auto w-full" /> </div> ) }

React Screenshot Component with Loading States

A production-ready React website thumbnail component should handle loading, error, and success states:

tsx
import { useState, useCallback } from 'react' interface ScreenshotProps { url: string width?: number height?: number className?: string } function Screenshot({ url, width = 1280, height = 800, className }: ScreenshotProps) { const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading') const screenshotSrc = `/api/screenshot?url=${encodeURIComponent(url)}&width=${width}&height=${height}&type=webp` const handleLoad = useCallback(() => setStatus('ready'), []) const handleError = useCallback(() => setStatus('error'), []) return ( <div className={`relative overflow-hidden rounded-lg border ${className ?? ''}`}> {status === 'loading' && ( <div className="flex h-48 items-center justify-center bg-muted"> <div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" /> </div> )} {status === 'error' && ( <div className="flex h-48 items-center justify-center bg-muted"> <span className="text-sm text-muted-foreground">Failed to load preview</span> </div> )} <img src={screenshotSrc} alt={`Preview of ${url}`} onLoad={handleLoad} onError={handleError} className={status === 'ready' ? 'block h-auto w-full' : 'hidden'} /> </div> ) }

Using TanStack Query for Screenshots

For applications that already use TanStack Query, fetching screenshots as blobs gives you fine-grained control over caching and refetching:

tsx
import { useQuery } from '@tanstack/react-query' function useScreenshot(url: string) { return useQuery({ queryKey: ['screenshot', url], queryFn: async () => { const params = new URLSearchParams({ url, width: '1280', height: '800', type: 'webp', }) const res = await fetch(`/api/screenshot?${params}`) if (!res.ok) throw new Error('Screenshot failed') const blob = await res.blob() return URL.createObjectURL(blob) }, staleTime: 1000 * 60 * 60, retry: 2, }) } function SiteThumbnail({ url }: { url: string }) { const { data: imageUrl, isLoading, isError } = useScreenshot(url) if (isLoading) return <div className="h-48 animate-pulse rounded-lg bg-muted" /> if (isError) return <div className="h-48 rounded-lg bg-muted" /> return ( <img src={imageUrl} alt={`Preview of ${url}`} className="h-auto w-full rounded-lg" /> ) }

Remember to revoke object URLs when components unmount to avoid memory leaks. See the TanStack Query documentation for advanced caching patterns.

Screenshot Gallery Component

Building a gallery of website previews is a common pattern for portfolio sites and link aggregators:

tsx
interface Site { name: string url: string } function ScreenshotGallery({ sites }: { sites: Site[] }) { return ( <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3"> {sites.map((site) => ( <a key={site.url} href={site.url} target="_blank" rel="noopener noreferrer" className="group cursor-pointer overflow-hidden rounded-xl border transition-shadow hover:shadow-lg" > <Screenshot url={site.url} width={1440} height={900} /> <div className="p-4"> <h3 className="font-semibold group-hover:text-primary">{site.name}</h3> <p className="mt-1 text-sm text-muted-foreground">{site.url}</p> </div> </a> ))} </div> ) }

Dark Mode and Light Mode Captures

ScreenshotAPI's colorScheme parameter lets you capture both themes without modifying the target site:

tsx
function ThemeComparison({ url }: { url: string }) { return ( <div className="grid gap-4 md:grid-cols-2"> <div> <h3 className="mb-2 font-medium">Light Mode</h3> <img src={`/api/screenshot?url=${encodeURIComponent(url)}&colorScheme=light`} alt="Light mode preview" className="rounded-lg border" /> </div> <div> <h3 className="mb-2 font-medium">Dark Mode</h3> <img src={`/api/screenshot?url=${encodeURIComponent(url)}&colorScheme=dark`} alt="Dark mode preview" className="rounded-lg border" /> </div> </div> ) }

Production Tips

Protect Your API Key

Your SCREENSHOTAPI_KEY must stay on the server. Never import it in client-side bundles. The proxy pattern shown above keeps the key safe while exposing a clean /api/screenshot interface to your React app.

Caching Best Practices

  1. HTTP caching: Return Cache-Control headers from your proxy so the browser and CDN cache responses.
  2. TanStack Query caching: Set staleTime to avoid refetching screenshots that haven't changed.
  3. Persistent storage: For thumbnails that rarely change, save the image to S3 or R2 and serve the stored copy.

Rate Limiting User Input

If users can enter arbitrary URLs, add server-side validation and rate limiting. Reject private IPs, limit requests per user, and sanitize input to prevent SSRF attacks.

Image Optimization

Use the webp format and the quality parameter to minimize bandwidth:

/api/screenshot?url=https://example.com&type=webp&quality=80

WebP images are typically 25-35% smaller than PNG at comparable visual quality.

Get 200 free screenshots per month. No credit card required. Sign up free →

Further Reading

Frequently asked questions

Can I call ScreenshotAPI directly from a React component?

You should proxy requests through your backend to protect your API key. Expose a server endpoint that calls ScreenshotAPI, then fetch from that endpoint in your React component.

How do I display a website thumbnail in React?

Point an img tag at your backend proxy endpoint, or fetch the screenshot as a blob and create an object URL. Both approaches work with lazy loading and responsive images.

Does ScreenshotAPI work with Vite and Create React App?

Yes. Vite and CRA only ever talk to your own proxy endpoint, so the build tool is irrelevant. The official screenshotapi-to package installs in the backend project and runs on any Node 18+, Bun, or Deno server.

How do I handle loading states while a screenshot is being captured?

Use React state or TanStack Query's isLoading flag to show a skeleton or spinner while the screenshot request is in flight. A capture is a real page load on our side, so treat it as an async request rather than an instant one; the SDK returns durationMs in the response metadata if you want to measure your own timings.

Related resources

Start capturing screenshots today

Create a free account and get 200 free screenshots per month to try the API. No credit card required.

React screenshot library or a screenshot API? Pick by what you are capturing

Searches for a React screenshot cover two different jobs. Client-side hooks such as use-react-screenshot, which declares html2canvas as a peer dependency, capture a DOM node your own app has already rendered in the visitor's browser. ScreenshotAPI renders a URL, or raw HTML you POST, in a real browser on our infrastructure and returns the finished image file. The deciding question is whether the pixels you want already exist inside your own React tree.

What you needBetter fitWhy
An image of a component your app already renders, such as an invoice or a chartClient-side captureThe markup is already in the DOM, so nothing has to be fetched and the capture costs no API call
A thumbnail of a website your app does not renderScreenshotAPIhtml2canvas builds its image from the DOM of the page it is loaded on, so a third-party URL is out of reach
Output that matches what a visitor seesScreenshotAPIhtml2canvas states it does not take an actual screenshot, and renders only the CSS properties it understands
Images loaded from another origin inside the captureScreenshotAPIhtml2canvas needs those images to be same-origin or proxied, otherwise the canvas is tainted and unreadable
A PDF rather than an imageScreenshotAPItype=pdf is a documented output format; a canvas capture returns an image, so a PDF needs an extra library
Capture work kept off the visitor's deviceScreenshotAPIRendering runs server-side, so a slow phone does not decide how long the capture takes

Can use-react-screenshot capture a different website?

No. use-react-screenshot is a React hook that declares html2canvas as a peer dependency, and html2canvas documents that it does not take an actual screenshot: it builds a representation of the page from the properties it reads from the DOM of the page it is loaded on. That limits it to markup your own app has rendered. Capturing a URL you do not control needs the page loaded somewhere else, which is what a server-side screenshot API does - GET /api/v1/screenshot?url=... returns the image for any public URL.

Should I use html2canvas or a screenshot API in my React app?

Use html2canvas when the pixels are already on screen inside your own app, such as exporting a chart or an invoice the user is looking at. Use a screenshot API when the target is a URL: link previews, directory thumbnails, competitor snapshots, or any page your visitor's browser cannot read across origins. Plenty of React apps use both, for different features.

Does use-react-screenshot support React 19?

The published package, version 4.0.0 from January 2024, declares peer dependencies on react ^18.2.0 and html2canvas ^1.3.3, so a React 19 project falls outside its declared support range. ScreenshotAPI is called over HTTP from your own backend, so it carries no React version constraint at all - your components only fetch an image URL from your proxy.

Every parameter used on this page is documented in the screenshot API reference. The free tier includes 200 renders a month with no credit card.