Skip to content

feat: POC for supporting Optimizely fullstack / feature experimentation allocations#21

Closed
patrick-wu wants to merge 1 commit intodevelopmentfrom
feat/optimizely-fs-fe-support
Closed

feat: POC for supporting Optimizely fullstack / feature experimentation allocations#21
patrick-wu wants to merge 1 commit intodevelopmentfrom
feat/optimizely-fs-fe-support

Conversation

@patrick-wu
Copy link
Collaborator

@patrick-wu patrick-wu commented Apr 10, 2025

Summary

Adding support for Optimizely Full Stack / Feature Experimentation as 3rd party experimentation platforms we can integrate with.

This is more complex than Optimizely Web because unlike OW, the Full Stack / Feature Exp SDK does not keep the state of the current session's allocation.

Instead, it can guarantee to return consistent allocation, GIVEN an 'ID' and any additional optional attribute for consistent hashing / allocation, which mean the complexity now is we'll need to pass in the allocation ID and attributes into the selectPlacement call somehow.

Solution Presented in POC

We pass these things in with specific keys that we look for, use them to generate allcoations, and remove them from the filteredAttributes object before passing it to the selectPlacement call.

Testing Plan

{explain how this has been tested, and what additional testing should be done}

@patrick-wu patrick-wu changed the base branch from main to development April 10, 2025 17:35
@patrick-wu patrick-wu changed the title POC for supporting fullstack / feature-exp allocations feat: POC for supporting Optimizely fullstack / feature experimentation allocations Apr 10, 2025
Comment on lines +133 to +155
userId = filteredAttributes['optimizely.userId'];
attributes = Object.keys(filteredAttributes)
.filter(function (key) {
return key.indexOf('optimizely.attributes') === 0;
})
.reduce(function (obj, key) {
obj[key] = filteredAttributes[key];
return obj;
}, {});

// Remove all optimizely.* keys from filteredAttributes
filteredAttributes = Object.keys(filteredAttributes)
.filter(function (key) {
return key.indexOf('optimizely.') !== 0;
})
.reduce(function (obj, key) {
obj[key] = filteredAttributes[key];
return obj;
}, {});
experimentAttributes = fetchOptimizelyFeatureExpAllocations(
userId,
attributes
);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically, for Optimizely Full Stack / Feature Experimentation, you need to pass in the user information (an ID, plus whatever additional attributes) to the SDK when trying to retrieve the bucketing information of the current user.

This kind of strategy is stateless (i.e. it doesn't keep track of what the allocation is) but idempotent, so we have to somehow pass in the user ID + attributes used when deciding

});

if (forwarders.length > 0 && window.optimizelyClient) {
var user = window.optimizelyClient.createUserContext(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do an additional check like && window.optimizelyClient.hasOwnProperty('createUserContext') just in case different versions of optimizely do or don't have this method. and put a try/catch block around it

userId,
attributes
);
var config = window.optimizelyClient.getOptimizelyConfig();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment regarding this one. check for window.optimizelyClient.hasOwnProperty('getOptimizelyConfig')

var selectPlacementsAttributes = mergeObjects(
filteredAttributes,
optimizelyAttributes,
experimentAttributes,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice in https://docs.rokt.com/developers/integration-guides/rokt-ads/web-sdk/attributes/#core-attributes that all attributes are strings, numbers, and not more complex types like dictionaries. should the value be stringified?


module.exports = {
register: register,
OnboardingExpProvider: OnboardingExpProvider,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this necessary? If it's only necessary for the tests, I think you can just duplicate the values in the test itself.

This is generally just used for an end developer to use.

Copy link
Collaborator

@rmi22186 rmi22186 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple of small suggestions. Also can you add a test for when OPTIMIZELY_FEATURE_EXP. There's a lot of complicated logic in here, so it's hard to know if it works or not and it's unclear what optimizely will return. You'll have to mock mParticle._getActiveForwarders, as well as a few optimizely methods that you are using. let me know if you need help with this and we can book like 15-30 min.

@patrick-wu
Copy link
Collaborator Author

closing this one as we've aligned on the other approach with the Rokt Manager

@patrick-wu patrick-wu closed this Apr 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants