Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8ee986f
Merge branch 'latest' of ssh://github.com/bbc/simorgh into latest
louisearchibald Mar 18, 2026
37a69f6
Merge branch 'latest' of ssh://github.com/bbc/simorgh into latest
louisearchibald Mar 26, 2026
6165b2c
Merge branch 'latest' of ssh://github.com/bbc/simorgh into latest
louisearchibald Mar 31, 2026
ac8ab21
add notification listener to optimizely page metrics file
louisearchibald Mar 31, 2026
bfc3927
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 7, 2026
c9e02c1
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely' of ssh://gi…
louisearchibald Apr 7, 2026
842a8b4
add optimizely-sdk as a dependency
louisearchibald Apr 7, 2026
3c90e5c
Revert "add optimizely-sdk as a dependency"
louisearchibald Apr 7, 2026
66c9b86
add optimizely-sdk as a dependency
louisearchibald Apr 7, 2026
7fde059
change version
louisearchibald Apr 7, 2026
9d72a6d
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
LilyL0u Apr 7, 2026
c7f6a58
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 8, 2026
284abce
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 8, 2026
d93ce11
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 8, 2026
797d85c
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely' of ssh://gi…
louisearchibald Apr 8, 2026
412040c
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 8, 2026
4c4291d
adds unit tests to test new behaviour
louisearchibald Apr 8, 2026
762c4d7
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely' of ssh://gi…
louisearchibald Apr 8, 2026
06074e2
fix import
louisearchibald Apr 8, 2026
086ecc4
[copilot] refactor OptimizelyPageMetrics notification listener to use…
HarveyPeachey Apr 9, 2026
1333648
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 15, 2026
984909f
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely' into WS-228…
louisearchibald Apr 15, 2026
ee0ead9
update bundlesize
louisearchibald Apr 15, 2026
c10fdb2
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely-alt' of ssh:…
louisearchibald Apr 15, 2026
15287eb
fix failing test
louisearchibald Apr 15, 2026
42776ab
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 15, 2026
1ae0def
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely' into WS-228…
louisearchibald Apr 15, 2026
5752d57
update test names
louisearchibald Apr 15, 2026
4bf04c9
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely-alt' of ssh:…
louisearchibald Apr 15, 2026
a0691bd
input test experiment details
louisearchibald Apr 15, 2026
cfa1854
addresses PR comment by adding optional chaining to decisionInfo
louisearchibald Apr 16, 2026
758385d
adds experiment name to activeExperiments array for article pages
louisearchibald Apr 16, 2026
9c5c87f
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 16, 2026
a8611b5
skip time of day test
louisearchibald Apr 17, 2026
c0baa66
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
louisearchibald Apr 17, 2026
48edf01
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely' into WS-228…
louisearchibald Apr 17, 2026
e1a3cad
Merge branch 'WS-2284-fix-lost-view-events-in-optimizely-alt' of ssh:…
louisearchibald Apr 17, 2026
482e58a
whitespace
louisearchibald Apr 17, 2026
a0a6c55
bundle size
louisearchibald Apr 17, 2026
fe65d79
whitespace
louisearchibald Apr 17, 2026
48ebcb0
Revert "whitespace"
louisearchibald Apr 17, 2026
ca687cc
Merge branch 'latest' into WS-2284-fix-lost-view-events-in-optimizely
LilyL0u Apr 20, 2026
8dc9571
Merge pull request #13893 from bbc/WS-2284-fix-lost-view-events-in-op…
LilyL0u Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"@emotion/styled": "11.14.1",
"@loadable/component": "5.16.7",
"@loadable/server": "5.16.7",
"@optimizely/optimizely-sdk": "5.4.1",
"@optimizely/react-sdk": "3.3.1",
"aws-embedded-metrics": "4.2.0",
"compression": "1.8.1",
Expand Down
139 changes: 113 additions & 26 deletions src/app/components/OptimizelyPageMetrics/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
OptimizelyContext,
OptimizelyDecideOption,
} from '@optimizely/react-sdk';
import { enums } from '@optimizely/optimizely-sdk';
import { RequestContext } from '#contexts/RequestContext';
import PageCompleteTracking from './PageCompleteTracking';
import ScrollDepthTracking from './ScrollDepthTracking';
Expand All @@ -16,6 +17,16 @@ type Props = {
trackVisit?: boolean;
};

// Shape expected by the Optimizely decision notification listener for decision events
type DecisionListener = {
userId?: string;
type?: string;
decisionInfo?: {
flagKey?: string;
variationKey?: string;
};
};

