To purge screenshot cache entries, call POST /v1/cache/purge with the exact keys you saved from X-Cache-Key, a url pattern such as https://example.com/blog/*, or a before timestamp. Then render again with cache.refresh: true if you still need the image. This guide explains what is cached, how each filter matches, the one rule about combining filters that surprises people, and a deploy hook that purges and re-renders changed pages. It is part of the guides; the endpoint reference is cache management.

Tested on October 15, 2026, with Node.js 22.18.0 and curl: the deploy hook and the purge-by-key flow against a local mock of the RenderScreenshot API; SDK purge calls in Node.js, Python, Ruby, PHP and Go against the same mock. Filter semantics described here were checked against the API source, not only the mock.

What is cached

Every successful render is stored and served from the CDN link in X-Cache-URL, with no authentication, until its TTL ends. The default TTL is 24 hours; cache.ttl accepts 3,600 seconds (1 hour) to 2,592,000 (30 days). The response also carries X-Cache-Key, the handle you use to purge that entry.

Separately, a request with cache.available: true asks the API to return an earlier identical render from your account instead of rendering again, for 0 credits. See caching.

So purging is about two things: links you want to stop working (X-Cache-URL), and earlier renders you no longer want reused.

Pick the right tool

Goal Use
A page changed and its card must update cache.refresh: true on the next request; purge only if the old image must disappear
Remove one known image keys in a purge, with the value from X-Cache-Key
Remove everything for a section of a site Purge with url: "https://example.com/blog/*"
Clean up old renders Purge with before
Stop social networks from showing an old card Change the image URL; purging cannot reach their copies

Requests

Keep the key when you render. It is in the X-Cache-Key header (or cache.key with Accept: application/json):

# 1. Render once and keep the cache key (store it next to the record that owns the image)
KEY=$(curl -s -D - -o card.png -X POST "$API/v1/screenshot" \
  -H "Authorization: Bearer $RS_API_KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/","preset":"og_card"}' \
  | awk -F': ' 'tolower($1)=="x-cache-key"{print $2}' | tr -d '\r')
echo "key: $KEY"

# 2. Later: remove that entry. The key goes in the JSON body, so slashes need no escaping.
curl -s -X POST "$API/v1/cache/purge" \
  -H "Authorization: Bearer $RS_API_KEY" -H "Content-Type: application/json" \
  -d "{\"keys\":[\"$KEY\"]}"; echo

Against the mock this printed the key, then {"purged":1}. Cache keys look like a storage path, with slashes and a file extension (for example screenshots/ab/cd/<hash>_<time>.png). Send them in the purge body as shown; that is the reliable way to remove one entry.

The cache management reference also lists DELETE /v1/cache/:key, which takes the key in the URL path. A key with slashes and a file extension does not travel well in a path, so for keys copied from X-Cache-Key, use the purge body.

Purge by URL pattern:

