How to Automate Website Screenshots from Zoho Forms Submissions in India
Connect Zoho Forms submissions to a screenshot API, validate submitted URLs, and save or deliver the resulting image with a reliable workflow.
Direct answer: Zoho Forms does not document a built-in action that takes a screenshot of a website URL submitted in a form. You can assemble the workflow from documented integration pieces: a form field for the URL, a Zoho Forms outgoing webhook, and either Zoho Flow or a small server endpoint that calls a screenshot API and saves or delivers the returned image. Treat this as an integration pattern, not a prebuilt connector or a recipe verified end to end.
For an India deployment, also decide where screenshots and form data may be processed and stored. The integration documentation cited here does not establish data residency for Zoho or a screenshot provider. Zoho’s India OAuth callback is an OAuth setup detail; it does not prove India-only data storage.
1. Choose the workflow and decide what the form submits
Before configuring integrations, decide whether each submission contains a public URL, an authenticated URL, or a URL with sensitive query parameters. Then decide where the screenshot should go: object storage, a record attachment, email, or a controlled link. These decisions affect credentials, retention, access control, and whether a low-code flow can handle the image bytes.
| Approach | Good fit | Check before choosing |
|---|---|---|
| Zoho Forms → Zoho Flow → screenshot API | Low-code orchestration and mapping submission fields into later steps. | How the flow handles a binary response, file upload, retries, and execution limits. |
| Zoho Forms → your endpoint → screenshot API | Custom validation, storage, access control, and job processing. | Hosting, secrets, request authentication, queueing, and monitoring. |
| Zoho Forms → Deluge invokeUrl | A Zoho-side custom HTTP call where the work fits its execution limits. | Deluge’s documented 40-second socket timeout and service call limits; large or slow captures may need asynchronous processing. |
Zoho Forms can generate a PDF of the form submission, but that is different from capturing a screenshot of a separate website URL. Configure a URL field for the target page and validate it in your receiving workflow. URL validation and domain allowlisting are application design advice, not a feature established by the cited webhook documentation.
2. Configure a Zoho Forms outgoing webhook
- In Zoho Forms, open Developer & Automation → Integrations → Webhooks and configure a webhook.
- Set the destination URL to your receiving endpoint, or to the generated webhook URL from a Zoho Flow webhook trigger.
- Choose the request content type to match the receiver. Forms sends an HTTP POST and lets you configure authorization, URL parameters, headers, and the fields included in the payload.
- Include the submission identifier, submitted URL, and only the additional fields the next step needs. Avoid transmitting secrets or unnecessary personal data.
- Send a sample submission and inspect the actual request body before mapping fields or writing parsing logic.
Payload format matters: Zoho documents that application/json excludes file attachments; application/x-www-form-urlencoded excludes attachments and subform data; and multipart/form-data excludes subform data. Choose based on the fields your workflow needs, and verify the real payload rather than assuming the formats carry identical data. Zoho Forms webhook configuration.
3. Route the submission through Zoho Flow
- Create a flow and choose Webhook as its trigger.
- Select JSON, form data, or plain text to match the Forms webhook request. Flow generates a unique URL for the trigger.
- Configure the Forms webhook to POST to that URL. Send a sample submission so Flow can expose the received values for mapping.
- Map the submitted URL into an HTTP action or a custom function that calls the screenshot service.
- Choose a destination action for the resulting image or a link to it. Confirm that the selected action accepts the response as a file or can fetch an image from a controlled URL.
- Configure an acknowledgement if useful, and decide what happens when the screenshot or destination step fails.
Zoho Flow’s webhook trigger accepts JSON, form data, and plain text, and makes received data available to later steps. Its documentation does not establish that a particular Flow action can persist arbitrary screenshot response bytes. Verify binary/file handling with your chosen destination. Zoho Flow webhook trigger documentation.
4. Call a screenshot API from a server
A small endpoint gives you a clear place to validate URLs, keep the API key private, handle binary image data, and store the result. This runnable Node.js example accepts a JSON POST containing url, calls ScreenshotOne’s documented URL-based API, and saves the binary response locally. It is an integration example; deploy it behind authentication and adapt storage and request verification before using it with real submissions.
// Node.js 18+; install express with: npm install express
// Set SCREENSHOTONE_ACCESS_KEY in the server environment.
import express from 'express';
import { randomUUID } from 'node:crypto';
import { writeFile } from 'node:fs/promises';
const app = express();
app.use(express.json({ limit: '32kb' }));
const accessKey = process.env.SCREENSHOTONE_ACCESS_KEY;
if (!accessKey) throw new Error('Set SCREENSHOTONE_ACCESS_KEY');
function validateTarget(value) {
let parsed;
try { parsed = new URL(value); } catch { throw new Error('url must be an absolute URL'); }
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
throw new Error('Only http and https URLs are accepted');
}
// For production, allowlist approved hostnames and block private or local IP ranges.
return parsed.toString();
}
app.post('/zoho-form-screenshot', async (req, res) => {
try {
const target = validateTarget(req.body?.url);
const query = new URLSearchParams({ access_key: accessKey, url: target });
const shot = await fetch(`https://api.screenshotone.com/take?${query}`, {
signal: AbortSignal.timeout(90_000)
});
const contentType = shot.headers.get('content-type') || '';
if (!shot.ok || !contentType.startsWith('image/')) {
const detail = await shot.text();
return res.status(502).json({ error: 'Screenshot request failed', detail });
}
const bytes = Buffer.from(await shot.arrayBuffer());
const filename = `${randomUUID()}.png`;
await writeFile(`./screenshots/${filename}`, bytes, { flag: 'wx' });
return res.status(202).json({ status: 'saved', filename });
} catch (error) {
return res.status(400).json({ error: error.message });
}
});
app.listen(3000, () => console.log('Listening on port 3000'));
Create the screenshots directory and replace local disk storage with your approved durable storage before production use. Verify Zoho’s webhook authorization at the endpoint; do not assume that an unguessable URL alone provides sufficient authentication. The sample’s basic protocol check is not complete protection against server-side request forgery: enforce an approved hostname policy and reject localhost, private, link-local, and other internal network destinations. Recheck redirect destinations if your architecture permits arbitrary URLs.
Direct API examples for the screenshot step
These examples call ScreenshotOne’s documented endpoint. Keep the key in a server-side secret store or environment variable, never in a public form, browser script, or committed source file. By default, the API’s by-format response is binary; validate the response status and content type before saving it. ScreenshotOne getting started and API key guidance.
# cURL: save the binary response to a file
curl -G 'https://api.screenshotone.com/take' \
--data-urlencode 'access_key=YOUR_API_KEY' \
--data-urlencode 'url=https://example.com' \
-o screenshot.png
# Python 3; install requests with: python -m pip install requests
import os
import requests
response = requests.get(
'https://api.screenshotone.com/take',
params={'access_key': os.environ['SCREENSHOTONE_ACCESS_KEY'],
'url': 'https://example.com'},
timeout=(10, 90),
)
response.raise_for_status()
if not response.headers.get('content-type', '').startswith('image/'):
raise RuntimeError(f"Expected image, got {response.headers.get('content-type')}")
with open('screenshot.png', 'wb') as output:
output.write(response.content)
// Node.js 18+
const q = new URLSearchParams({
access_key: process.env.SCREENSHOTONE_ACCESS_KEY,
url: 'https://example.com'
});
const response = await fetch(`https://api.screenshotone.com/take?${q}`, {
signal: AbortSignal.timeout(90_000)
});
if (!response.ok) throw new Error(`Screenshot API returned ${response.status}`);
if (!(response.headers.get('content-type') || '').startsWith('image/')) {
throw new Error('Expected an image response');
}
const bytes = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', bytes));
ScreenshotOne documents URL capture over HTTPS, API-key authentication, binary responses by default, and options for formats and rendering. Check its current options documentation for the precise parameters you need. ScreenshotOne options.
5. Use Deluge when the capture fits its execution window
Deluge’s invokeUrl task can make HTTP requests to third-party APIs. A synchronous screenshot request is a poor fit if a page can take longer than the documented 40-second socket timeout or if the image exceeds the service’s download limits. Confirm the exact Deluge product’s limits and supported response/file handling before implementing; the limits cited here are from Zoho Creator’s invokeUrl documentation.
// Illustrative Deluge pattern; adapt response handling and connection setup
// to the Zoho service where this function runs.
response = invokeurl
[
url : "https://api.screenshotone.com/take?access_key=YOUR_API_KEY&url=https%3A%2F%2Fexample.com"
type : GET
];
info response;
Do not paste a real key into a shared script or log. Prefer an appropriately secured connection or secret mechanism supported by the Zoho service. For slow captures, have the form webhook enqueue a job and return promptly; a worker can render and store the image, then update the record or notify the destination. This queue-and-callback arrangement is architectural guidance, not a guaranteed Zoho feature. Deluge invokeUrl documentation.
6. Screenshot options and edge cases
- Output and rendering: Select the image format and any viewport or full-page behavior required by your use case. A screenshot API may return binary data or a URL depending on provider options; confirm which response the flow can pass to storage.
- Public versus authenticated pages: A URL alone cannot grant access to a private page. Use an approved authentication mechanism, such as scoped headers or cookies if supported, and avoid putting long-lived credentials in submitted URLs. Test access with least-privilege credentials.
- Redirects and tracking parameters: Decide whether to preserve query parameters and follow redirects. Submitted URLs may contain tokens or personal data; redact them from logs and avoid exposing them in public image links.
- Slow or dynamic pages: Pages may render late, require JavaScript, or load images lazily. Configure wait behavior in the screenshot provider if available and budget for the endpoint’s timeout. The exact supported options are provider-specific.
- Duplicate submissions: Use the Zoho submission ID as an idempotency key in your own job store. Before saving, check whether that submission already has a completed screenshot so webhook retries do not create duplicate files or notifications.
- Large pages and files: Set request and response size limits, and check the provider and destination’s file limits. Do not assume a low-code action can carry arbitrarily large binary responses.
- India and localization: If the target page varies by language, timezone, or geography, configure those rendering inputs only when needed and verify the resulting page. Do not infer data residency from an India OAuth callback or from the user’s location.
- Unsafe destinations: If form submitters can choose a URL, treat it as untrusted input. Allowlist domains where possible, block private network addresses and local hostnames, limit redirects, and set request timeouts to reduce SSRF and resource-exhaustion risk.
7. Reliability, performance, and cost
Capture time is dominated by the target site’s availability, network behavior, page weight, and render readiness. Full-page pages and late-loading assets can take longer and produce larger files. Set bounded timeouts, cap image size where supported, and avoid making the form submission wait for the entire render.
For a dependable pipeline, acknowledge or accept the webhook quickly, store a job with the submission ID, and process it with bounded retries. Retry transient network errors and provider throttling with backoff; do not retry malformed URLs or authentication failures indefinitely. Record a status such as queued, completed, or failed, plus a sanitized error code. Keep the original submission and screenshot retention period aligned with your business and security requirements.
Estimate screenshot cost from expected monthly submissions, retries, and any additional captures per submission. Also check Zoho plan quotas, Flow execution limits, Deluge call limits, storage charges, and the screenshot API’s current plan and billing rules. The dossier establishes no provider benchmark or comparative pricing for Zoho integrations, so confirm current limits and costs directly before choosing an architecture.
8. Troubleshooting
| Symptom | Likely cause | What to check or fix |
|---|---|---|
| No flow runs | Wrong webhook URL, disabled flow, or payload format mismatch. | Copy the active generated URL, match JSON/form/plain text, and send a fresh sample request. |
| URL field is empty | The selected Forms payload omits the field, or the receiver maps a different key. | Inspect the actual POST body and remap the exact field name. |
| Attachment or subform data is missing | The chosen content type excludes that data. | Check the documented format exclusions and select a compatible payload if available. |
| Screenshot API returns an error instead of an image | Invalid or missing key, malformed URL, unsupported option, or provider-side failure. | Check the HTTP status and JSON error body; verify the key server-side and test with a public URL. |
| Image is blank or shows a challenge | The page may be blocked, require authentication, render slowly, or show a bot check. | Confirm the URL is reachable, credentials are valid, and wait settings suit the page. Some sites intentionally block automated browsers. |
| Deluge socket timeout | The render takes longer than Deluge’s documented 40-second timeout. | Move work to an asynchronous endpoint or queue and update the record after completion. |
| File upload step rejects response | The action expects a file object or hosted URL rather than raw binary bytes. | Check the action’s accepted input types; upload from a custom endpoint or use a storage step that accepts binary data. |
| Duplicate images or messages | Webhook retries or repeated submissions are not idempotent. | Deduplicate by submission ID and make destination updates safe to repeat. |
| Requests target internal systems | Untrusted URLs or redirects bypass basic URL checks. | Enforce hostname and IP allowlists, validate every redirect, and block private and link-local ranges. |
9. Or skip the browser setup
If you prefer to send the submitted URL to a hosted screenshot API instead of maintaining browser-rendering infrastructure, ScreenshotNeo accepts a URL in one GET request and returns an image or PDF. Put this call in your secured endpoint or supported Flow HTTP step, and store the returned image using your chosen destination. Keep the API key server-side. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.
10. FAQ
Can Zoho Forms itself screenshot the submitted website?
The documented Forms feature relevant here sends submission data to a webhook. The documented generated PDF is a PDF of the form submission, not a capture of the separate URL. Assemble the screenshot step with a Flow, Deluge, or server-side integration.
Can I screenshot a page that requires a login?
Only if the rendering service can access it through an authorized method and you are permitted to capture it. Use scoped, short-lived credentials where possible, and avoid collecting passwords in a general-purpose form.
Does using Zoho’s India OAuth callback guarantee India data residency?
No. The callback URL is an OAuth configuration detail. Confirm data processing locations, retention, and contractual terms with each service involved.
Where should the image be stored?
Choose a destination based on access control, retention, audit, and attachment-size needs. Confirm that the integration step can store binary image data or upload a file; a screenshot API returning an image does not by itself establish a Zoho attachment workflow.


