FabricFabricExperiments
Getting started

Tag-loader (drop-in script)

Run Fabric Experiments on a marketing site or via Google Tag Manager without touching application code.

The tag-loader is a single <script> build of the web SDK. It auto-creates an anonymous subject id, fetches the signed manifest, and applies declarative DOM ops from each running experiment — Mojito-style, but governed.

The fastest install is to load the bundle directly from the Fabric-operated CDN — no build pipeline, no upload step. This is the same model Google Analytics uses: paste the snippet, ship.

<script>
  window.__FX__ = {
    manifestUrl: 'https://manifest.example.com/<orgId>/manifest',
  };
</script>
<script
  src="https://cdn.fabric.pro/v/0/experiments.tag.global.js"
  async
></script>

URL scheme:

PathBehavior
/v/0.5.3/experiments.tag.global.jsPinned exact version. Immutable, 1-year browser cache.
/v/0/experiments.tag.global.jsMajor-pinned. Auto-updates within 0.x releases.
/v/latest/experiments.tag.global.jsAlways newest. Use for prototyping; pin a major in production.

Subresource Integrity (SRI) hashes for every published version are exposed at https://cdn.fabric.pro/index.json:

<script
  src="https://cdn.fabric.pro/v/0.5.3/experiments.tag.global.js"
  integrity="sha384-…"          {/* paste from index.json */}
  crossorigin="anonymous"
  async
></script>

Install — self-hosted (full control)

If you'd rather not load JavaScript from a third-party origin (CSP-strict shops, regulated industries, sites with strict supply-chain reviews), host the bundle yourself. Two ways:

Via the CLIfx publish --static writes the signed manifest and the tag-loader bundle into a directory you upload to your CDN. Walks through this in the self-host page.

Via npm — install @fabricorg/experiments-web and copy the file from node_modules/@fabricorg/experiments-web/dist/experiments.tag.global.js into your asset pipeline.

Either way the snippet becomes:

<script src="https://cdn.example.com/experiments.tag.global.js" async></script>

How it works

window.__FX__ is the only global the loader expects. Set it before the loader script tag so the bootstrap reads it on first execution.

The loader exposes window.fx — a Promise<ClientApi> you can await from later scripts:

<script>
  window.fx?.then(client => {
    if (client.treatment('homepage-cta') === 'treatment') {
      console.log('user is in treatment');
    }
  });
</script>

What's auto-wired

  • Anonymous subject id — cookie _fx_sid (365d, samesite=lax). Override with __FX__.cookieName or pass __FX__.subjectId directly for logged-in users.
  • DOM ops — variants with domOps (replaceText, setAttr, addClass, injectCSS, etc.) apply on assignment.
  • Triggers — when a manifest experiment declares a trigger (urlMatch, waitForSelector, event), activation defers until the trigger fires.
  • Exposures — pushed to window.dataLayer so GTM tags can listen for the fx_exposure event. Set __FX__.noDefaultAdapter = true to suppress.
  • Preview — when ?fxpreview=<expId>:<variant>&fxtoken=<jwt> is in the URL, the SDK verifies the short-lived token with public JWKS from /.well-known/jwks/<orgId> and forces the variant in this browser only. Preview assignments are deliberately not exposure-tracked.

Configuration reference

FieldTypeDefaultNotes
manifestUrlstringrequiredOrigin must be CORS-friendly
subjectIdstringautoOverride the anonymous id
cookieNamestring_fx_sidAnonymous-id cookie name
cookiePrefixstring'fx.'Sticky-bucket key prefix
previewJwksUrlstringderived from manifestUrlOptional public JWKS URL for preview token verification
previewSecretstringDeprecated legacy HS256 verifier; do not embed in production HTML
beaconEndpointstringURL for batched exposure POSTs via sendBeacon
noDefaultAdapterbooleanfalseSuppress the default dataLayer.push
onExposurefunctionCustom exposure handler
onRecipeFailurefunctionFires only when variant code throws — additive to onExposure
excludedbool | functionTruthy → SDK is no-op (bots, opt-outs, consent)
maxErrorStackLengthnumber1000Cap on failure.stack chars sent to handlers

Realistic install (with adapters)

<script>
  window.__FX__ = {
    manifestUrl: 'https://manifest.example.com/acme/manifest',
    cookiePrefix: 'acme.fx.',
    excluded: () => /bot|crawler/i.test(navigator.userAgent),
    onRecipeFailure: (rec) => {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: 'fx_recipe_failure',
        fx_experiment_id: rec.experimentId,
        fx_variant_key: rec.variantKey,
        fx_failure_message: rec.failure?.message,
      });
    },
  };
</script>
<script src="https://cdn.example.com/experiments.tag.global.js" async></script>

Preview tokens are bearer credentials in URLs. They are signed by Studio/API and verified with public keys, so no preview secret belongs in customer HTML. Still set:

Referrer-Policy: no-referrer

…on pages that may receive preview links so the token isn't leaked via the Referer header to third-party origins.

See also

On this page