How to Use the Cloudinary Website Screenshot API in React
Capture public webpages with Cloudinary URL2PNG in a React app. Generate signed URLs on your server, then display the resulting screenshots safely.
To use Cloudinary’s website screenshot API in React, enable its URL2PNG add-on, generate a signed screenshot delivery URL on your server, and return that URL to the React app. React then displays the image with a normal <img> element. Keep Cloudinary credentials on the server; do not put an API secret in a client-side bundle. URL2PNG captures public webpages, while Cloudinary’s React SDK is for rendering and transforming Cloudinary media, not a dedicated screenshot component. Cloudinary React SDK documentation · Cloudinary CLI documentation.
1. Understand the request flow
- Register for the URL2PNG Website Screenshots add-on in your Cloudinary account. Check the account console for current eligibility, quota, terms, and pricing.
- Your app accepts or selects a public webpage URL. Treat user-provided URLs as untrusted input.
- A trusted server endpoint builds and signs the URL2PNG delivery URL with server-held credentials.
- The server returns the resulting URL. React displays it as an image.
Cloudinary documents signed or eagerly generated URL2PNG requests as the default protection against unplanned dynamic requests. Account settings can change that behavior; unsigned transformations are a security choice, not a reason to expose credentials in React. See the URL2PNG add-on documentation and Cloudinary’s server-side URL2PNG example. The detailed add-on reference surfaced on a test documentation host, so confirm exact syntax against current production documentation and your account before deploying.
2. Enable the add-on and configure credentials
- Sign in to Cloudinary and register for URL2PNG Website Screenshots.
- From your Cloudinary account, obtain the cloud name, API key, and API secret required by your server-side integration.
- Store credentials in server environment variables or a secret manager. Never expose the API secret through a
VITE_,NEXT_PUBLIC_, or other browser-exposed environment variable. - Confirm add-on access, quota, and account terms in the Cloudinary console; this guide does not assume an account-specific price or quota.
3. Build a signed URL on the server
The signing boundary belongs in a backend route, server action, or serverless function. The example below uses Node.js and the Cloudinary Node SDK pattern from the server-side implementation article. Install the SDK with npm install cloudinary. Set CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, and CLOUDINARY_API_SECRET on the server.
import express from 'express';
import { v2 as cloudinary } from 'cloudinary';
const app = express();
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
app.get('/api/screenshot-url', (req, res) => {
const target = req.query.url;
if (typeof target !== 'string') {
return res.status(400).json({ error: 'Provide one url query parameter.' });
}
let parsed;
try {
parsed = new URL(target);
} catch {
return res.status(400).json({ error: 'The url must be an absolute URL.' });
}
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
return res.status(400).json({ error: 'Only HTTP and HTTPS URLs are supported.' });
}
// Apply your destination allowlist or other URL policy here before signing.
const screenshotUrl = cloudinary.url(target, {
resource_type: 'image',
type: 'url2png',
sign_url: true,
});
return res.json({ screenshotUrl });
});
app.listen(3000);
URL2PNG examples use the url2png delivery type. Exact option names and signing behavior can depend on the SDK version and account configuration; validate the generated URL and signature with the current production documentation. The security invariant is stable: construct and sign on a trusted server, return only the signed URL.
Constrain destinations
Do not treat syntactic URL parsing as a complete SSRF defense. The research reviewed here does not establish a comprehensive threat model for URL2PNG inputs. If users can submit targets, use an explicit host allowlist when possible, reject localhost and private or internal destinations according to your server policy, and follow Cloudinary’s current security guidance. Avoid accepting arbitrary schemes or silently forwarding user-controlled request headers.
4. Request the screenshot from React
React calls your own backend endpoint, not Cloudinary with a secret. Here is a complete component that requests a screenshot URL and renders the image:
import { useState } from 'react';
export function Screenshot({ targetUrl }) {
const [screenshotUrl, setScreenshotUrl] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
async function capture() {
setLoading(true);
setError('');
setScreenshotUrl('');
try {
const response = await fetch(
`/api/screenshot-url?url=${encodeURIComponent(targetUrl)}`
);
const body = await response.json();
if (!response.ok) throw new Error(body.error || 'Screenshot request failed');
setScreenshotUrl(body.screenshotUrl);
} catch (err) {
setError(err instanceof Error ? err.message : 'Screenshot request failed');
} finally {
setLoading(false);
}
}
return (
<section>
<button type="button" onClick={capture} disabled={loading}>
{loading ? 'Preparing screenshot…' : 'Capture webpage'}
</button>
{error && <p role="alert">{error}</p>}
{screenshotUrl && (
<img
src={screenshotUrl}
alt={`Screenshot of ${targetUrl}`}
loading="lazy"
style={{ maxWidth: '100%', height: 'auto' }}
/>
)}
</section>
);
}
Pass a known or validated target URL to the component. In a real form, validate user input on the server as well as the client, show a useful error state, and avoid rendering a stale image after a new capture request fails.
5. Choose how to create and serve the screenshot
Signed dynamic URL
Generate the signed URL when a user chooses a target. This suits applications where the screenshot destination is selected at runtime. Protect the signing endpoint with your own authentication, rate limits, and destination policy as appropriate. A signed URL is a URL that can be requested by its holder, so avoid logging or sharing it more widely than intended.
Eager generation
If the target is known in advance, generate the screenshot through Cloudinary’s authenticated API workflow and serve the resulting asset URL. Cloudinary documents both eager generation and signed URL approaches. The reviewed sources do not establish which is faster or cheaper for a particular workload; choose based on when the destination is known and how your application manages generated assets.
Plain image versus the React SDK
Use <img src={screenshotUrl}> when the server returns a ready-to-display screenshot URL. Use @cloudinary/url-gen and @cloudinary/react when you want Cloudinary’s media URL construction, transformations, and AdvancedImage rendering. The SDK’s documented setup configures a Cloudinary instance with a cloud name and renders a Cloudinary image object; it is not required just to display an existing URL2PNG URL. See the React SDK guide.
6. Add image transformations carefully
Cloudinary’s URL2PNG materials describe viewport and user-agent options and transformations applied to the captured image. Use those only after confirming their current syntax in the production documentation and testing the signed URL. Common decisions include:
- Viewport: Select the page dimensions needed for the screenshot. The viewport affects responsive layout and therefore the content captured.
- User agent: A target may serve different markup to different user agents. Set one only when you need to reproduce a specific presentation.
- Image resizing or cropping: Apply post-capture transformations only if you want a different delivered image size or crop; preserve the original capture dimensions when the full page must remain legible.
- Signing: Any transformation or URL component covered by signing must be included in the signed URL exactly as expected by Cloudinary.
The cited research does not verify a complete list of current URL2PNG parameters or their defaults. Do not copy parameter spellings from old examples without checking the current add-on docs and your account.
7. Validate inputs and handle edge cases
- Private or authenticated pages: URL2PNG is documented for public webpages. A page behind a login may not be capturable as the signed-in user sees it.
- Redirects: Decide whether your app accepts redirecting targets. Validate the submitted URL and avoid assuming the final destination matches the initial host.
- Very long URLs: Query strings can make request URLs unwieldy. If this becomes a problem, send the target to your backend in a POST body, then have the backend construct the Cloudinary request.
- Repeated targets: Consider reusing a stored result or controlling repeated generation when your workflow permits. The reviewed evidence does not specify cache behavior or savings for URL2PNG.
- Slow or unavailable pages: Treat capture failure as an expected application state. Offer retry or a clear message rather than leaving an indefinite spinner.
- Responsive pages: The chosen viewport can change the page layout, lazy content, and what is visible. Use dimensions appropriate to the result you intend to show.
8. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| Cloudinary rejects the request or returns an error | The add-on is not registered, the account is not eligible, or the generated URL/options are invalid. | Confirm URL2PNG activation in the console and compare the URL syntax with current production docs. |
| Signature is invalid | The URL was modified after signing, the wrong credentials were used, or the SDK’s URL construction differs from the expected URL2PNG format. | Generate and sign in one server-side step; do not edit the signed path or query in React. Verify the current signing example and SDK version. |
| Screenshot URL exposes credentials | A secret or signing code was placed in client code. | Remove secrets from browser-exposed configuration, rotate any exposed secret, and move signing to the server. |
| Image does not render in React | The endpoint response is an error, the URL is malformed, or the image request is blocked. | Inspect the backend JSON response and browser network panel; open the returned URL directly to inspect its response. |
| Capture shows the wrong layout | Viewport or user-agent settings differ from the intended display. | Set the documented capture options for the target layout and check the target page’s responsive behavior. |
| Capture omits content | The content may load late, require authentication, or depend on client-side behavior. | Confirm the page is public and review the current add-on’s supported wait or rendering options before relying on them. |
| Unexpected usage or cost | Repeated dynamic requests, retries, or unplanned access may generate requests. | Keep the documented signing/eager-generation protections enabled as appropriate, rate-limit your endpoint, and review account usage and terms. |
9. Performance, reliability, and cost
Screenshot generation depends on fetching and rendering a third-party page, so target-page latency and availability affect the user experience. The research provides no workload-specific latency, reliability, or cost benchmark; measure your own targets and avoid promising a fixed response time.
- Keep captures off the critical render path: Trigger them on demand or prepare known screenshots ahead of display when that fits the workflow.
- Use bounded retries: Retry transient failures sparingly and avoid retry loops that can multiply requests.
- Reuse where appropriate: If screenshots are stable, save and serve a generated result according to your application’s freshness needs. Confirm Cloudinary’s current storage and delivery terms.
- Protect the endpoint: Apply application-level authorization, rate limits, and target restrictions so an open endpoint cannot be used to request arbitrary captures.
- Check account terms: URL2PNG is an add-on. Verify current plan, quota, eligibility, pricing, and terms in your Cloudinary console; no generally applicable price was verified for this guide.
Or skip the browser setup
ScreenshotNeo provides a screenshot API and MCP server. One GET request returns a screenshot; use it from your backend and keep the API key private. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Learn about ScreenshotNeo, then sign up for 1,000 free screenshots a month with no card.
FAQ
Does Cloudinary provide a React screenshot component?
The reviewed React SDK documentation describes Cloudinary media rendering with AdvancedImage; URL2PNG performs the webpage capture. A normal image element can display the returned screenshot URL.
Can I call URL2PNG directly from the browser?
Build and sign the URL on the server so your API secret stays private. The browser can request your backend endpoint and display its returned URL.
Can URL2PNG capture a page that requires my user’s login?
The sources describe capture of public webpages and do not establish authenticated-page capture behavior. Do not assume a private page will render as the user sees it.
Where can I find current URL2PNG pricing and quota?
Check your Cloudinary console for account-specific plans, eligibility, quota, and terms; the reviewed sources do not establish universally applicable figures.


