How to Fix Stale Content in a Screenshot API Capture of an Indian Web Page
A screenshot can be stale because of the capture cache, the site or CDN response, or page-render timing. Identify the layer before changing settings.
If a screenshot API shows old content on an Indian web page, first determine which layer is stale: the screenshot service’s own cached result, the HTML or assets served by the website or its CDN, or a capture taken before client-side updates finished. India is not, by itself, an explanation. Compare the same URL and capture settings, inspect response metadata when available, then change one variable at a time.
This guide uses Cloudflare Browser Rendering as a documented example. Its settings are specific to that API; another provider may use different parameters or expose less metadata. See the Cloudflare snapshot API reference and Cloudflare cache behavior documentation.
1. Identify what “old” means
Before changing cache settings, write down the exact expected content and where it should appear. Then record the requested URL, capture time, screenshot API settings, and the result. “Old” might mean the wrong page after a redirect, stale HTML, an outdated API response rendered by JavaScript, or a previous screenshot returned from a capture cache. Those cases need different fixes.
| Observation | Likely layer to investigate | Next check |
|---|---|---|
| The API returns the same old image while the page itself is current | Screenshot service cache or cache key | Disable or shorten the provider’s capture cache; vary one documented request input if needed |
| The rendered page and a direct page response both contain old content | Website, origin, or CDN | Inspect response headers and site cache rules; compare an uncached/control fetch where available |
| The HTML is current but the screenshot shows an earlier state | Browser rendering timing or client-side data | Wait for a meaningful selector or page event |
| Only an India-based or language-specific capture differs | Possibly redirect, cookie, localization, geolocation, or CDN routing | Compare final URL, redirects, headers, cookies, and region/language inputs with a control capture |
This is a troubleshooting framework, not a claim about how often any cause occurs. Do not attribute the problem to India unless a controlled regional comparison reproduces it.
2. Capture evidence before editing settings
For each run, retain the full request and response metadata your provider returns. Useful fields include:
- HTTP status and success/error details: distinguishes a page response from an API or navigation failure.
- Final URL and redirect chain: shows whether the browser reached a language, mobile, login, or regional destination.
- Origin response headers: inspect cache-related headers such as
Cache-Controland any CDN-specific cache status fields the site exposes. - Capture options: cache TTL, wait condition, cookies, headers, user agent, viewport, and geolocation if supported.
- Capture timestamp and content marker: compare a visible revision number, article date, or known text rather than relying only on visual impression.
Cloudflare’s snapshot API can return a final URL, origin response headers, redirect chain, status, and title. Other screenshot APIs may not return these fields. An empty redirect chain is not proof that no client-side redirect occurred: Cloudflare documents that its chain covers HTTP redirects and omits client-side redirects such as meta refresh.
3. Rule out the screenshot service cache
Check the exact endpoint’s current documentation for its cache control and cache key. Do not assume that changing image format, viewport, or a query parameter bypasses caching unless the provider says that input participates in the key.
For Cloudflare Browser Rendering’s /snapshot endpoint, cacheTTL defaults to 5 seconds; the documented range is 0–86400 seconds, and 0 disables that cache. This is specific to that endpoint. Other Cloudflare Browser Rendering endpoints and other vendors may differ.
Cloudflare snapshot example with its capture cache disabled
Replace the environment variables with your Cloudflare account ID and API token. This request asks for the page snapshot and sets the documented query parameter cacheTTL=0. The response is JSON and includes metadata and a base64 screenshot when successful.
export ACCOUNT_ID="YOUR_ACCOUNT_ID"
export CLOUDFLARE_API_TOKEN="YOUR_API_TOKEN"
export PAGE_URL="https://example.in/"
curl --fail-with-body --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/browser-rendering/snapshot?cacheTTL=0" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{\"url\":\"${PAGE_URL}\"}" \
-o snapshot.json
Inspect snapshot.json for success, errors, and meta fields such as status, finalUrl, headers, and redirectChain. Avoid putting secrets directly in source control or logs. For URLs containing special characters, use a JSON library rather than interpolating raw strings into JSON.
Python request example
import json
import os
import requests
account_id = os.environ["ACCOUNT_ID"]
token = os.environ["CLOUDFLARE_API_TOKEN"]
page_url = os.environ.get("PAGE_URL", "https://example.in/")
endpoint = (
"https://api.cloudflare.com/client/v4/accounts/"
f"{account_id}/browser-rendering/snapshot"
)
response = requests.post(
endpoint,
params={"cacheTTL": 0},
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json={"url": page_url},
timeout=120,
)
response.raise_for_status()
data = response.json()
if not data.get("success"):
raise RuntimeError(json.dumps(data.get("errors", data), indent=2))
meta = data.get("meta", {})
print("status:", meta.get("status"))
print("final URL:", meta.get("finalUrl"))
print("headers:", meta.get("headers"))
print("redirect chain:", meta.get("redirectChain"))
This logs response evidence; it does not save or decode the screenshot. The snapshot response’s screenshot representation and response format should be handled according to the endpoint’s current API schema.
Node.js request example
const accountId = process.env.ACCOUNT_ID;
const token = process.env.CLOUDFLARE_API_TOKEN;
const pageUrl = process.env.PAGE_URL || 'https://example.in/';
if (!accountId || !token) throw new Error('Set ACCOUNT_ID and CLOUDFLARE_API_TOKEN');
const endpoint = new URL(
`https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-rendering/snapshot`
);
endpoint.searchParams.set('cacheTTL', '0');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url: pageUrl }),
signal: AbortSignal.timeout(120_000),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const data = await response.json();
if (!data.success) throw new Error(JSON.stringify(data.errors));
console.log({
status: data.meta?.status,
finalUrl: data.meta?.finalUrl,
headers: data.meta?.headers,
redirectChain: data.meta?.redirectChain,
});
4. Check whether the website or CDN serves old content
If a fresh browser navigation still receives old HTML or stale assets, the screenshot service cannot make the source current by changing the screenshot format or viewport. Compare the screenshot API’s origin response metadata with a direct control request from an environment that can reach the site. A direct command-line fetch is useful for checking headers, but it is not always equivalent to a browser: cookies, JavaScript, geography, and request headers can differ.
curl -sS -D response-headers.txt -o response-body.html \
-H 'Cache-Control: no-cache' \
'https://example.in/'
Cache-Control: no-cache is a request asking caches to revalidate where supported; it is not a guarantee that every intermediary will bypass its cache. A query-string cache buster can also change the URL and behavior, so use it only as a controlled diagnostic and only where the site permits it.
Check the site’s own cache configuration and the response headers from the origin/CDN. For Cloudflare-managed sites, cache rules can affect whether origin headers are respected or overridden; consult Cloudflare Cache Rules settings and default cache behavior. Do not apply Cloudflare defaults to another CDN or assume a site uses Cloudflare.
- If the old value is in the HTML response, inspect the application’s rendered HTML, origin cache, and CDN rule.
- If the HTML is current but an image, script, or stylesheet is old, inspect that asset’s URL and cache headers separately.
- If the page fetches data from an API after navigation, check that API response and its own caching policy.
- Only purge or change a cache you control. If the page belongs to a third party, provide the owner with the URL, timestamp, response evidence, and reproducible steps.
5. Wait for the content the page actually needs
Browser navigation completing does not always mean an application has finished replacing placeholder or cached-looking content. A client-side app can load its main document, then fetch data and update the DOM. Prefer a condition tied to the content becoming ready over an arbitrary sleep.
Cloudflare’s screenshot guide says its /screenshot endpoint processes HTML and JavaScript before capturing the rendered page. Its API documents navigation conditions including load, domcontentloaded, networkidle0, and networkidle2, as well as selector and timeout options. The appropriate condition depends on the page.
| Wait condition | Use when | Tradeoff |
|---|---|---|
domcontentloaded |
You need the document parsed and the application can become ready quickly | May capture before images, data requests, or later rendering complete |
load |
Resources needed for the page’s load event matter | Some client-side updates may still happen afterward |
networkidle0 / networkidle2 |
The page settles after network activity | Long polling, analytics, or streaming may prevent or delay idleness |
| Selector wait | A known element appears only after the relevant update | The selector must uniquely represent the desired ready state |
| Fixed delay | A third-party page has no observable readiness signal and a bounded delay is the only available fallback | Can waste time or remain too short when response times vary |
For Cloudflare’s snapshot endpoint, a request body can use gotoOptions.waitUntil, waitForSelector, or waitForTimeout. Here is a selector-based example; choose a selector that represents the newly updated content on your own page:
curl --fail-with-body --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/browser-rendering/snapshot?cacheTTL=0" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{
"url": "https://example.in/",
"gotoOptions": { "waitUntil": "domcontentloaded" },
"waitForSelector": {
"selector": "[data-content-state=loaded]",
"visible": true,
"timeout": 15000
}
}' \
-o snapshot.json
The selector and state attribute above are illustrative placeholders, not known features of a particular site. Replace them with a real marker; if no such marker exists, use the best documented lifecycle condition and measure whether it captures the intended state.
6. Compare region, language, redirects, and cookies only when relevant
If the issue reproduces only for an India-based capture or one language, compare it against a control run while keeping cache and readiness settings constant. Check the final URL, each HTTP redirect, response headers, and relevant cookies. Then vary one context input at a time: language cookie or header, authentication cookie, user agent, timezone, or geolocation if the provider supports it.
A regional redirect, language preference, geo-dependent response, or different CDN route is a hypothesis to verify. The title alone does not establish any of them. Be careful with authenticated cookies and personal data: avoid sharing them in logs or screenshots, and do not pass credentials to a service unless you are authorized to do so.
7. Use a controlled recapture sequence
- Save a baseline. Record URL, timestamp, capture parameters, screenshot, status, final URL, headers, redirects, and visible content marker.
- Disable the screenshot service cache. Use that provider’s documented no-cache setting. For Cloudflare snapshot, test
cacheTTL=0. - Compare the page response. Check whether the API’s response metadata and an available control fetch contain the expected current content.
- Adjust readiness only if necessary. Use a selector or lifecycle event that corresponds to the update, not a guessed long delay.
- Investigate context only if the mismatch remains regional or language-specific. Compare final destination and inputs such as cookies or geolocation.
- Repeat and keep the winning settings. Change one axis per run so the result identifies the effective fix.
Compare four axes across captures: cache state, render readiness, destination, and context. This makes intermittent reports easier to reproduce and prevents a timing change from masking a CDN issue.
8. Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
| Cache TTL parameter is rejected or has no effect | Wrong endpoint, parameter placement, or provider-specific syntax | Verify the exact endpoint reference. Cloudflare snapshot documents cacheTTL as a query parameter; do not assume the same for another route or provider. |
| Capture stays old after disabling screenshot cache | The website/CDN or a client-side data endpoint still returns old content | Inspect origin response headers and page data requests; fix the cache at the layer you control. |
| Fresh HTML but old visible text | Capture happened before JavaScript replaced the old state | Wait for a meaningful selector or event; confirm that it denotes the updated content. |
| Selector wait times out | Selector is wrong, never appears, is hidden, or the page failed earlier | Check the live DOM and final URL; use the correct selector and a bounded timeout, then inspect navigation errors. |
networkidle never completes |
Persistent requests such as polling, streaming, or analytics keep the page active | Use a selector or another documented lifecycle condition instead of waiting indefinitely for network inactivity. |
| Final URL is unexpected | Redirect, language negotiation, login gate, or client-side navigation | Inspect the redirect chain and final URL; reproduce with the relevant cookies and request context. |
Direct curl response differs from screenshot |
Direct HTTP fetch does not run page JavaScript or match browser cookies and headers | Use the direct fetch for response-level evidence, then inspect the browser capture’s metadata and readiness behavior. |
| API returns an error or no screenshot | Authentication, permission, rate limit, malformed input, or action timeout | Check HTTP status and structured API errors, verify token permissions and JSON, then reduce the page’s work or adjust a documented timeout within its limit. |
| Only the India capture differs | Potential regional route, localization, cookie, or geolocation variation | Compare a control capture and vary one context input. Do not assume geography until the difference is reproducible. |
9. Performance, reliability, and cost
- Performance: Disable cache only while diagnosing or when fresh output is a requirement. It can remove a cache shortcut and require another browser render. Waiting for a selector can finish sooner than waiting for the entire network to become idle, when that selector genuinely marks readiness.
- Reliability: Record request parameters and response metadata. Use a bounded timeout, check status and structured errors, and retry transient failures with a limit and backoff rather than retrying indefinitely. A retry cannot fix a consistently stale origin response.
- Cost: Screenshot API pricing and billing behavior vary by provider. Check the provider’s plan and whether failed loads, cache hits, or retries are billed before scaling capture volume. Avoid repeated high-frequency polling when a targeted wait or suitable cache policy solves the problem.
- Correctness: For monitoring, capture a visible revision/date marker or compare extracted page content as well as the image. A visually similar screenshot alone may not reveal which response or content version was captured.
10. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a screenshot or PDF, and its parameters use names other screenshot APIs use to make switching easier. Its API documentation is at screenshotneo.com/docs.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.in/ \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.in/"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.in/',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use screenshot, page-info, and PDF tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
FAQ
Does an Indian website need a special screenshot cache setting?
No special setting follows from the country alone. Use the same layer-by-layer diagnosis; test regional inputs only if the mismatch is reproducible by region or language.
Should I always set cache TTL to zero?
No. It is useful as a diagnostic or for a freshness requirement, but caching can reduce repeated work. Choose the policy based on how current each capture must be and what your provider bills.
Will a cache-busting query string fix stale content?
Only if the relevant cache treats that URL as a different key and the source can provide current content. It may also change application behavior, so treat it as a controlled test rather than a universal fix.
What if I do not control the website’s CDN?
Send its owner a reproducible URL, capture time, expected and observed content, final URL, response status, relevant headers, and whether a cache-disabled capture changed the result.


