Skip to content

Fix/optimizely personalization campaign#1463

Open
James Shebester (JamesShebester) wants to merge 2 commits intosnowplow:masterfrom
JamesShebester:fix/optimizely-personalization-campaign-id
Open

Fix/optimizely personalization campaign#1463
James Shebester (JamesShebester) wants to merge 2 commits intosnowplow:masterfrom
JamesShebester:fix/optimizely-personalization-campaign-id

Conversation

@JamesShebester
Copy link
Copy Markdown

Summary

Fixes #1462

Replaces getActiveExperimentIds() with getCampaignStates({ isActive: true }) in getOptimizelyXSummary() to correctly capture campaignId for Optimizely Personalization campaigns.

Problem

The existing implementation uses two Optimizely state API calls that
bypass the campaign layer entirely:

// Before — misses campaignId completely
var experiment_ids = state.getActiveExperimentIds() || [];
var variationMap = state.getVariationMap();

For Optimizely Personalization campaigns, getActiveExperimentIds()
surfaces experience IDs (the sub-unit inside a campaign) but never
exposes the parent campaignId (layerId). This means campaignId
was never captured in Snowplow event data — not as null, not as empty — it simply did not exist in the schema output.

Solution

getCampaignStates({ isActive: true }) returns a unified state object
for both Web Experimentation and Personalization campaigns, where the
top-level key is the campaignId:

// After — correctly captures campaignId for all campaign types
const campaignStates = state.getCampaignStates({ isActive: true }) || {};

return Object.keys(campaignStates).map((campaignId: string) => {
  const campaign = campaignStates[campaignId];
  return {
    campaignId: parseAndValidateInt(campaignId) || null,
    experimentId: parseAndValidateInt(campaign.experiment?.id) || null,
    variationName: campaign.variation?.name?.toString() || null,
    variation: parseAndValidateInt(campaign.variation?.id) || null,
    visitorId: visitorId,
  };
});

Behavior by Campaign Type

Field Web Experimentation Personalization
campaignId layerId (auto-generated wrapper) layerId of the campaign
experimentId experimentId experienceId (sub-unit of campaign)
variation variationId variationId

Changes

  • src/index.ts — replaced getActiveExperimentIds() + getVariationMap()
    with getCampaignStates({ isActive: true }), moved visitorId resolution
    outside the loop, updated schema reference to 1-1-0
  • src/contexts.ts — added campaignId?: number | null to
    OptimizelyxSummary interface

Schema

This change requires a new schema version
iglu:com.optimizely.optimizelyx/summary/jsonschema/1-1-0 with campaignId
added as an optional integer field. This is a minor version bump
(1-0-01-1-0) as the addition is backward compatible — existing events without campaignId remain valid.

Testing

Verified in browser console against a live Optimizely Personalization
campaign:

optimizely.get('state').getCampaignStates({ isActive: true })
// Returns campaignId, experiment.id, variation.id, and variation.name 
// correctly for both Personalization and Web Experimentation campaigns

…campaign

getActiveExperimentIds() does not surface campaignId (layerId) for
   Optimizely Personalization campaigns. Switching to getCampaignStates()
   correctly captures the campaign layer for both Web Experimentation
   and Personalization campaigns. Also adds campaignId to OptimizelyxSummary
   interface and bumps schema reference to 1-1-0.
@snowplowcla
Copy link
Copy Markdown

Thanks for your pull request. Is this your first contribution to a Snowplow open source project? Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://docs.snowplowanalytics.com/docs/contributing/contributor-license-agreement/ to learn more and sign.

Once you've signed, please reply here (e.g. I signed it!) and we'll verify. Thanks.

@snowplowcla Snowplow CLA bot (snowplowcla) added the cla:no [Auto generated] Snowplow Contributor License Agreement has not been signed. label Mar 26, 2026
@JamesShebester
Copy link
Copy Markdown
Author

@snowplowcla
Copy link
Copy Markdown

Confirmed! James Shebester (@JamesShebester) has signed the Contributor License Agreement. Thanks so much.

@snowplowcla Snowplow CLA bot (snowplowcla) added cla:yes [Auto generated] Snowplow Contributor License Agreement has been signed. and removed cla:no [Auto generated] Snowplow Contributor License Agreement has not been signed. labels Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla:yes [Auto generated] Snowplow Contributor License Agreement has been signed.

Development

Successfully merging this pull request may close these issues.

bug: browser-plugin-optimizely-x does not capture campaignId for Optimizely Personalization campaigns

2 participants