All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
This release adds support for Holdouts, allowing you to measure the incremental impact of feature flags and experiments by holding back a percentage of users from seeing any changes.
-
Holdouts Support (#452): Agent now fully supports Optimizely's Holdouts feature for measuring incremental impact of flags and experiments. Features include:
- Full holdouts evaluation through go-sdk v2.3.0
- Support for global (project-level) holdouts
- Holdouts evaluated before experiments and rollouts in decision flow
- Holdout decisions return
enabled: false,variationKey: "off", andruleKeycontaining the holdout identifier - Forced decisions correctly override holdout bucketing
- Zero Agent code changes required - all holdout logic handled by go-sdk
- Comprehensive acceptance test coverage with real project datafile
This enables accurate measurement of feature impact by comparing users held out from experiments against those receiving variations.
-
CMAB Acceptance Tests (#451): Added comprehensive acceptance tests for Contextual Multi-Armed Bandit (CMAB) functionality to ensure reliable AI-powered experimentation
- Updated to go-sdk v2.3.0 with holdouts support and CMAB improvements
- Updated CMAB API migration to use
CmabConfig.PredictionEndpointTemplatefield
- Fixed Prisma security scanning issues (#450)
This release introduces production-ready support for Contextual Multi-Armed Bandit (CMAB), enabling AI-powered experimentation that learns and adapts in real-time based on user context.
-
Contextual Multi-Armed Bandit (CMAB) Support (#446, #447): Agent now fully supports Optimizely's Contextual Multi-Armed Bandit feature for intelligent experiment variation selection. Features include:
- Full CMAB decision API integration using go-sdk v2.1.1 client.CmabConfig API
- In-memory LRU cache (default, size: 10000, TTL: 30m) for single-instance deployments
- Redis cache for multi-instance deployments with shared decision caching
- Configurable via
client.cmab.cachein config.yaml - Configurable prediction endpoint via
client.cmab.predictionEndpointfor testing/staging environments - Flexible Redis authentication support (auth_token, redis_secret, password fields)
- Follows the same plugin-based architecture as ODP cache for consistency
This enables efficient scaling of CMAB-powered feature experiments across multiple Agent instances with shared caching and real-time learning.
-
Redis Version Auto-Detection for Notifications (#448): Agent now automatically detects Redis version at startup and selects the optimal notification implementation:
- Redis >= 5.0: Uses Redis Streams (persistent, batched delivery with acknowledgment)
- Redis < 5.0: Uses Redis Pub/Sub (fire-and-forget)
- Detection fails: Falls back to Redis Pub/Sub (safe default)
Simply configure
synchronization.notification.default: "redis"and Agent handles the rest. No configuration changes needed when upgrading Redis versions. -
Redis Streams for Persistent Notification Delivery (#448): Added Redis Streams implementation for notification synchronization across Agent nodes. Redis Streams provides:
- Persistent message delivery with acknowledgment
- Automatic retries with exponential backoff
- Consumer groups for load balancing
- Configurable batching and flush intervals (batch_size, flush_interval)
- Connection error recovery with reconnection logic
- Comprehensive metrics tracking
Automatically enabled when Redis >= 5.0 is detected. See docs/redis-streams.md for advanced configuration options.
-
Flexible Redis Authentication: Added support for flexible Redis password field names across all Redis clients (ODP cache, UPS, CMAB cache, and synchronization):
- Supports
auth_token,redis_secret, andpasswordfields (in order of preference) - Falls back to environment variables:
REDIS_PASSWORD,REDIS_ODP_PASSWORD,REDIS_UPS_PASSWORD,REDIS_CMAB_PASSWORD,REDIS_PUBSUB_PASSWORD - Avoids security scanning alerts from hardcoded "password" field names
- Supports
-
CMAB Prediction Endpoint Configuration: Added configurable CMAB prediction endpoint via
client.cmab.predictionEndpointin config.yaml orOPTIMIZELY_CMAB_PREDICTIONENDPOINTenvironment variable for testing/staging environments
- Updated Redis configuration in
synchronization.pubsub.redisto useauth_tokeninstead ofpasswordfield (backwards compatible) - CMAB configuration moved from top-level to
client.cmabsection for consistency with other client-related settings (ODP, UPS)
- Improved Redis connection error handling and recovery across all Redis clients
- Added comprehensive test coverage for Redis authentication and CMAB caching
- Added SSE timeout warning in config.yaml to help users configure proper timeouts for notification streams
- Fixed Go module dependencies synchronization to enable successful Docker builds
- Fixed decision notifications not working with secure environment SDK keys
- Added documentation for Redis channel naming pattern in config.yaml
- [FSSDK-10665] fix: Github Actions YAML files vulnerable to script injections corrected by @FarhanAnjum-opti in #425
- [FSSDK-10734] update regex to allow
=character by @pulak-opti in #426 - [FSSDK-10734] update regex to support base64 char for SDK Key & access token by @pulak-opti in #427
- chore(deps): bump golang.org/x/crypto from 0.19.0 to 0.31.0 by @junaed-optimizely in #429
- [FSSDK-11338] Resolve critical SCA prisma alerts by @Mat001 in #430
- [FSSDK-11471] HIGH Dependabot Alerts- Golang/Agent by @Mat001 in #433
- [FSSDK-11452] Agent - netspring integration - experimentID, VariationID by @Mat001 in #438
- Moderate & high CVEs are fixed. (#414,#416)
- Log levels are changed to
Debugand redundant info logs are removed to make/decideAPI call less noisy. (#420) isEveryoneElseVariationfield is added in/decideAPI response. (#422)
The 4.0.0 release introduces a new primary feature, Advanced Audience Targeting enabled through integration with Optimizely Data Platform (ODP) (#356, #364, #365, #366).
You can use ODP, a high-performance Customer Data Platform (CDP), to easily create complex real-time segments (RTS) using first-party and 50+ third-party data sources out of the box. You can create custom schemas that support the user attributes important for your business, and stitch together user behavior done on different devices to better understand and target your customers for personalized user experiences. ODP can be used as a single source of truth for these segments in any Optimizely or 3rd party tool.
With ODP accounts integrated into Optimizely projects, you can build audiences using segments pre-defined in ODP. The SDK will fetch the segments for given users and make decisions using the segments. For access to ODP audience targeting in your Feature Experimentation account, please contact your Optimizely Customer Success Manager.
This version includes the following changes:
-
FetchQualifiedSegments()API has been added to the/decideendpoint. This API will retrieve user segments from the ODP server. The fetched segments will be used for audience evaluation. Fetched data will be stored in the local cache to avoid repeated network delays. -
SendOdpEvent()API has been added with the/send-opd-eventendpoint. Customers can build/send arbitrary ODP events that will bind user identifiers and data to user profiles in ODP.
For details, refer to our documentation pages:
This release also introduces a fundamental enhancement to the agent with the addition of a datafile syncer. This feature is designed to facilitate seamless synchronization of datafiles across agent nodes, ensuring consistency and accuracy in the operation of the webhook API. The datafile syncer uses a PubSub system (Default: Redis) to send updated datafile webhook notification to Agent nodes (in HA system) so that nodes can immediately fetch the latest datafile. (#405)
- ODPManager in the SDK is enabled by default. Unless an ODP account is integrated into the Optimizely projects, most ODPManager functions will be ignored. If needed, ODPManager can be disabled when OptimizelyClient is instantiated. From Agent, it can be switched off from config.yaml or env variables.
- Updated go-sdk version to v2.0.0 with module path github.com/optimizely/go-sdk/v2
- Updated openapi schema to 3.1.0. (#392)
- Added support for prometheus metrics. (#348)
- Github Issue template is udpated. (#396)
- Updated go version to 1.21. (#398)
- Added OpenTelemetry Tracing Support. (#400)
- Added traceID & spanID to logs. (#407)
In previous versions, there was an issue where the Notification API would miss notification events when the Agent was operating in HA mode. It only got notification events from one Agent node. The bug has been addressed in this release with the implementation of a comprehensive solution. A PubSub system (Default: Redis) is used to ensure consistent retrieval of notification events across all nodes in an HA setup. (#399)
- Added support for including
traceIdandspanIdinto the logs. (#407)
-
Added support for Prometheus-based metrics alongside expvar metrics. This can be configured from the config.yaml file. (#348)
-
Added support for OpenTelemetry tracing. Distributed tracing is also supported according to W3C TraceContext. (#400, #401, #402)
The 4.0.0-beta release introduces a new primary feature, Advanced Audience Targeting enabled through integration with Optimizely Data Platform (ODP) (#356, #364, #365, #366).
You can use ODP, a high-performance Customer Data Platform (CDP), to easily create complex real-time segments (RTS) using first-party and 50+ third-party data sources out of the box. You can create custom schemas that support the user attributes important for your business, and stitch together user behavior done on different devices to better understand and target your customers for personalized user experiences. ODP can be used as a single source of truth for these segments in any Optimizely or 3rd party tool.
With ODP accounts integrated into Optimizely projects, you can build audiences using segments pre-defined in ODP. The SDK will fetch the segments for given users and make decisions using the segments. For access to ODP audience targeting in your Feature Experimentation account, please contact your Optimizely Customer Success Manager.
This version includes the following changes:
-
FetchQualifiedSegments()API has been added to the/decideendpoint. This API will retrieve user segments from the ODP server. The fetched segments will be used for audience evaluation. Fetched data will be stored in the local cache to avoid repeated network delays. -
SendOdpEvent()API has been added with the/send-opd-eventendpoint. Customers can build/send arbitrary ODP events that will bind user identifiers and data to user profiles in ODP.
For details, refer to our documentation pages:
- ODPManager in the SDK is enabled by default. Unless an ODP account is integrated into the Optimizely projects, most ODPManager functions will be ignored. If needed, ODPManager can be disabled when OptimizelyClient is instantiated. From Agent, it can be switched off from config.yaml or env variables.
- Update README.md and other non-functional code to reflect that this SDK supports both Optimizely Feature Experimentation and Optimizely Full Stack. (#369).
- Upgrade golang version to
1.20(#357). - Fix an issue with oauth/token API denying client access (#346).
- Minimum required golang version for agent has been upgraded to
1.20to fix vulnerabilities.
- Add support for asynchronous
SaveusingrestUPS by settingasyncboolean value insideconfig.yaml(#350).
- Add
UserProfileServicesupport. Out of the box implementations includein-memory,restandredis. In-memory service supports bothfifoandlifoorders. For details refer to our documentation page: UserProfileService (#326, #331). - Add more detail in documentation for sdk key. (#332)
- Add support to remove sdkKey from logs (#329).
- Update JWT library to
https://github.com/golang-jwt/jwtto fix security warnings since the previous library was no longer maintained (#334).
-
Introduce
Forced Decisionsproperty into thedecideAPI for overriding and managing user-level flag, experiment and delivery rule decisions. Forced decisions can be used for QA and automated testing purposes (#324, #325).- For details, refer to our API documentation page: https://library.optimizely.com/docs/api/agent/v1/index.html#operation/decide.
- Upgrade to use Go SDK v1.8.0. This adds support for Forced Decisions.
- Add new fields (sdkKey, environmentKey, attributes, audiences, events, experimentRules, deliveryRules) to
/configendpoint (PR #322):
-
Introduce
/decideendpoint as a new primary interface for Decide APIs, that is for retrieving feature flag status, configuration and associated experiment decisions for users (#292). -
For details about this Agent release, refer to our documentation page: https://docs.developers.optimizely.com/full-stack/v4.0/docs/optimizely-agent. Upgrade to use Go SDK v1.6.1. This adds support for OptimizelyDecision.
- Add "enabled" field to decision metadata structure
- Introduce Agent interceptor plugins
- Adding support for upcoming application-controlled introduction of tracking for non-experiment Flag decisions
- Update to Optimizely Go SDK 1.4.0 with version audience condition evaluation based on semantic versioning as well as support for number 'greater than or equal to' and 'less than or equal to'.
- For
server.allowedHostsconfiguration property, add support for matching all subdomains of a host, or all hosts - Adding batching for agent (/v1/batch endpoint), including requests in parallel
- Removed vulnerable version coreos/etcd
- Add SDK key validation configuration
- Reject request with invalid host (excluding port)
- Block content type other than application/json
- Introducing support for authenticated datafiles
- Reject requests with invalid hosts, and introduce
server.allowedHostsconfiguration property - Agent will now reject the request if the content-type is not specified from the clients
- Add Host as a configurable item
- Previously, Agent was listening on all interfaces, and did not allow configuring the network interface that it listens on. NewServer allowed specification of a port to listen on, but not an address.
- Now, we have added configurable HOST, with the default value set to the localhost (127.0.0.1)
- If there is a need to deploy Agent in docker, then the Host needs to be set to 0.0.0.0. This can be achieved by setting variable
OPTIMIZELY_SERVER_HOST=0.0.0.0, or settingserver.hostto 0.0.0.0 in config file.
- Upgrade to use go-sdk v1.3.0. This adds support for JSON feature variables
- Add /debug/pprof endpoints to the admin service
- Run docker container as non root user
- Log warnings when HTTPS and authorization are not enabled via configuration
- Expose event dispatch URL as a config parameter
- Return experimentKey and variationKey with feature test decisions
- Expose health endpoint for all listeners
- Update API docs
- Streamline CI stages
- Upgrade to use go-sdk 1.2.0. This adds support for multi-rule rollouts.
- Add datafileURLTemplate configuration option
- Update to use go-sdk 1.1.3. This has a fix to the batch event processor was creating a dispatcher without a logger.
- Update documentation and examples
- Add response body for override and track
- Add userId in /activate response
- Require userId in /activate request
- Add python integration test suite
- Add route handler and serve /openapi.yaml
- Improve logging from the SDK
- Update windows build script
- Remove pre-v1 api references
- Allow unknown keys in /activate request
- Improve API token issuer and auth client config
- Expand on example python scripts and general documentation
- Add ability to blacklist TLS ciphers
- Disable notifications and overrides by default
- Update misc items in swagger spec
- Improve README and add auth examples
- Update SDK client config namespace
- Add support for JWKS URI
- Add OAuth to swagger spec
- Add client secret creation tool
- Add support for typed user attributes
- Add event-stream API for notifications
- Add basic client credentials grant flow
- Add native TLS support via configuration
- Refactor to a POST based action API
- Bump to 1.0.0-rc1@d1b332c of the Optimizely go-sdk
- Improve build tooling
- Add standard metrics registry
- Update documentation
- Return 404 when feature or experiment are not found
- Update event payloads to include Agent name and version
- Rename repo to optimizely/agent and update imports
- Improve CI builds for Windows and SourceClear
- Major /pkg refactoring
- Exclude vulnerabilities identified through SourceClear
- Capture response time metrics in milliseconds
- Bump to 1.0.0-rc1@d1b332c of the Optimizely go-sdk
- Add metric visibility into event dispatcher
- Miscellaneous clean-up and of docs and openapi spec
- Add top level config package to consolidate configuration
- Incorporate OptimizelyConfig into feature and experiment models
- Add get experiment and list experiment endpoints
- Add user features endpoint for batched decision responses
- Add windows tooling
- Add credit section to README
- Improve service shutdown
- Bump to 1.0.0-rc1@973644b of the Optimizely go-sdk
- Update test harness with new interface
- Adds ability to limit the number of active api connections
- Allows SDK keys to be bootstrapped during startup
- Adds http server timeouts
- Adds graceful shutdown hooks
- Adds support for forced variation API
- Adds support for experimentation APIs
- Adds request timing metrics
- Allows config file location to be set
- Bumps go-sdk version to latest master
- Adds a few more debug logs
- Updates to latest master to resolve some targeting issues
- Update make clean to clean mod cache
- Actually enable the impression tracking endpoint in the router
- Adds GET endpoint for user-based features
- Adds impression tracking for Feature Tests
- Adds admin endpoints for health, info and metrics
- Adds requestId to logs and response header
- Improves log integration with Optimizely SDK
- Updates swagger spec to match current server implementation
- Updates dependency version for the Optimizely SDK
- Enhance webhook service configurability
- Adds user centric API routes
- Introduces spf13/viper based configuration
- Adds OptlyContext middleware
- Adds webhook support for multiple concurrent SDK keys
- Adds Optimizely webhook support
- Adds full Feature MGMT support
- Adds NSQ for UserEvent message transport
- Adds support for multiple concurrent SDK keys
This is the initial release which supported a basic web application and go-sdk integration.