-
Notifications
You must be signed in to change notification settings - Fork 2
ExperienceManager
Welcome back! In Chapter 2: Context, we saw how the Context object acts as a personal guide for each visitor. When we wanted to know which headline variation 'user123' should see in our A/B test, we called visitorContext.runExperience('headline-test'). We learned that the Context object doesn't make this decision itself; it delegates the task to a specialist.
Let's meet that specialist: the ExperienceManager.
Imagine you're running multiple A/B tests (which we call "experiences" in Convert):
- A headline test on the homepage.
- A button color test on the pricing page.
- A special promotion shown only to users from Canada.
When a visitor like 'user123' navigates your site, how does the SDK ensure they get the correct variation for each relevant experiment? How does it know:
- Which experiences are even active?
- Does 'user123' meet the specific targeting rules for each experience (e.g., "only for users from Canada")?
- If they qualify, which variation (A or B) should they consistently see based on the traffic distribution (e.g., 50% see A, 50% see B)?
Managing all this decision logic for just the A/B tests requires a dedicated component.
Think of the ExperienceManager as the Director specifically focused on running your A/B tests (experiences). While the ConvertSDK is the overall conductor, and the Context is the personal guide for a visitor, the ExperienceManager is the expert who knows all about the different A/B test "scenes" being filmed.
Its main jobs are:
-
Knowing the Script: It can tell you about all the active experiences (using
getList()) or give you details about a specific one (getExperience(key)). -
Casting the Role: Its most crucial job is deciding which variation a specific visitor should see for a particular experience. This involves checking rules and splitting traffic fairly. This is done via the
selectVariation()method. -
Collaborating with Specialists: The ExperienceManager doesn't do everything alone! To make the final decision in
selectVariation(), it relies heavily on other managers:- DataManager: To get the details of the experience and its rules.
- RuleManager: To check if the visitor meets the targeting conditions (handled via DataManager).
- BucketingManager: To assign the visitor to a variation based on traffic allocation (also handled via DataManager).
So, ExperienceManager directs the A/B test, but it uses the DataManager as its primary assistant, which in turn consults with the RuleManager and BucketingManager.
As a developer using the SDK, you will rarely interact directly with the ExperienceManager. Why? Because the Context object handles it for you!
Remember this code from Chapter 2?
// 'visitorContext' is the Context object for 'user123'
const experienceKey = 'headline-test';
// Ask the context which variation 'user123' should see
const decision = visitorContext.runExperience(experienceKey);
console.log(decision); // e.g., { experienceKey: 'headline-test', key: 'variation-B', ... }When you call visitorContext.runExperience(), the Context object internally turns around and asks the ExperienceManager: "Hey, can you please figure out the variation for 'user123' in the 'headline-test' experience?"
Specifically, the Context calls the ExperienceManager's selectVariation() method, passing along the visitor's ID, the experience key, and any relevant visitor properties.
So, while ExperienceManager is doing the heavy lifting for choosing A/B test variations, you trigger its work through the convenient methods on the Context object.
Let's peek behind the curtain. What happens when the Context calls experienceManager.selectVariation('user123', 'headline-test', { ...attributes })?
-
Delegation to DataManager: The first thing the
ExperienceManagerdoes inside itsselectVariationmethod is immediately delegate the task to the DataManager. It calls something likedataManager.getBucketing('user123', 'headline-test', { ...attributes }). - DataManager Orchestrates: The DataManager takes over. It fetches the definition of the 'headline-test' experience (including variations, traffic split, and targeting rules).
- Rule Checking: The DataManager uses the RuleManager to check if 'user123' (with their attributes) matches the targeting rules defined for 'headline-test'. If not, the process stops here, and an error indicating the visitor didn't qualify is returned.
- Bucketing: If the rules pass, the DataManager uses the BucketingManager to determine which variation ('variation-A' or 'variation-B') 'user123' should see, based on their ID and the traffic distribution percentages set for the experiment. This ensures the visitor consistently sees the same variation.
-
Result Returned: The DataManager returns the result (either the chosen variation object or a rule/bucketing error) back to the
ExperienceManager. -
Final Pass-Through: The
ExperienceManagersimply passes this result back to theContextobject, which then returns it to your originalrunExperiencecall.
Here's a simplified diagram showing the flow:
sequenceDiagram
participant Context as Visitor Context
participant ExpManager as ExperienceManager
participant DataManager as DataManager
participant RuleManager as RuleManager
participant BucketManager as BucketingManager
Context->>ExpManager: selectVariation('user123', 'headline-test', {...})
activate ExpManager
ExpManager->>DataManager: getBucketing('user123', 'headline-test', {...})
activate DataManager
Note right of DataManager: Fetches experience data
DataManager->>RuleManager: Check rules for 'user123' against 'headline-test' rules
activate RuleManager
RuleManager-->>DataManager: Rules Pass/Fail
deactivate RuleManager
alt Rules Pass
DataManager->>BucketManager: Determine variation for 'user123' based on traffic split
activate BucketManager
BucketManager-->>DataManager: Return chosen variation (e.g., 'variation-B')
deactivate BucketManager
DataManager-->>ExpManager: Return variation object
else Rules Fail
DataManager-->>ExpManager: Return RuleError
end
deactivate DataManager
ExpManager-->>Context: Return variation object or error
deactivate ExpManager
As you can see, ExperienceManager acts primarily as an entry point that quickly hands off the complex logic to the DataManager, which coordinates the rule checking and bucketing specialists.
Code Peek:
Let's look at the actual ExperienceManager code to confirm this.
1. The Constructor (experience-manager.ts)
The constructor mainly just stores a reference to the DataManager it needs.
// File: packages/experience/src/experience-manager.ts (Simplified)
import {DataManagerInterface} from '@convertcom/js-sdk-data';
// ... other imports ...
export class ExperienceManager implements ExperienceManagerInterface {
private _dataManager: DataManagerInterface; // Stores the DataManager
private _loggerManager: LogManagerInterface | null;
constructor(
config: Config,
{ dataManager, loggerManager }: { // Receives managers
dataManager: DataManagerInterface;
loggerManager?: LogManagerInterface;
}
) {
// Store the DataManager for later use
this._dataManager = dataManager;
this._loggerManager = loggerManager;
// ... logging ...
}
// ... other methods ...
}- It receives the
DataManager(and potentially others likeLoggerManager) when it's created by the main SDK Core. - It stores
dataManagerinthis._dataManager.
2. The selectVariation Method (experience-manager.ts)
This method directly calls the DataManager to do the real work.
// File: packages/experience/src/experience-manager.ts (Simplified)
// Inside the ExperienceManager class:
selectVariation(
visitorId: string,
experienceKey: string,
attributes: BucketingAttributes
): BucketedVariation | RuleError | BucketingError {
// === The Core Delegation ===
// Immediately ask the DataManager to handle bucketing
return this._dataManager.getBucketing(
visitorId,
experienceKey,
attributes
);
}- That's it! The
ExperienceManager'sselectVariationmethod just callsthis._dataManager.getBucketingwith the exact same arguments it received. It acts as a pass-through for this core function.
3. Other Helper Methods (experience-manager.ts)
Methods like getExperience or getList also rely on the DataManager to retrieve information.
// File: packages/experience/src/experience-manager.ts (Simplified)
// Inside the ExperienceManager class:
// Get details of a specific experience by its key
getExperience(key: string): ConfigExperience {
// Asks DataManager to find the entity named 'key' in the 'experiences' list
return this._dataManager.getEntity(key, 'experiences') as ConfigExperience;
}
// Get a list of all experiences
getList(): Array<ConfigExperience> {
// Asks DataManager for the entire list of 'experiences'
return this._dataManager.getEntitiesList('experiences') as Array<ConfigExperience>;
}- These methods simply ask the DataManager to look up and return the requested data about experiences.
The ExperienceManager is the dedicated component within the Convert SDK responsible for managing A/B tests (experiences). While you typically interact with it indirectly via the Context object's runExperience method, it plays a vital role behind the scenes.
You've learned that:
-
ExperienceManageracts as the "Director" for A/B tests. - Its main job is to select the correct variation for a visitor using
selectVariation. - It achieves this by delegating heavily to the DataManager, which coordinates with the RuleManager and BucketingManager.
- Methods like
getExperienceandgetListallow access to experience configuration data, again via the DataManager.
ExperienceManager handles the complexity of A/B testing variations. But what if you don't need multiple variations? What if you just want to turn a feature on or off for certain users, or gradually roll out a new feature? For that, we have another specialist.
Let's explore how the SDK handles feature flags in the next chapter: Chapter 4: FeatureManager!
Copyrights © 2025 All Rights Reserved by Convert Insights, Inc.
Core Modules
- ConvertSDK / Core
- Context
- ExperienceManager
- FeatureManager
- DataManager
- BucketingManager
- RuleManager
- ApiManager
- EventManager
- Config / Types
Integration Guides