Data flow — end user
A visitor landing on a host page that embeds a DropAFinder widget goes through several distinct fetch phases before the widget renders. This document traces the full path from script load to interactive widget, plus the subsequent interactions (search, analytics).
For the broader architecture context, see Architecture overview. For the embedding setup from the customer’s perspective, see Embedding guide.
Phase 1 — Script bootstrap
The host page includes two elements:
<div id="finder-app" finder-key="YOUR_FINDER_KEY"></div>
<script src="https://cdn.locationfinders.com/ext/v2/snippet.js" defer></script>When the browser fetches snippet.js (the root loader), the loader checks whether a pointer.variant is set on the finder’s config. If the variant is "default" or absent, it imports the standard ext/2 bundle from the CDN. If a non-default variant is set, it attempts to dynamically import a variant-specific bundle from ${CDN_BASE}/ext/v2/variants/${variant}.js; if that fails, it falls through to the default bundle.
Sources: ext/2/source/src/main.js, ext/2/source/src/lib/embed.js
Phase 2 — Finder key resolution
getFinderKey() queries the DOM for the first element with a finder-key attribute and returns its value:
const appElement = document.querySelector('[finder-key]');
return appElement?.getAttribute('finder-key');This is the short token that identifies the finder. All subsequent fetches are keyed by it.
Source: ext/2/source/src/lib/embed.js
Phase 3 — Pointer fetch
fetchFinderPointer(finderKey) fetches the short-TTL pointer file from the CDN:
GET https://cdn.locationfinders.com/finders/{finderKey}/config.jsonThe pointer is a small JSON object with (at minimum) a hash field and a variant field:
{ "hash": "a1b2c3d4", "variant": "default", "published_at": "2026-04-27T12:00:00Z" }- CDN TTL: 60 seconds (
max-age=60). This is the intentionally short-lived layer — it tells the widget which version of the payload to load. - If the pointer fetch fails (network error, 404), the function returns
nulland the widget falls through to the origin API fallback.
Source: ext/2/source/src/lib/api.js:39-50
Phase 4 — Payload fetch (CDN → localStorage → origin fallback)
fetchFinderPayload(finderKey, knownHash) implements a three-level read path:
Level 1 — localStorage cache
The widget checks localStorage for the key lf-cdn-v2:{finderKey}. If the cached entry’s hash matches the pointer’s hash, the cached payload is returned immediately. No network request.
Level 2 — CDN hash-versioned payload
If the cache misses (or hash changed), the widget fetches the immutable versioned file:
GET https://cdn.locationfinders.com/finders/{finderKey}/v/{hash}.jsonThis URL is immutable — the same hash always returns the same JSON. It is served with a long CDN cache TTL. On success, the payload is stored in localStorage (keyed by lf-cdn-v2:{finderKey}, value includes { hash, data }) for next time.
Level 3 — Origin API fallback
If the CDN fetch fails (or no hash was available from the pointer), the widget falls back to the origin backend:
GET https://api.locationfinders.com/api/ext/finders/details/{finderKey}This route is unauthenticated and workspace-scoped by the finder key. It returns the same payload shape as the CDN version. The origin fallback is always available (it’s the dev path too, before any CDN infrastructure is live).
Source: ext/2/source/src/lib/api.js:52-95
Phase 5 — Geolocation enrichment
If the finder has geolocation enabled (e.g., “sort by distance” or “show results near me”), the widget calls:
GET https://ipinfo.io/jsonThe raw ipinfo.io response includes a loc string ("lat,lng"); fetchIpLocation() parses this into the normalized shape { lat, lng, country, region, city } used by the widget. The result is used to pre-center the map and sort results by proximity. If the request fails, geolocation features degrade gracefully — the map uses a default center and no distance sorting is applied.
Source: ext/2/source/src/lib/api.js:9-37
Phase 6 — Mount and render
With the payload resolved and geolocation complete, the Svelte App is mounted:
mount(App, { target, props: { finderKey, pointer } });App.svelte receives finderKey and the pointer object (which includes the CDN hash). The payload fetch runs inside App once mounted. Reset.svelte applies CSS custom properties derived from the finder’s design config and injects the Google Fonts link for DM Sans.
Phase 7 — Subsequent interactions
Search / autocomplete
When a visitor types in the search bar:
GET /api/mapping/autocomplete?input=…&provider=…
POST /api/mapping/places (place details, on selection)The autocomplete provider is configured per-finder (Google Places, Mapbox, HERE, Radar, Geoapify, or DropASearch). All requests are proxied through the backend to hide third-party API keys.
Analytics
Every finder interaction (view, click, search) emits an analytics event:
POST https://api.locationfinders.com/api/analyticsThis endpoint is unauthenticated and keyed by finderKey. The payload includes the event type, timestamp, and optional metadata (clicked location ID, search query, etc.).
Full sequence diagram
Visitor browser CDN Backend ipinfo.io
| | | |
|-- GET snippet.js -------->| | |
|<-- 200 snippet.js --------| | |
| | | |
|-- GET config.json (60s) ->| | |
|<-- { hash, variant } -----| | |
| | | |
| check localStorage | | |
| (hash match?) ----hit--> return cached payload | |
| (hash miss) | | |
|-- GET /v/{hash}.json ---->| | |
|<-- payload (immutable) ---| | |
| store in localStorage | | |
| | | |
| (fallback if CDN fetch fails) | |
|-- GET /api/ext/finders/details/{key} ------------->| |
|<-- payload ----------------------------------------| |
| | | |
|-- GET ipinfo.io/json ----------------------------------------------------------->|
|<-- { loc, country, ... } --------------------------------------------------------------|
| parse loc → { lat, lng } | | |
| | | |
| mount App.svelte | | |
| apply CSS vars + fonts | | |
| render widget | | |
| | | |
| (visitor interactions) | |
|-- POST /api/analytics ----------------------------->| |
|-- GET /api/mapping/autocomplete ------------------>| |Key performance characteristics
| Fetch | Cache | Notes |
|---|---|---|
snippet.js | CDN (long TTL) | Versioned URL; invalidated on deploy |
config.json pointer | CDN ~5 min | Short TTL so new publishes propagate quickly |
/v/{hash}.json payload | CDN long TTL + localStorage | Immutable; hash changes only on publish |
| Origin fallback | None | Always real-time; used in dev and on CDN miss |
| ipinfo.io | None | Per-visitor; not cached by the widget |
Related documents
- Architecture overview — system map
- CDN and pointer pattern — CDN layout and cache design
- External widget — init flow — widget mount internals
- Embedding guide — caching — customer-facing cache behavior