These docs are a work in progress and may not be fully up to date. Some pages may contain internal notes for our team.
Skip to Content

Decision: CDN pointer pattern

Status: accepted

Context

Each published finder has a payload — a JSON blob of locations, design config, and settings — that the widget loads on every page view. This payload can be large (hundreds of locations × field data). Caching it at the CDN matters directly for embed load time.

The straightforward approach is a single URL per finder (cdn.../finders/{token}/config.json) with a short TTL so updates propagate quickly. The problem: a 5-minute TTL on a large payload means every CDN edge re-fetches the full payload every 5 minutes even when nothing changed. Cache hit rates are low for infrequently-visited finders.

The goal is: fast propagation after publish, high cache hit rate between publishes.

Decision

Two files per finder, with different TTLs:

FileKey patternTTLContents
Pointerfinders/{token}/config.json5 minutes{ "hash": "sha1hexstring" }
Payloadfinders/{token}/v/{hash}.json1 year (immutable)Full finder JSON

The widget loads the pointer first, reads the hash, then checks its localStorage cache. If the cached hash matches, the local copy is used directly (no CDN round-trip for the payload). If the hash differs — or there is no cache — the widget fetches the versioned payload URL. Since the payload URL contains the hash, it is content-addressed and can be cached forever.

When a finder is published, ExternalController::syncFinderDetails computes a new SHA-1 hash of the payload, uploads v/{hash}.json to R2, then overwrites config.json with the new hash. Old payload files are not deleted — they are orphaned but serve ongoing sessions that loaded the previous pointer before the update.

Propagation time = pointer TTL = 5 minutes. A visitor who loaded the old pointer will use the old payload until their pointer cache expires.

Alternatives considered:

  • Single URL with ?v=hash query string — CDN varies on query string but many edge configs don’t, leading to unpredictable behavior.
  • Origin-only serving — eliminates CDN benefits entirely; unacceptable latency for international embeds.

Consequences

Benefits:

  • Payload is cached at CDN edges for up to a year between publishes. High-traffic finders pay one origin round-trip per 5-minute window.
  • The widget can serve stale-but-valid payloads from localStorage even when the CDN is unreachable.
  • Publish never breaks in-flight sessions: old versioned URLs remain valid indefinitely.

Costs:

  • One extra round-trip (pointer fetch) on every cold load.
  • R2 storage grows linearly with publish history. No cleanup job exists for orphaned payload files — this is an open maintenance gap.
  • The 5-minute propagation window means a just-published update is not immediately live everywhere.