-
Notifications
You must be signed in to change notification settings - Fork 2
Context
Welcome back! In Chapter 1: ConvertSDK / Core, we learned how to initialize the main ConvertSDK
object – our orchestra conductor. We finished by creating a special object for a single website visitor using convert.createContext(visitorId, visitorAttributes)
.
But what is this Context
object, and what can we do with it? Let's find out!
Imagine your website is like a busy theme park. The ConvertSDK
object is the park management – it knows about all the rides (experiments) and attractions (features). However, park management doesn't interact directly with every single visitor.
When a visitor arrives ('user123' lands on your homepage), you need a way to:
- Identify them uniquely: Know this is 'user123'.
- Give them the right experience: If you're testing two different welcome messages (A/B test), ensure 'user123' consistently sees one version throughout their visit.
- Track their actions: If 'user123' signs up after seeing a specific welcome message, you need to record that success for that specific message and that specific user.
How do you manage all this personalized information and interaction for just one visitor among potentially thousands?
The Context
object is the answer! Think of it as a personalized guide and wristband given to each visitor when they enter your theme park (website).
-
Identification: The guide knows the visitor's unique ID (
visitorId
). - Personalization: It keeps track of which specific version of an experiment (like which welcome message) the visitor should see.
- Interaction Point: You use this guide to ask questions like "Which experiment variation should this visitor see?" or to tell it "This visitor just completed a goal!".
-
State: It can hold information about the visitor (like
browser: 'chrome'
orcountry: 'USA'
) which might influence which experiments or features they are eligible for.
Every action you perform using a specific Context
object is tied directly to the visitorId
it was created with. If you create one Context
for 'user123' and another for 'visitor456', their activities remain separate and personalized.
Let's go back to the A/B test from Chapter 1: testing two headlines ('headline-A' vs. 'headline-B') to see which gets more sign-ups. We already initialized the SDK and created a context for 'user123'.
// Remember from Chapter 1:
// 'convert' is the initialized ConvertSDK instance
// 'visitorContext' is the Context object for 'user123'
const visitorContext = convert.createContext('user123', { device: 'mobile' });
// Now, let's use the context!
// Assume your headline A/B test is called 'headline-test' in Convert
const experienceKey = 'headline-test';
// Ask the context which variation 'user123' should see
const decision = visitorContext.runExperience(experienceKey);
console.log(decision);
-
visitorContext.runExperience(experienceKey)
is the core action here. We're asking the personal guide (visitorContext
) which specific variation of the'headline-test'
ride this visitor (user123
) should experience. -
experienceKey
: This is the unique identifier for your experiment (you set this up in your Convert account).
What does runExperience
give back?
It usually returns a small object describing the variation the visitor should see. It might look something like this (simplified):
// Example possible output for 'decision':
{
"experienceKey": "headline-test",
"key": "variation-B", // The ID of the chosen variation
"id": "10023457", // Convert ID for the variation
"status": "running",
// ... other details
}
This tells you that for user123
, the SDK decided they should see variation-B
(maybe this corresponds to your second headline). Now your website code can use this information to display the correct headline.
If something goes wrong (e.g., the experience key doesn't exist, or the visitor doesn't qualify for the experiment based on rules), runExperience
might return an error code instead.
Other Context Actions:
The Context
object isn't just for A/B tests. You'll use it for other common tasks too:
-
runFeature(featureKey, attributes)
: Checks if a feature flag is enabled for this visitor and gets its details. (FeatureManager handles the logic). -
trackConversion(goalKey, attributes)
: Records that this visitor completed a specific goal (like clicking a sign-up button). (DataManager helps store this). -
runExperiences(attributes)
: Runs all active experiments the visitor qualifies for at once. -
runFeatures(attributes)
: Checks all relevant feature flags for the visitor.
All these methods work similarly: you call them on the specific visitor's Context
object, and the action is tied to that visitor's ID.
When you call visitorContext.runExperience('headline-test')
, what happens inside the SDK?
-
Check Visitor ID: The
Context
object confirms it has a validvisitorId
('user123'). -
Gather Properties: It looks at the visitor's properties. This includes properties provided when creating the context (like
{ device: 'mobile' }
) and potentially other stored properties for this visitor that the SDK might know about (managed by the DataManager). It also includes any temporary properties you might pass directly torunExperience
. -
Delegate to ExperienceManager: The
Context
itself doesn't decide the variation. It passes thevisitorId
, theexperienceKey
('headline-test'), and all the gathered properties to the ExperienceManager. - ExperienceManager Decides: The ExperienceManager is the specialist. It checks if the experiment exists, if it's running, if the visitor meets any targeting rules (like "only show to mobile users"), and then uses a process called "bucketing" (managed by the BucketingManager) to consistently assign the visitor to a variation.
-
Return Result: The ExperienceManager sends the result (the chosen variation details or an error) back to the
Context
. -
Fire Event (Optional): The
Context
might notify other parts of the system that a bucketing decision was made by firing an event using the EventManager. This is useful for logging or integrations. -
Return to You: The
Context
returns the final result (the variation object or error) to your code.
Here's a simplified diagram:
sequenceDiagram
participant YourCode as Your Website Code
participant Context as Visitor Context ('user123')
participant ExpManager as ExperienceManager
participant DataManager as DataManager
participant EventManager as EventManager
YourCode->>+Context: runExperience('headline-test')
Context->>+DataManager: Get stored properties for 'user123'
DataManager-->>-Context: Return properties (e.g., {})
Note over Context: Combine with initial properties (e.g., {device: 'mobile'})
Context->>+ExpManager: selectVariation('user123', 'headline-test', {device: 'mobile'})
Note right of ExpManager: Checks rules, performs bucketing...
ExpManager-->>-Context: Return variation object (e.g., variation-B)
Context->>+EventManager: fire(BUCKETING, {details...})
EventManager-->>-Context: Context-->>-YourCode: Return variation object
Code Peek:
Let's look at simplified snippets from the SDK's context.ts
file.
1. The Constructor (context.ts
)
When convert.createContext()
is called, it runs this constructor to set up the Context
object.
// File: packages/js-sdk/src/context.ts (Simplified)
export class Context implements ContextInterface {
private _visitorId: string;
private _visitorProperties: Record<string, any>;
private _experienceManager: ExperienceManagerInterface; // Will use this!
private _featureManager: FeatureManagerInterface;
private _dataManager: DataManagerInterface; // Will use this!
private _eventManager: EventManagerInterface; // Will use this!
// ... other managers and properties
constructor(
config: Config,
visitorId: string,
managers: { // SDK passes all needed managers
eventManager: EventManagerInterface;
experienceManager: ExperienceManagerInterface;
featureManager: FeatureManagerInterface;
dataManager: DataManagerInterface;
// ... other managers
},
visitorProperties?: Record<string, any> // e.g., { device: 'mobile' }
) {
this._visitorId = visitorId; // Store the visitor's ID
this._visitorProperties = visitorProperties || {}; // Store initial properties
// Store references to the managers passed in
this._experienceManager = managers.experienceManager;
this._featureManager = managers.featureManager;
this._dataManager = managers.dataManager;
this._eventManager = managers.eventManager;
// ...
}
// ... methods like runExperience, runFeature, etc. ...
}
- The constructor simply stores the
visitorId
, any initialvisitorProperties
, and references to all the helper managers it needs to delegate tasks to.
2. The runExperience
Method (context.ts
)
This is the method called when you write visitorContext.runExperience(...)
.
// File: packages/js-sdk/src/context.ts (Simplified)
// Inside the Context class:
runExperience(
experienceKey: string,
attributes?: BucketingAttributes // Optional extra attributes
): BucketedVariation | RuleError | BucketingError {
if (!this._visitorId) {
// Handle error: Visitor ID is missing
return; // Simplified error handling
}
// Combine stored properties with any temporary ones from 'attributes'
const visitorProperties = this.getVisitorProperties(
attributes?.visitorProperties
); // Uses _visitorProperties and DataManager
// === The Core Delegation ===
// Ask ExperienceManager to figure out the variation
const bucketedVariation = this._experienceManager.selectVariation(
this._visitorId,
experienceKey,
{
visitorProperties: visitorProperties, // Pass combined properties
locationProperties: attributes?.locationProperties, // Pass location info if any
// ... other options
}
);
// Check if the result is an error (RuleError, BucketingError)
if (/* result is an error */) {
return bucketedVariation; // Return the error
}
// If successful, fire an event (optional step)
if (bucketedVariation) {
this._eventManager.fire(
SystemEvents.BUCKETING, // Type of event
{ // Event details
visitorId: this._visitorId,
experienceKey: experienceKey,
variationKey: (bucketedVariation as BucketedVariation).key
}
);
}
// Return the successful result (the variation object)
return bucketedVariation as BucketedVariation;
}
// Helper method to combine properties (simplified)
private getVisitorProperties(newAttributes?: Record<string, any>): Record<string, any> {
const storedProperties = this._dataManager.getData(this._visitorId)?.segments || {};
const initialProperties = this._visitorProperties || {};
// Merge stored, initial, and new properties (simplified logic)
return { ...storedProperties, ...initialProperties, ...(newAttributes || {}) };
}
- It first checks for the
visitorId
. - It calls
getVisitorProperties
which merges any properties passed now (attributes
) with properties provided initially and potentially others stored by the DataManager. - The key step is
this._experienceManager.selectVariation(...)
, where it delegates the actual decision-making. - It fires a
BUCKETING
event via the EventManager on success. - Finally, it returns the result from the ExperienceManager.
The Context
object is your primary tool for interacting with the Convert SDK on behalf of a single visitor. It acts as a personal guide, holding the visitor's ID and properties, and providing methods like runExperience
, runFeature
, and trackConversion
. Every action taken through a Context
is tied specifically to that visitor, enabling personalized experiences and accurate tracking.
You now understand:
- Why
Context
is necessary for managing individual user sessions. - What the
Context
object represents (a visitor's personal guide). - How to use
context.runExperience()
to get the correct A/B test variation for a visitor. - That
Context
delegates the complex decision-making logic to specialized managers like the ExperienceManager.
We saw that Context
relies heavily on the ExperienceManager to actually choose the variation in runExperience
. How does that manager work its magic? Let's explore that in the next chapter!
Ready to learn more? Head over to Chapter 3: ExperienceManager!
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