Experimentation SDK Architecture
The problem: experiment evaluation must be fast
Section titled “The problem: experiment evaluation must be fast”Every experiment evaluation adds latency. If a server-side SDK takes 200ms to decide which variation to show, your API response is 200ms slower. If a client-side snippet blocks rendering while it downloads configuration, visitors see a flash of unstyled content. The architecture of an experimentation system determines whether experiments are invisible to users or noticeably degrade their experience.
Optimizely solves this with a local-evaluation architecture. Both the server-side SDKs and the client-side snippet download a configuration file once, then evaluate all experiment decisions locally without network round-trips.
The datafile: configuration as JSON
Section titled “The datafile: configuration as JSON”At the center of every Optimizely experiment is the datafile — a JSON document that contains your complete experiment configuration. It includes every active experiment, its variations, traffic allocation percentages, audience conditions, and feature flag states.
The datafile contains:
- Experiments — variation definitions, traffic allocation, and status
- Feature flags — flag keys, variables, and rollout rules
- Audiences — targeting conditions (attributes, values, operators)
- Events — metric definitions used for tracking conversions
- Attributes — user attribute keys available for targeting
Because the datafile is a static JSON document, SDKs evaluate decisions locally using deterministic logic. No network call is needed at decision time. This is what makes experiment evaluation sub-millisecond on the server and near-instant in the browser.
Server-side SDK architecture (Feature Experimentation)
Section titled “Server-side SDK architecture (Feature Experimentation)”Server-side SDKs follow a consistent lifecycle across all platforms:
- Initialize — The SDK downloads the datafile from Optimizely’s CDN and builds an in-memory representation of your experiment configuration.
- Evaluate — When your code calls
decide()orisFeatureEnabled(), the SDK evaluates the decision locally using the in-memory datafile. No network call occurs.
Deprecation note:
isFeatureEnabled()is deprecated in SDK v4+ and will be removed in a future major version. Usedecide()(via theOptimizelyUserContext) instead. Thedecide()method returns a singleOptimizelyDecisionobject that includes the enabled state, variation key, and feature variables in one call, replacing the need for separateisFeatureEnabled()andgetFeatureVariable*()calls.
- Track — When a conversion happens, the SDK queues an event and dispatches it asynchronously to Optimizely’s event endpoint.
- Update — The SDK periodically polls for datafile changes or listens for webhook notifications.
Your Application └── Optimizely SDK (in-process) ├── Datafile (in-memory JSON config) ├── Decision Engine (local evaluation) ├── Event Dispatcher (async HTTP) └── Notification Center (lifecycle hooks)Keeping the datafile current
Section titled “Keeping the datafile current”When you change an experiment in the Optimizely app, the datafile is updated on the CDN. Your SDK needs to pick up that change. Two strategies are available:
- Polling — The SDK periodically fetches the latest datafile. Default intervals vary by SDK (typically 5 minutes). You configure the interval at initialization. Polling is simple and works everywhere.
- Webhooks — Optimizely sends a webhook notification to your server when the datafile changes. Your server then tells the SDK to re-fetch. Webhooks give near-instant updates but require infrastructure to receive them.
For most applications, polling with a short interval (30-60 seconds) balances freshness and simplicity.
Client-side snippet architecture (Web Experimentation)
Section titled “Client-side snippet architecture (Web Experimentation)”The Web Experimentation snippet follows a different lifecycle optimized for browser environments:
- Load — The snippet loads synchronously in the
<head>to execute before the page renders. This prevents flicker — visitors never see the original content before the variation is applied. - Activate — The snippet evaluates all active experiments for the current page, determines which variations apply, and executes the variation code (DOM modifications, CSS changes, or custom JavaScript).
- Track — The snippet listens for conversion events (clicks, pageviews, custom events) and sends them to Optimizely’s analytics endpoint.
- Persist — The snippet stores bucketing decisions in browser cookies so returning visitors see the same variation.
Browser └── Optimizely Snippet (synchronous in <head>) ├── Snippet Config (bundled experiment definitions) ├── Activation Engine (DOM mutation, CSS injection) ├── Event Tracker (beacon/XHR) └── Cookie Storage (bucketing persistence)The snippet bundles experiment configuration directly into the JavaScript file. When you publish changes in the Optimizely app, the snippet file is rebuilt and deployed to the CDN. There is no separate datafile.
Architectural differences at a glance
Section titled “Architectural differences at a glance”| Aspect | Feature Experimentation (SDK) | Web Experimentation (Snippet) |
|---|---|---|
| Runs on | Your server, mobile app, or OTT device | Visitor’s browser |
| Config delivery | Separate datafile (JSON via CDN) | Bundled into the snippet JS file |
| Decision latency | Sub-millisecond (in-memory) | Near-instant (in-page) |
| Flicker risk | None (server-side rendering) | Managed via synchronous loading |
| Update mechanism | Polling or webhooks | CDN snippet rebuild |
| Supported changes | Any code logic | DOM, CSS, and JavaScript |
| Offline capable | Yes (cached datafile) | No (requires page load) |
When to use which architecture
Section titled “When to use which architecture”Choose server-side SDKs when you need to experiment on backend logic, support multiple platforms from a single decision source, or eliminate any risk of visual flicker.
Choose the client-side snippet when marketers need to launch visual tests without code deploys, or when the experiment only involves front-end content changes like headlines, images, or page layout.
Many teams use both. The SDK handles feature flags and backend experiments. The snippet handles marketing-driven visual tests. They share the same Optimizely project and analytics, so results appear in one place.
Ready to implement?
Section titled “Ready to implement?”- Start with feature flags: Follow the Implement Feature Flags tutorial to create your first flag and integrate the SDK end to end.
- Set up your SDK: See the SDK quickstart guides for platform-specific initialization, installation, and first-decision walkthroughs.
1. Your team notices that experiment decisions are adding 200ms of latency to API responses. A developer suggests the SDK must be making a network call for each decision. Is this correct, and what should they investigate?
Optimizely SDKs use a local-evaluation architecture. The datafile is downloaded once and decisions are evaluated in-memory without network round-trips, making them sub-millisecond. If latency is observed, the issue is likely in SDK initialization, datafile download, or surrounding application code.
Optimizely SDKs use a local-evaluation architecture. The datafile is downloaded once and decisions are evaluated in-memory without network round-trips, making them sub-millisecond. If latency is observed, the issue is likely in SDK initialization, datafile download, or surrounding application code.
Review this topic →2. A marketer publishes a new experiment in the Optimizely app, but visitors are not seeing the changes even after 10 minutes. The team uses server-side SDKs with default settings. What is the most likely cause?
Server-side SDKs periodically poll for datafile changes. Default intervals vary by SDK (typically 5 minutes). If a change was published recently, the SDK may not have fetched the updated datafile yet. Shortening the polling interval or implementing webhooks provides faster updates.
Server-side SDKs periodically poll for datafile changes. Default intervals vary by SDK (typically 5 minutes). If a change was published recently, the SDK may not have fetched the updated datafile yet. Shortening the polling interval or implementing webhooks provides faster updates.
Review this topic →3. Your site uses the Web Experimentation snippet and users occasionally see a flash of original content before the variation loads. What architectural aspect of the snippet deployment should you review?
The Web Experimentation snippet must load synchronously in the head tag so it executes before the page renders. This prevents flicker by applying variation changes before visitors see the original content. Loading it asynchronously or in the footer causes the flash of unstyled content.
The Web Experimentation snippet must load synchronously in the head tag so it executes before the page renders. This prevents flicker by applying variation changes before visitors see the original content. Loading it asynchronously or in the footer causes the flash of unstyled content.
Review this topic →