How Loading Works
The sequence from page load to applied variants — install script, edge fetch, and anti-flicker
Copy this guide and your current settings as a prompt for your AI agent.
Preview agent promptSee the guide, code and settings included when you copy.
The Coframe SDK reaches your visitors through a three-part sequence: an install
script in your page’s <head> sets up the queue and hides the page, the SDK
script is fetched from the edge (arriving with project data already baked in),
and the page is revealed once variants are applied or a timeout elapses.
01The install script
The install script is a small, synchronous IIFE placed in the <head> of each
page. It runs before the browser paints content and does the following in order:
-
Disable guard — if
?cf_disable(or?cf_disabled) appears anywhere in the query string, the script logs a warning and exits immediately. Nothing loads. -
Duplicate guard — if an element with the id
coframe-sdk-jsalready exists in the DOM, the script exits. This prevents the SDK from being installed twice on the same page. -
Config object — builds a configuration object containing at minimum
projectId,currentUrl(the current page URL),startTime(the current timestamp, used for performance tracking), andtimeoutMs: 1000. -
Queue setup — initialises
window.CFQand pushes the config:(window.CFQ = window.CFQ || []).push({ config }). The SDK reads this command from the queue when it loads. -
Anti-flicker — hides the page body and arms a fallback reveal timer (see Anti-flicker during load below).
-
SDK script injection — creates an
async<script>pointing tohttps://edge.cofra.me/cf.jswith the config serialized into theconfigquery parameter. Anonerrorhandler callsshow()so the page is never permanently hidden if the request fails.
The config query parameter is a JSON-encoded, URL-encoded configuration
object. The edge requires it to contain both projectId and currentUrl — the
install script populates both automatically.
For the full install snippet and placement guidance, see JavaScript installation.
02Fetching from the edge
When the browser fetches https://edge.cofra.me/cf.js?config=..., the edge
worker parses the config parameter, loads project data (experiments, variants,
personalization rules) for the identified project, selects the appropriate SDK
bundle based on the browser’s User-Agent, and returns a single JavaScript
response containing both:
- A
window.CFQ.push({ projectData: ... })call with the project data — the filtered experiment configuration and personalization headers — baked directly into the script. - The full compiled SDK bundle, appended immediately after.
Because the project data and the SDK bundle arrive together in one HTTP
response, the SDK does not need a separate network round-trip to fetch its
configuration after it loads. The projectData push is already waiting in the
queue before the first line of SDK code executes.
For details on how the edge handles SDK delivery and versioning, see Delivery and versioning.
03Anti-flicker during load
When Coframe applies a variant to a page element, there is a window between the browser’s first paint and when the SDK finishes applying changes. Without protection, visitors can briefly see the original content before it is replaced — a flash of original content.
The install script addresses this synchronously, before the browser’s first paint, using a CSS variable to hide the body:
const style = document.createElement('style');
style.id = 'coframe-antiflicker';
style.textContent =
':root { --cf-show: 0;}' +
'body { opacity: var(--cf-show) !important; transition: opacity 0.2s ease; }'
function hide() { document.head.appendChild(style); }
function show() {
document.documentElement.style.setProperty('--cf-show', '1');
style.parentNode && style.parentNode.removeChild(style);
}
hide(); setTimeout(show, config.timeoutMs);The body is hidden by setting --cf-show: 0. A fallback timer calls show()
after config.timeoutMs — the generated install script ships timeoutMs: 1000,
so the page is always revealed within 1000 ms even if the SDK has not finished
applying changes. When the SDK finishes applying variants it calls show()
earlier, and the onerror handler on the injected <script> also calls
show() directly if the edge request fails. The page is never permanently stuck
in a hidden state.
Because anti-flicker must guarantee the body is hidden before the browser’s first paint, the install script cannot be loaded asynchronously. Loading it through an async tag manager (such as Google Tag Manager) means the browser may paint original content before the snippet runs, defeating the protection.
For the full hide/reveal explanation and timeout configuration, see
Anti-flicker. To adjust timeoutMs and other
runtime settings, see Config reference.
# How Loading Works
The sequence from page load to applied variants — install script, edge fetch, and anti-flicker
The Coframe SDK reaches your visitors through a three-part sequence: an install
script in your page’s `<head>` sets up the queue and hides the page, the SDK
script is fetched from the edge (arriving with project data already baked in),
and the page is revealed once variants are applied or a timeout elapses.
[Video: Video: the install script, the single edge round trip, and the reveal — step by step (54s, narrated)](assets/videos/fig05-how-loading-works.mp4)
Watch: 54s — the install script, the single edge round trip, and the reveal — step by step
## The install script
The install script is a small, synchronous IIFE placed in the `<head>` of each
page. It runs before the browser paints content and does the following in order:
-
Disable guard — if `?cf_disable` (or `?cf_disabled`) appears anywhere in
the query string, the script logs a warning and exits immediately. Nothing
loads.
-
Duplicate guard — if an element with the id `coframe-sdk-js` already
exists in the DOM, the script exits. This prevents the SDK from being
installed twice on the same page.
-
Config object — builds a configuration object containing at minimum
`projectId`, `currentUrl` (the current page URL), `startTime` (the current
timestamp, used for performance tracking), and `timeoutMs: 1000`.
-
Queue setup — initialises `window.CFQ` and pushes the config:
`(window.CFQ = window.CFQ || []).push({ config })`. The SDK reads this
command from the queue when it loads.
-
Anti-flicker — hides the page body and arms a fallback reveal timer (see
[Anti-flicker during load](#anti-flicker-during-load) below).
-
SDK script injection — creates an `async` `<script>` pointing to
`https://edge.cofra.me/cf.js` with the config serialized into the `config`
query parameter. An `onerror` handler calls `show()` so the page is never
permanently hidden if the request fails.
The `config` query parameter is a JSON-encoded, URL-encoded configuration
object. The edge requires it to contain both `projectId` and `currentUrl` — the
install script populates both automatically.
For the full install snippet and placement guidance, see
[JavaScript installation](../docs/javascript.html).
## Fetching from the edge
When the browser fetches `https://edge.cofra.me/cf.js?config=...`, the edge
worker parses the `config` parameter, loads project data (experiments, variants,
personalization rules) for the identified project, selects the appropriate SDK
bundle based on the browser’s `User-Agent`, and returns a single JavaScript
response containing both:
- A `window.CFQ.push({ projectData: ... })` call with the project data — the
filtered experiment configuration and personalization headers — baked
directly into the script.
- The full compiled SDK bundle, appended immediately after.
Because the project data and the SDK bundle arrive together in one HTTP
response, the SDK does not need a separate network round-trip to fetch its
configuration after it loads. The `projectData` push is already waiting in the
queue before the first line of SDK code executes.
For details on how the edge handles SDK delivery and versioning, see
[Delivery and versioning](../docs/delivery-and-versioning.html).
## Anti-flicker during load
When Coframe applies a variant to a page element, there is a window between the
browser’s first paint and when the SDK finishes applying changes. Without
protection, visitors can briefly see the original content before it is
replaced — a flash of original content.
The install script addresses this synchronously, before the browser’s first
paint, using a CSS variable to hide the body:
JS
```
const style = document.createElement('style');
style.id = 'coframe-antiflicker';
style.textContent =
':root { --cf-show: 0;}' +
'body { opacity: var(--cf-show) !important; transition: opacity 0.2s ease; }'
function hide() { document.head.appendChild(style); }
function show() {
document.documentElement.style.setProperty('--cf-show', '1');
style.parentNode && style.parentNode.removeChild(style);
}
hide(); setTimeout(show, config.timeoutMs);
```
The body is hidden by setting `--cf-show: 0`. A fallback timer calls `show()`
after `config.timeoutMs` — the generated install script ships `timeoutMs: 1000`,
so the page is always revealed within 1000 ms even if the SDK has not finished
applying changes. When the SDK finishes applying variants it calls `show()`
earlier, and the `onerror` handler on the injected `<script>` also calls
`show()` directly if the edge request fails. The page is never permanently stuck
in a hidden state.
Because anti-flicker must guarantee the body is hidden before the browser’s
first paint, the install script cannot be loaded asynchronously. Loading it
through an async tag manager (such as Google Tag Manager) means the browser may
paint original content before the snippet runs, defeating the protection.
For the full hide/reveal explanation and timeout configuration, see
[Anti-flicker](../docs/anti-flicker.html). To adjust `timeoutMs` and other
runtime settings, see [Config reference](../docs/config-reference.html).
## Related
- [JavaScript installation](../docs/javascript.html) — full install
snippet and placement guidance
- [Anti-flicker](../docs/anti-flicker.html) — hide/reveal behavior and
timeout configuration
- [Delivery and versioning](../docs/delivery-and-versioning.html) — how
the edge serves the SDK bundle
- [Config reference](../docs/config-reference.html) — all supported
configuration fields including `timeoutMs`
- [Preview and debug](../docs/preview-and-debug.html) — `?cf_disable`
and other debug URL parameters