Browser as a CDN
Requires a Enterprise license
It is anniversary week at Dave’s Dog Depot, and every sign in the shop wants the anniversary board. With the render cache, signed URLs, and a purge token, the zshot server works as a render CDN: the first fetch renders the board in the warm browser, every other sign is served from disk, and the operator expires the entry when the week is over.
Start the server with all three. The Docker image reads signing and the token from the environment; the cache flags append as arguments:
zshot --server --server-bind-port 3000 \
--server-cache --server-cache-ttl 300 \
--server-signed-url hmac-sha256:s3cr3t --server-signed-url-max-age 300 \
--server-token-auth purg3-t0k3ndocker run --rm -p 3000:3000 \
-e ZSHOT_LICENSE="MY-ZSHOT-LICENSE-KEY" \
-e ZSHOT_SERVER_SIGNED_URL="hmac-sha256:s3cr3t" \
-e ZSHOT_SERVER_SIGNED_URL_MAX_AGE="300" \
-e ZSHOT_SERVER_TOKEN_AUTH="purg3-t0k3n" \
scaleassembly/zshot-server:latest \
--server-cache --server-cache-ttl 300Distribute a signed URL
The Signed URL example mints short-lived renders of the everyday board and walks the signing algorithm; the anniversary board is the same capture with #anniversary on the page URL. This snippet signs it:
SIGNED_URL=$(python3 - <<'EOF'
import hashlib, hmac, time, urllib.parse
params = {
"url": "https://zshot-cli.com/example_assets/daves-dog-depot/#anniversary",
"output_type": "webm",
"video_duration": "16",
"video_framerate": "24",
"browser_width": "1920",
"browser_height": "1128",
"video_width": "1280",
"video_height": "752",
"wait_for": "js:menu:ready",
"expires": str(int(time.time()) + 300),
}
canonical = "&".join(
"%s=%s" % (k, urllib.parse.quote(v, safe=""))
for k, v in sorted(params.items())
)
signature = hmac.new(b"s3cr3t", canonical.encode(), hashlib.sha256).hexdigest()
print("http://127.0.0.1:3000/?" + canonical + "&signature=" + signature)
EOF
)The signs need no credentials: the signature authorizes the fetch, and an unsigned request gets 401. The first fetch pays the sixteen-second board capture; every repeat returns in milliseconds from the cache, marked by the age header:
curl -sD- -o board.webm "$SIGNED_URL" # renders the board
curl -sD- -o board.webm "$SIGNED_URL" # served from cacheHTTP/1.1 200 OK
cache-control: public, max-age=300
etag: "sha-256=:gTUKIp2NfEIBx87zKqnqs5DOOWZC+AqTzADwwZi2y/0=:"
age: 0Entries stay fresh for --server-cache-ttl seconds, and the cache-control header carries the same window downstream.
Expire the cache
When the week ends, the cached board is no longer valid. Purge it with a DELETE of the same render arguments, sent as query parameters or a JSON body. Purging follows the GET auth rules, so an anonymous DELETE gets 401; the Bearer token from --server-token-auth authorizes it:
curl -X DELETE http://127.0.0.1:3000/ \
-H 'Authorization: Bearer purg3-t0k3n' \
-H 'Content-Type: application/json' \
-d '{"url":"https://zshot-cli.com/example_assets/daves-dog-depot/#anniversary","output_type":"webm","video_duration":16,"video_framerate":24,"browser_width":1920,"browser_height":1128,"video_width":1280,"video_height":752,"wait_for":"js:menu:ready"}'204 confirms a fresh entry was expired; a repeat returns 410 because nothing is cached. The signs fall back to signed fetches of the everyday board, and a bare DELETE / with the token purges the entire cache. See the API for the full endpoint contract.