Technical reference
The Brightspot Experimentation plugin provides a provider-based A/B testing framework for Brightspot CMS. It defines the core interfaces, data model, and CMS UI components for managing experiments and content variations, and ships with a complete Kameleoon integration—including a REST API client and CDN edge functions for AWS CloudFront, Cloudflare Workers, and Akamai EdgeWorkers—for variation delivery without front-end changes.
Dependencies
- Kameleoon integration: a Kameleoon account with client ID, client secret, and site code
- CDN edge integration: an AWS account with CloudFront and Lambda@Edge access, a Cloudflare account with Workers access, or an Akamai account with EdgeWorkers and EdgeKV access
Installation
To add the core experimentation framework:
- Maven
- Gradle
- Gradle (Kotlin DSL)
<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.experimentation</groupId>
<artifactId>experimentation</artifactId>
<version>1.6.0</version>
</dependency>
// Requires Brightspot 4.5 or later.
implementation 'com.brightspot.experimentation:experimentation:1.6.0'
// Requires Brightspot 4.5 or later.
implementation("com.brightspot.experimentation:experimentation:1.6.0")
To use the Kameleoon provider (includes the core framework as a transitive dependency):
- Maven
- Gradle
- Gradle (Kotlin DSL)
<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.experimentation</groupId>
<artifactId>kameleoon</artifactId>
<version>1.6.0</version>
</dependency>
// Requires Brightspot 4.5 or later.
implementation 'com.brightspot.experimentation:kameleoon:1.6.0'
// Requires Brightspot 4.5 or later.
implementation("com.brightspot.experimentation:kameleoon:1.6.0")
API reference
Core framework
Experiment<E, S>
Base interface for experiment data models. E is the concrete experiment type (self-referential) and S is its associated ExperimentService type. Extend AbstractExperiment rather than implementing this interface directly.
| Method | Return type | Description |
|---|---|---|
getName() | String | Returns the experiment name. Must not return null. |
getDescription() | String | Returns the experiment description. |
getService() | S | Returns the ExperimentService associated with this experiment. Must not return null. |
getStatus() | ExperimentStatus | Returns the current experiment status. Must not return null. |
setStatus(ExperimentStatus) | void | Sets the experiment status. |
getStatusLabel() | String | Returns a human-readable label for the current status. Providers can override this to append their own context—KameleoonExperiment appends " (MTU Limited)" when the account has exceeded its monthly tracked users limit. |
getVariations() | Set<VariationOrDefault> | Returns the set of variations participating in the experiment. |
getWinner() | VariationOrDefault | Returns the winning variation, or null if no winner has been determined. |
isAutoPromoteWinner() | boolean | Returns true if the winning variation should be automatically published as the primary content. |
getResultsUrl() | String | Returns a URL to the provider's results page. Returns null by default. |
getResultsTarget() | String | Returns the link target for the results URL (for example, _blank). Returns null by default. |
getScheduleStartOn() | ZonedDateTime | Returns the scheduled start time, or null to start immediately. |
getUniqueExperimentId() | String | Returns a unique identifier for the experiment. Defaults to the record id as a string. |
endExperiment(boolean, boolean) | void | Ends the experiment. The first parameter controls whether the winner is promoted to primary content; the second controls whether associated variations are archived. |
restoreExperiment() | void | Restores the experiment and any associated archived variations. |
ExperimentStatus
Enum representing the lifecycle states of an experiment.
| Value | Description |
|---|---|
RUNNING | The experiment is active and collecting data. |
PAUSED | The experiment is temporarily paused. |
PLANNED | The experiment is scheduled but has not started. |
COMPLETED | The experiment has ended. |
"Archived" is not an ExperimentStatus value. It is a derived state based on whether the experiment's content has been moved to the trash, and is filtered separately from ExperimentStatus in queries and the Experiments widget. The "Running (MTU Limited)" and "Planned (MTU Limited)" labels shown in the CMS are likewise not status values—they come from Experiment#getStatusLabel().
VariationOrDefault
Interface representing either a named content variation or the default (control) version of an asset. Used as the element type for Experiment#getVariations() and the return type of Experiment#getWinner().
| Method | Return type | Description |
|---|---|---|
getRecordId() | UUID | Returns the ID of the underlying record (variation or default content). |
getVariationLabel() | String | Returns the display label for this variation or default. |
canBePromotedToPrimary() | boolean | Returns true if this entry can be promoted to primary content. |
promoteToDefaultContent(Experiment<?,?>) | void | Promotes this entry to the primary content of the given experiment's asset. |
restoreVariation() | void | Restores this entry from an archived state. Default implementation is a no-op. |
ExperimentService<E, S>
Service interface for synchronizing experiment state with a provider. E is the experiment type and S is the service type (self-referential). Implement this interface to integrate a new A/B testing provider.
| Method | Return type | Description |
|---|---|---|
create(E) | void | Creates the experiment in the provider. |
read(E) | void | Reads the current experiment state from the provider, updating the experiment object in place. |
update(E) | void | Updates the experiment in the provider. |
delete(E) | void | Deletes the experiment from the provider. |
prepareRefresh(Collection<E>) | void | Called once before RefreshExperimentTask refreshes a batch of this service's Refreshable experiments. Default is a no-op; override to prefetch state shared across the batch. |
endRefresh() | void | Called once after that batch finishes refreshing. Default is a no-op. |
ExperimentServiceProvider
Interface for registering provider-specific ExperimentService instances with the framework. Implement this interface to control which services are available for a given content type or site. Use the static utility methods on ExperimentServiceProvider.Static to look up registered services.
| Static method | Return type | Description |
|---|---|---|
Static.getExperimentServicesByContent(Site, Object) | Set<ExperimentService> | Returns all services that support experiments on the given content object. |
Static.getAllExperimentServices(Site) | Set<ExperimentService> | Returns all registered services for the given site. |
Static.getExperimentsSupportingTypes(Site) | Set<ObjectType> | Returns all content types that support experiments on the given site. |
AbstractExperiment
Abstract base class for experiment data models. Extends Brightspot's Content type and provides default field implementations for name, description, and autoPromoteWinner. Extend this class when implementing a new experiment type.
ExperimentVariation
Represents one content variation for use in an experiment. Extends Content and implements OverlayProvider, using ExperimentVariationData to store field-level differences between the original content and the variation.
| Method | Return type | Description |
|---|---|---|
getName() | String | Returns the variation name. |
getContentId() | UUID | Returns the ID of the content asset this variation is based on. |
promoteToDefaultContent(Experiment<?,?>) | void | Applies the variation's field differences to the primary content and publishes it. |
restoreVariation() | void | Restores the variation from an archived state. |
Refreshable<E, S>
Optional interface for experiments that need periodic state synchronization from the provider. Implement this alongside Experiment when the provider may update experiment state independently of Brightspot.
| Method | Return type | Description |
|---|---|---|
shouldRefresh() | boolean | Returns true if the experiment should be refreshed. The default implementation returns true for experiments with RUNNING, PAUSED, or PLANNED status, unless a permanent stop record exists. |
onRefresh() | boolean | Refreshes the experiment by calling ExperimentService#read. Returns true if state changed, false otherwise. The experiment is only saved when this returns true. |
RefreshExperimentTask runs hourly, restricted to a configured task host, and groups Refreshable experiments by ExperimentService, calling ExperimentService#prepareRefresh and #endRefresh around each service's batch. It tracks per-experiment backoff and failure state in a RefreshRecord, which shouldRefresh() consults in addition to checking for a permanent stop record.
ExperimentationPermissionProvider
Interface for contributing permission entries to the experimentation permission system. Implement this interface to register additional permissions that appear under the Experimentation additional permission on Brightspot roles.
| Method | Return type | Description |
|---|---|---|
getExperimentationPermissions() | Set<ExperimentationPermissionValue> | Returns the permission id/display name pairs contributed by this implementation. |
The core framework registers ExperimentPermissionProvider (create, create multiple, view, edit, archive, end, view results, delete, restore, and toggle status permissions) and VariationPermissionProvider. The Kameleoon integration adds KameleoonExperimentPermissionProvider (Calculate Experiment Duration), KameleoonGoalPermissionProvider (Create Shared Goal), and KameleoonMutuallyExclusiveGroupPermissionProvider (Create Mutually Exclusive Group).
ExperimentationPermissionOption
Abstract base class for the field type on ExperimentationPermissionSetting, the additional permission embedded on CMS roles that decides which of the contributed permissions a role is granted. Extends Record.
| Method | Return type | Description |
|---|---|---|
hasPermission(String) | boolean | Returns true if the given permission id is granted by this option. |
Four concrete options are provided: AllExperimentationPermission, NoneExperimentationPermission, OnlyExperimentationPermission, and AllExceptExperimentationPermission.
Kameleoon integration
KameleoonAccount
Implements ExperimentService<KameleoonExperiment, KameleoonAccount> and is stored as a Brightspot Record, making it configurable in the CMS. Displayed in the UI as "Experimentation Account," each record connects to one Kameleoon site and manages all experiment, goal, and segment synchronization for that site.
| Field | Type | Description |
|---|---|---|
name | String | Display name for this account record. |
clientId | String | Kameleoon API client ID. |
clientSecret | String | Kameleoon API client secret. Stored as a secret field. |
siteId | Integer | Deprecated. Kameleoon numeric site identifier. Hidden from the CMS form; retained only as a fallback for accounts saved before siteCode became authoritative. getResolvedSiteId() resolves the numeric ID from siteCode at run time. |
siteCode | String | Kameleoon site code. |
apiBaseUrl | String | Base URL for the Kameleoon REST API. Defaults to the Kameleoon API's default endpoint; override only for a non-default endpoint. Validated as an HTTP/HTTPS URL when set. |
environment | String | Kameleoon environment. Defaults to production. Configurable from the Developer tab. |
winnerReliability | Double | Minimum confidence level (0–100) required to declare a winner. Defaults to 95.0. |
winnerImprovement | Double | Minimum improvement percentage over the control required to declare a winner. Defaults to 5.0. |
integrationNames | List<String> | Names of Kameleoon integrations enabled for this site (for example, analytics integrations configured in Kameleoon). |
defaultMutuallyExclusiveGroupId | String | ID of the MutuallyExclusiveGroup applied to an experiment on this account when the experiment does not select one explicitly. |
maxPageTargetingPaths | Integer | Maximum number of pages an experiment can target via Run On Pages. Defaults to 100. |
enableUnboundedPageTargeting | boolean | Whether experiments may target all pages or pages matching a pattern. Defaults to false. |
minRampDurationHours | Integer | Shortest progressive delivery ramp an unbounded experiment may use. Defaults to 24. |
maxConcurrentUnboundedExperiments | Integer | Maximum number of unbounded experiments that may be live at the same time. Defaults to 3. |
maxUnboundedExperimentVariations | Integer | Maximum number of variations an unbounded experiment may define. Defaults to 4. |
The Developer tab on the Experimentation Account form has additional fields not listed above (enableApplicationLayerVariationFiltering, enableLocalEngineTrackingSimulation, engineScriptTld, topLevelDomain)—local-development and engine-script overrides not needed for standard production setups.
KameleoonExperiment
Implements Experiment for the Kameleoon provider. Maps Brightspot experiment fields to Kameleoon feature flag objects and manages targeting rules, traffic allocation, and variation exposure settings.
| Field | Type | Description |
|---|---|---|
service | String | The KameleoonAccount this experiment synchronizes with. |
scheduleStartOn | Date | The scheduled start time. Placeholder "Start Immediately" when unset. |
pageTargeting | PageTargeting | Displayed as Run On Pages. Only shown when the experiment's content has no permalink of its own; defines which pages the experiment runs on. See PageTargeting. |
deliveryRule | MultiVariateDeliveryRule | Target, exposure, traffic allocation, variations, and control for the experiment. |
mutuallyExclusiveGroupId | String | Displayed as Mutually Exclusive Group. ID of the MutuallyExclusiveGroup this experiment belongs to. Falls back to the service account's defaultMutuallyExclusiveGroupId when unset. See MutuallyExclusiveGroup. |
goalPlacement | GoalPlacement | Displayed as Goal. Defaults to a new SharedGoalPlacement. See GoalPlacement. |
pageTargeting, deliveryRule, and mutuallyExclusiveGroupId render together on the same page of the New Experiment wizard; goalPlacement renders on the following page.
ExperimentConverter
Converts between Brightspot AbstractExperiment instances and Kameleoon API objects. Used internally by KameleoonAccount when synchronizing experiments with the Kameleoon API.
GoalPlacement
Interface for choosing between a shared goal and a goal defined inline on the experiment. Two implementations are provided:
| Implementation | Display name | Description |
|---|---|---|
SharedGoalPlacement | Shared | The default placement. Selects a previously created Goal by id via a goalId field, using SharedGoalValueGenerator to list goals scoped to the experiment's account. |
InlineGoalPlacement | Inline | Defines a GoalType directly on the experiment. Defaults to PageViewsGoalType. |
Goal
A shared goal definition that can be reused across multiple experiments on the same KameleoonAccount. Managed via the GoalsPage admin area. Creating one requires the Create Shared Goal permission.
| Field | Type | Description |
|---|---|---|
name | String | Display name for the goal. |
account | KameleoonAccount | The account this goal belongs to. Read-only after creation. |
goalType | GoalType | The goal's tracking configuration. Defaults to PageViewsGoalType. |
GoalType
Interface for a goal's tracking configuration, used by both InlineGoalPlacement and Goal. Five implementations are provided:
| Implementation | Display name | Key fields |
|---|---|---|
PageViewsGoalType | Number of Page Views | comparison, pageViews |
AccessToPageGoalType | Access To Page | comparison, url |
ClickTrackingGoalType | Click Tracking | pageUrl, cssSelectors |
ScrollTrackingGoalType | Scroll Tracking | pageUrl, scrollTarget |
TimeSpentGoalType | Time Spent | comparisonType, duration, timeUnit |
GoalConverter
Handles conversion between Brightspot goal configurations and Kameleoon goal objects. Supports all five GoalType implementations.
SegmentConverter
Manages synchronization of Kameleoon audience segments for use as experiment targeting rules.
PageTargeting
Abstract base class defining the set of pages a KameleoonExperiment runs on when its content has no permalink of its own (e.g., a shared configuration object). Assigned to KameleoonExperiment#getPageTargeting(). Resolved page URLs are converted into path conditions on the experiment's Kameleoon wrapper segment, so the experiment is only evaluated on those pages. The resolved set is always capped by KameleoonAccount#getMaxPageTargetingPaths() to bound CDN cache fragmentation.
| Method | Return type | Description |
|---|---|---|
resolveUrls(int) | List<String> | Returns the site-absolute permalink URLs this targeting resolves to, up to the given maximum. |
resolveContentIds(int) | Set<UUID> | Returns the ids of the content this targeting matches, up to the given maximum. |
segmentConditionSpec(KameleoonAccount, KameleoonExperiment, Date) | SegmentConditionSpec | Describes the segment conditions scoping the experiment to this targeting, and records what they were built from so refreshes can detect changes. |
Four concrete implementations are provided:
| Implementation | Display name | Description |
|---|---|---|
CuratedPageTargeting | Selected Pages | Targets a fixed, editorially curated list of content. Not refreshed automatically; validation rejects lists larger than the account's page cap. |
QueryPageTargeting | Pages Matching Query | Targets the newest content matching a Query<Content>, re-evaluated on a schedule (RefreshInterval, default HOURLY). maxContentAgeHours (default 72) excludes older content on refresh unless set to 0; disableAutoRefresh limits recalculation to save time. |
PathPatternPageTargeting | Pages Matching Pattern | Targets every page whose normalized request path matches a pathPattern regular expression. Extends UnboundedPageTargeting. |
GlobalPageTargeting | All Pages | Targets every page on the site. Extends UnboundedPageTargeting. |
UnboundedPageTargeting
Abstract subclass of PageTargeting for targeting that has no enumerable member pages. Pages join the experiment progressively in stable hash buckets that widen linearly over a ramp window (rampDurationHours, default 48), spreading CDN cache fill cost across the ramp instead of taking it all at experiment start. The ramp is monotone: once a page's bucket is included it never leaves. KameleoonExperiment#onValidate() rejects unbounded targeting unless KameleoonAccount#isEnableUnboundedPageTargeting() is true, and enforces the account's minimum ramp duration, maximum variation count, and maximum concurrent unbounded experiments.
| Method | Return type | Description |
|---|---|---|
getRampDurationHours() | int | Returns the configured ramp duration, or the 48-hour default. |
advanceBucketLimit(boolean, Date) | int | Advances and persists the ramp's current bucket limit while the experiment is running; returns the limit unchanged otherwise. |
isFullyRamped() | boolean | Returns true once the ramp has reached every bucket. |
MutuallyExclusiveGroup
A named Kameleoon tag used to assign experiments to a mutually exclusive group, scoped to a single KameleoonAccount. Managed via the MutuallyExclusiveGroupsPage admin area. Creating one requires the Create Mutually Exclusive Group permission.
| Field | Type | Description |
|---|---|---|
name | String | Display name for the group. |
account | KameleoonAccount | The account this group belongs to. |
tag | String | The group's Kameleoon tag suffix. getApiTag() prepends the ME-GROUP- prefix automatically. |
Configuration
Kameleoon account
To create an Experimentation Account:
-
In the header, click .
-
From the Create list, select Experimentation Account.
-
Using the following table as a reference, complete the fields as needed.
Field Description Name Display name for this account configuration. Client ID Kameleoon API client ID. Client Secret Kameleoon API client secret. Site Code Kameleoon site code. Winner Reliability Minimum confidence level (0–100) for automatic winner promotion. Defaults to 95. Winner Improvement Minimum improvement percentage over the control for automatic winner promotion. Defaults to 5. Integration Names Names of Kameleoon integrations enabled for this site. Default Mutually Exclusive Group The mutually exclusive group applied to an experiment on this account when the experiment does not select one explicitly. Max Pages Per Experiment Maximum number of pages an experiment can target via Run On Pages. Each targeted page is served per-variation from the origin, so large sets increase origin load. Defaults to 100. Allow Unbounded Experiments Whether experiments may target all pages or pages matching a pattern. Unbounded experiments always ramp in progressively to protect the CDN cache; leave off unless origin capacity has been verified. Min Ramp Duration (Hours) Shortest progressive delivery ramp an unbounded experiment may use. Defaults to 24. Max Concurrent Unbounded Experiments Maximum number of unbounded experiments that may be live at the same time. Each one multiplies CDN cache entries on every page it covers. Defaults to 3. Max Variations Per Unbounded Experiment Maximum number of variations an unbounded experiment may define. Each variation adds a per-page CDN cache entry across every covered page. Defaults to 4. -
Click Save.
Site ID is not part of this form. It is a deprecated, hidden field retained only as a fallback for accounts created before Site Code became authoritative.
Shared goals and mutually exclusive groups
Shared goals and mutually exclusive groups are each managed from their own admin area rather than as a content type created from the header. Go to the CMS's Admin area, and select Shared Goals or Mutually Exclusive Groups. Both areas require an account-scoped create permission (Create Shared Goal or Create Mutually Exclusive Group); without it, the form for creating a new record is read-only.
CDN edge integration
The plugin includes CDN edge functions that intercept requests before they reach Brightspot to resolve Kameleoon variation assignments at the network edge. This allows cached CDN responses to be personalized per visitor without requiring front-end JavaScript changes.
On each request, the edge function reads the visitor's Kameleoon cookie, calls the Kameleoon SDK to determine the assigned variation, and forwards the result to Brightspot via an x-bsp-variations request header. On the response, it sets the Kameleoon visitor cookie.
Three implementations are provided: one for AWS CloudFront using Lambda@Edge, one for Cloudflare using Workers, and one for Akamai using EdgeWorkers. The three platforms share the same core request/response flow, but their optional configuration has diverged—each platform's table below lists only the variables that platform supports.
AWS Lambda@Edge
The kameleoon-cdn-edge-aws module contains the Lambda@Edge function.
Building the function
To build the Lambda@Edge function:
-
Navigate to the
kameleoon-cdn-edge-aws/directory. -
Install dependencies and build:
1npm install2npm run buildThe output is a
handler.zipfile in thedist/directory. Deploy this file to Lambda in theus-east-1region.
Lambda@Edge functions must be deployed in us-east-1 regardless of where your CloudFront distribution is configured.
CloudFront configuration
After deploying the function:
- Add
x-bsp-variationsto the CloudFront distribution's safelisted forwarded headers. - Associate the Lambda function with both the
Viewer RequestandViewer Responseevent types on the relevant cache behavior.
Parameter Store configuration
The Lambda function reads its configuration from AWS Systems Manager Parameter Store. Parameters follow the path /kameleoon/{distributionId}/{parameterName} for distribution-level configuration, or /kameleoon/{distributionId}/{domain}/{parameterName} for domain-specific overrides.
Required parameters:
| Parameter | Type | Description |
|---|---|---|
SITE_CODE | String | Kameleoon site code. |
CLIENT_ID | String | Kameleoon API client ID. |
CLIENT_SECRET | SecureString | Kameleoon API client secret. Must be created manually in the AWS Console; this parameter type cannot be provisioned via infrastructure-as-code tools. |
Optional parameters:
| Parameter | Default | Description |
|---|---|---|
COOKIE_DOMAIN | Request domain | Cookie domain for Kameleoon visitor tracking. Set to a root domain (e.g., .example.com) to share the visitor cookie across subdomains. |
NETWORK_DOMAIN | Kameleoon's default endpoints | Routes all Kameleoon SDK traffic (config/data/events) through a custom proxy domain instead of the default *.kameleoon.* endpoints. |
CONFIG_UPDATE_INTERVAL | 20 | Interval in minutes at which the function refreshes its cached Kameleoon configuration. |
ENABLE_REMOTE_DATA | false | Whether to fetch additional visitor data from Kameleoon for enhanced targeting. Not recommended due to added latency. |
ENABLE_ENGINE_TRACKING | false | Sets the x-bsp-engine-tracking response header whenever enabled, even with no active variations, so the origin injects engine.js for control-group/visit-level tracking. |
ENABLE_EXPERIMENT_VARIATIONS_HEADER | false | Sets the x-bsp-experiment-variations response header with featureKey:variationKey pairs for every experiment-evaluated visitor, including those assigned the default variation. |
CONSENT_POLICY | not_required | Whether visitor consent is required before assigning variations. Values: required or not_required. |
UNKNOWN_CONSENT_BEHAVIOR | allow | Behavior when no consent cookie is present. Values: allow or block. |
For CloudFront distributions serving multiple domains, the function resolves parameters using a hierarchical lookup: it checks for a domain-specific parameter first (e.g., /kameleoon/{distributionId}/staging.example.com/SITE_CODE), walks up the domain hierarchy, and falls back to the distribution-level default. Most implementations use distribution-level parameters only.
Cloudflare Workers
The kameleoon-cdn-edge-cloudflare module contains the Cloudflare Worker.
Building and deploying
To build and deploy the Cloudflare Worker:
-
Navigate to the
kameleoon-cdn-edge-cloudflare/directory. -
Install dependencies:
1npm install -
Update
wrangler.jsoncwith your Cloudflare account ID and the required configuration variables. -
Deploy to Cloudflare:
1npm run deploy
Configuration variables
Set the following variables in wrangler.jsonc under env.{environment}.vars, or use Wrangler secrets for sensitive values.
Required variables:
| Variable | Description |
|---|---|
SITE_CODE | Kameleoon site code. |
CLIENT_ID | Kameleoon API client ID. |
CLIENT_SECRET | Kameleoon API client secret. Store as a Wrangler secret rather than committing to wrangler.jsonc. |
Optional variables:
| Variable | Default | Description |
|---|---|---|
COOKIE_DOMAIN | Request domain | Cookie domain for Kameleoon visitor tracking. Set to a root domain (e.g., .example.com) to share the visitor cookie across subdomains. |
CONFIG_UPDATE_INTERVAL | 20 | Interval in minutes at which the worker refreshes its cached Kameleoon configuration. |
ENABLE_REMOTE_DATA | false | Whether to fetch additional visitor data from Kameleoon for enhanced targeting. Not recommended due to added latency. |
ENABLE_TRACK | false | Whether the worker sends Kameleoon tracking events itself. |
ENABLE_ENGINE_TRACKING | false | Sets the x-bsp-engine-tracking response header whenever enabled, even with no active variations, so the origin injects engine.js for control-group/visit-level tracking. |
ENABLE_EXPERIMENT_VARIATIONS_HEADER | false | Sets the x-bsp-experiment-variations response header with featureKey:variationKey pairs for every experiment-evaluated visitor, including those assigned the default variation. |
ENABLE_DATAFILE_REFRESH | false | Whether the worker refreshes the Kameleoon SDK's data file on an interval rather than relying solely on the initial fetch. |
ENGINE_SCRIPT_TLD | io | Top-level domain used when constructing the Kameleoon engine script URL. |
LOG_LEVEL | WARNING | Minimum level the Kameleoon SDK logs at. |
CONSENT_POLICY | not_required | Whether visitor consent is required before assigning variations. Values: required or not_required. |
UNKNOWN_CONSENT_BEHAVIOR | allow | Behavior when no consent cookie is present. Values: allow or block. |
For multi-domain Cloudflare distributions, per-domain configuration can be provided via a KV namespace. Add a binding named exactly DOMAIN_CONFIG under env.{environment}.kv_namespaces in wrangler.jsonc—the worker reads this binding name directly, it is not configurable:
1"kv_namespaces": [2{3"binding": "DOMAIN_CONFIG",4"id": "<NAMESPACE_ID>"5}6]
Store each domain's configuration under the key domain:<hostname> (e.g., domain:www.example.com), as a JSON value with the following fields:
| Field | Default | Description |
|---|---|---|
siteCode | Required | Kameleoon site code. |
clientId | Required | Kameleoon API client ID. |
clientSecret | Required | Kameleoon API client secret. |
cookieDomain | Request domain | Cookie domain for Kameleoon visitor tracking. |
configUpdateInterval | 20 | Interval in minutes at which the worker refreshes its cached Kameleoon configuration. |
enableRemoteData | false | Whether to fetch additional visitor data from Kameleoon for enhanced targeting. |
enableTrack | false | Whether the worker sends Kameleoon tracking events itself. |
enableEngineTracking | false | Sets the x-bsp-engine-tracking response header whenever enabled. |
enableExperimentVariationsHeader | false | Sets the x-bsp-experiment-variations response header. |
enableDataFileRefresh | false | Whether the worker refreshes the Kameleoon SDK's data file on an interval. |
engineScriptTld | io | Top-level domain used when constructing the Kameleoon engine script URL. |
consentPolicy | not_required | Whether visitor consent is required before assigning variations. Values: required or not_required. |
unknownConsentBehavior | allow | Behavior when no consent cookie is present. Values: allow or block. |
logLevel | WARNING | Minimum level the Kameleoon SDK logs at. |
The worker reads domain-specific overrides from the bound namespace at run time, falling back to the vars configuration when no KV entry matches the request domain, and walks up the domain hierarchy the same way the Akamai and AWS implementations do. There is no networkDomain/NETWORK_DOMAIN equivalent on this platform—that option is AWS-only.
Akamai EdgeWorkers
The kameleoon-cdn-edge-akamai module contains the Akamai EdgeWorker. Unlike the AWS and Cloudflare implementations, it stores all configuration in Akamai EdgeKV rather than environment variables, and splits request handling across two event handlers—onClientRequest and onClientResponse—passing data between them via PMUSER variables, since onClientRequest has no response object to set headers on directly.
Building and deploying:
-
Navigate to the
kameleoon-cdn-edge-akamai/directory. -
Install dependencies and build the bundle:
1npm install2npm run bundleThe output is a
dist/bundle.tgzfile. Each deployment requires a uniqueedgeworker-versioninbundle.json. -
Upload and activate the bundle using the Akamai CLI:
1akamai edgeworkers --section <section> upload --bundle dist/bundle.tgz <edgeworker-id>2akamai edgeworkers --section <section> activate <edgeworker-id> STAGING <version>Activate on
PRODUCTIONafter verifying on staging.
Akamai property requirements:
The Akamai property must have an EdgeWorker behavior attached, referencing the EdgeWorker ID, and four PMUSER variables declared (type: text): PMUSER_BSP_VARIATIONS, PMUSER_BSP_VC_COOKIE, PMUSER_BSP_EXP_VARIATIONS (only used when enableExperimentVariationsHeader is set), and PMUSER_BSP_ENGINE_TRACKING (only used when enableEngineTracking is set).
EdgeKV configuration:
All configuration lives in the kameleoon namespace, config group of EdgeKV, as JSON values under two key patterns. Dots in hostnames become dashes (e.g., www.example.com → domain_www-example-com), since EdgeKV keys only allow A-Z a-z 0-9 _ -.
| Key pattern | Contents |
|---|---|
domain_<host-with-dashes> | Domain config JSON (below). |
sdk-config-<siteCode> | The Kameleoon SDK configuration JSON, fetched from Kameleoon and stored ahead of time. |
Domain config JSON fields:
| Field | Default | Description |
|---|---|---|
siteCode | Required | Kameleoon site code. |
clientId | Required | Kameleoon API client ID. |
clientSecret | Required | Kameleoon API client secret. |
cookieDomain | Request domain | Cookie domain for Kameleoon visitor tracking. |
networkDomain | unset | Routes all Kameleoon traffic (config/data/events) through a custom proxy domain instead of the default *.kameleoon.* endpoints. |
configUpdateInterval | 20 | Interval in minutes at which the worker refreshes its cached Kameleoon configuration. |
enableRemoteData | false | Whether to fetch additional visitor data from Kameleoon for enhanced targeting. |
enableEngineTracking | false | Sets the x-bsp-engine-tracking header whenever enabled, even with no active variations, so the origin injects engine.js. |
enableExperimentVariationsHeader | false | Sets the x-bsp-experiment-variations header with featureKey:variationKey pairs for every experiment-evaluated visitor. |
consentPolicy | not_required | Whether visitor consent is required before assigning variations. Values: required or not_required. |
unknownConsentBehavior | allow | Behavior when no consent cookie is present. Values: allow or block. |
The worker supports domain hierarchy lookup (www.example.com falls back to example.com) the same way the AWS implementation does for Parameter Store.
The EdgeKV access token used at run time is generated separately per environment and is not committed to the repository. See the kameleoon-cdn-edge-akamai module's README.md for the token generation and sandbox testing workflow.