const OptimizelyPageMetrics = ({
trackPageView = false,
trackPageDepth = false,
Expand All @@ -24,43 +35,119 @@ const OptimizelyPageMetrics = ({
}: Props) => {
const { optimizely } = useContext(OptimizelyContext);
const { isAmp, pageType } = useContext(RequestContext);
const [isInExperiment, setisInExperiment] = useState(false);
const [isInExperiment, setIsInExperiment] = useState(false);

const experimentsForPageType = experimentsForPageMetrics.find(
entry => entry.pageType === pageType,
)?.activeExperiments;

const optimizelyExperimentsEnabled =
experimentsForPageType && !isAmp && !isInExperiment;
const optimizelyExperimentsEnabled = Boolean(
experimentsForPageType?.length && !isAmp,
);

// on initial load, check if the user is in any relevant experiment and set state accordingly
useEffect(() => {
if (
!optimizelyExperimentsEnabled ||
!optimizely ||
!experimentsForPageType
) {
setIsInExperiment(false);
return undefined;
Comment thread
louisearchibald marked this conversation as resolved.
Outdated
}
Comment thread
louisearchibald marked this conversation as resolved.
Outdated

let mounted = true;

optimizely.onReady().then(() => {
Comment thread
louisearchibald marked this conversation as resolved.
Outdated
if (!mounted) return;

// disable decision event tracking to avoid sending duplicate events for any experiments that the user is bucketed into on page load, since the notification listener will also trigger for those experiments
const decisions = optimizely.decideAll([
OptimizelyDecideOption.DISABLE_DECISION_EVENT,
]);

const userInAnyExperiment = experimentsForPageType.some(
experimentName => {
const decision = decisions[experimentName];
return Boolean(decision && decision.variationKey !== 'off');
},
);

setIsInExperiment(userInAnyExperiment);
});

return () => {
mounted = false;
};
}, [optimizelyExperimentsEnabled, optimizely, experimentsForPageType]);

// Listen for Optimizely decisions after initial load in case the user is bucketed later
useEffect(() => {
if (optimizelyExperimentsEnabled) {
optimizely?.onReady().then(() => {
const decisions = optimizely.decideAll([
OptimizelyDecideOption.DISABLE_DECISION_EVENT,
]);
const isUserInAnyExperiments = experimentsForPageType.some(
experimentName => {
const decision = decisions[experimentName];
return decision && decision.variationKey !== 'off';
if (
!optimizelyExperimentsEnabled ||
!optimizely ||
!experimentsForPageType
) {
setIsInExperiment(false);
return undefined;
}

let mounted = true;
let notificationId: number | null = null;

const attachListener = async () => {
await optimizely.onReady();
if (!mounted) return;

if (
optimizely.notificationCenter &&
typeof optimizely.notificationCenter.addNotificationListener ===
'function'
Comment thread
louisearchibald marked this conversation as resolved.
Outdated
) {
notificationId = optimizely.notificationCenter.addNotificationListener(
Comment thread
HarveyPeachey marked this conversation as resolved.
Outdated
enums.NOTIFICATION_TYPES.DECISION,
(listener: DecisionListener) => {
if (!mounted) return;

const { type, decisionInfo } = listener || {};
if (type !== 'flag' || !decisionInfo) return;

const { flagKey, variationKey } = decisionInfo;

const isRelevantExperiment =
typeof flagKey === 'string' &&
experimentsForPageType.includes(flagKey);
Comment thread
louisearchibald marked this conversation as resolved.
Outdated

const isUserBucketedIntoExperiment =
typeof variationKey === 'string' && variationKey !== 'off';

if (isRelevantExperiment && isUserBucketedIntoExperiment) {
setIsInExperiment(true);
}
},
);
}
};

if (isUserInAnyExperiments) {
setisInExperiment(true);
}
});
}
}, [
optimizelyExperimentsEnabled,
optimizely,
trackPageComplete,
trackPageDepth,
trackPageView,
trackVisit,
experimentsForPageType,
]);
attachListener();

return () => {
mounted = false;
// clean up the notification listener on unmount
if (
notificationId !== null &&
optimizely.notificationCenter &&
typeof optimizely.notificationCenter.removeNotificationListener ===
'function'
) {
optimizely.notificationCenter.removeNotificationListener(
notificationId,
);
}
};
Comment thread
louisearchibald marked this conversation as resolved.
Outdated
}, [optimizelyExperimentsEnabled, optimizely, experimentsForPageType]);

// if the user is not in any relevant experiment, do not render the tracking components to avoid sending unintended events
if (!isInExperiment) {
return null;
}
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4861,7 +4861,7 @@ __metadata:
languageName: node
linkType: hard

"@optimizely/optimizely-sdk@npm:^5.4.1":
"@optimizely/optimizely-sdk@npm:5.4.1, @optimizely/optimizely-sdk@npm:^5.4.1":
version: 5.4.1
resolution: "@optimizely/optimizely-sdk@npm:5.4.1"
dependencies:
Expand Down Expand Up @@ -17587,6 +17587,7 @@ __metadata:
"@loadable/component": "npm:5.16.7"
"@loadable/server": "npm:5.16.7"
"@loadable/webpack-plugin": "npm:5.15.2"
"@optimizely/optimizely-sdk": "npm:5.4.1"
"@optimizely/react-sdk": "npm:3.3.1"
"@storybook/addon-a11y": "npm:10.3.3"
"@storybook/addon-docs": "npm:10.3.3"
Expand Down
Loading