curl -X POST https://api.renderscreenshot.com/v1/cache/purge \
  -H "Authorization: Bearer $RS_API_KEY" -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/blog/*" }'

Purge by date:

curl -X POST https://api.renderscreenshot.com/v1/cache/purge \
  -H "Authorization: Bearer $RS_API_KEY" -H "Content-Type: application/json" \
  -d '{ "before": "2026-10-01T00:00:00Z" }'

A purge returns {"purged": 12, ...} with the filters you sent, or {"purged": 0, "message": "No matching cache entries found"}.

How each filter matches

  • keys: exact cache keys, as returned in X-Cache-Key.
  • url: a pattern matched against the URL you asked us to capture, across your account's successful renders. Use * as the wildcard. The match is on the URL string you sent, so https://example.com/blog and https://example.com/blog/ are different; end the pattern with * to cover both, and remember query strings are part of the URL.
  • before: an ISO 8601 timestamp. Every successful render on your account created before it is purged. An unparseable value returns 400 with invalid_date.
  • pattern: matches storage paths rather than page URLs. For images cached by the API, the url and before filters are the practical ones.

Filters add up. An entry is purged if it matches any filter in the request. {"url": "https://example.com/blog/*", "before": "2026-10-01T00:00:00Z"} purges every blog image and every image of any page rendered before October 1. If you want "blog images older than October 1", there is no single request for it; keep the keys of those renders and purge by keys.

After a purge: render again with refresh

Purging does not render anything. The next request for that page renders as normal. If your code uses cache.available to reuse earlier renders, send cache.refresh: true on the first request after a purge. Refresh skips the lookup, renders a new image and replaces what is stored, so later lookups find the fresh render.

This deploy hook does both steps for a list of changed pages:

// purge-on-deploy.mjs: after a deploy, drop cached screenshots for changed pages and render them again.
// Node 22+. Usage: RS_API_KEY=rs_live_... node purge-on-deploy.mjs https://example.com/blog/a https://example.com/pricing
const API = process.env.RS_API_BASE ?? 'https://api.renderscreenshot.com';
const headers = { Authorization: `Bearer ${process.env.RS_API_KEY}`, 'Content-Type': 'application/json' };

async function post(path, body) {
  const res = await fetch(`${API}${path}`, { method: 'POST', headers, body: JSON.stringify(body) });
  if (!res.ok) throw new Error(`${path} ${res.status}: ${await res.text()}`);
  return res;
}

for (const page of process.argv.slice(2)) {
  const { purged } = await (await post('/v1/cache/purge', { url: page })).json();
  // Render again with refresh, so the next cache.available lookup gets this fresh image.
  const res = await post('/v1/screenshot', { url: page, preset: 'og_card', cache: { refresh: true } });
  await res.arrayBuffer();
  console.log(`${page}: purged ${purged}, new image ${res.headers.get('x-cache-url')}`);
}

Run it from CI after a deploy with the URLs of the pages that changed. Each page costs one credit for the re-render; the purge itself is free.

Social cards: change the URL instead

When an og:image must change, the copy that matters is often not ours: LinkedIn, Slack, X and messaging apps fetch the image once and keep it. Purging our cache does not touch their copies. Change the image URL instead, for example by adding a version of the page content to the URL you capture:

{ "url": "https://example.com/blog/launch?v=2026-10-15", "preset": "og_card" }

A different URL is a different cache key, so this renders a new image, and the old entry expires on its own. Platforms then fetch the new image the next time they scrape the page.

SDK examples

Purge helpers in each official SDK. Each returns the purge result with the purged count.

Node.js

import { Client } from 'renderscreenshot';

const client = new Client(process.env.RS_API_KEY);
await client.cache.purge([savedKey]);                       // by key
await client.cache.purgeUrl('https://example.com/blog/*');  // by URL pattern
await client.cache.purgeBefore(new Date('2026-10-01T00:00:00Z'));

Python

client.cache.purge([saved_key])
client.cache.purge_url('https://example.com/blog/*')
client.cache.purge_before(datetime(2026, 10, 1, tzinfo=timezone.utc))

Ruby

client.cache.purge([saved_key])
client.cache.purge_url('https://example.com/blog/*')
client.cache.purge_before(Time.utc(2026, 10, 1))

PHP

$client->cache->purge([$savedKey]);
$client->cache->purgeUrl('https://example.com/blog/*');
$client->cache->purgeBefore(new DateTime('2026-10-01T00:00:00Z'));

Java

client.cache.purge(Arrays.asList(savedKey));
client.cache.purgeUrl("https://example.com/blog/*");
client.cache.purgeBefore(Instant.parse("2026-10-01T00:00:00Z"));

Go

cache := client.Cache()
_, err = cache.Purge(ctx, []string{savedKey})
_, err = cache.PurgeURL(ctx, "https://example.com/blog/*")
_, err = cache.PurgeBefore(ctx, time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC))

The Java example was not run; the rest ran against the mock API.

Troubleshooting

Symptom Likely cause Fix
Purge removed far more than expected Two filters in one request; they add up One filter per request
purged: 0 for a page you rendered Pattern does not match the exact URL string (slash, query, http vs https) End the pattern with *; check the URL in your request logs
404 on DELETE for a key you just received The key's slashes and extension do not survive in a URL path, or it was already purged Purge it with keys in the body
400 invalid_date before is not ISO 8601 Send 2026-10-01T00:00:00Z
Social card still shows the old image The platform's own cache Change the image URL; re-scrape with the platform's debugger
Old image still reused with cache.available No fresh render since the purge Send cache.refresh: true once
Private screenshot reachable by link X-Cache-URL is public until TTL ends Short cache.ttl and a purge after download; see authenticated pages

Related in this topic

Was this page helpful?