Repository navigation
@dotcms/events: send only the current page's experiments in context.experiments #38046
Description
Description
@dotcms/events keeps a running list of every experiment the visitor joined in the analytics session and sends the whole list in context.experiments on the events of any page that runs an experiment the visitor is in. The backend will now attribute events to experiments by session, so the SDK no longer needs to build that list. This task removes the accumulation: the events of a page carry only the experiments that page runs and the visitor is in, and nothing else.
Today
A visitor in experiment A on /home and experiment B on /pricing, navigating /home → /about (no experiment) → /pricing:
| Page | context.experiments today |
After this task |
|---|---|---|
/home |
[A] |
[A] |
/about |
none | none |
/pricing |
[A, B] |
[B] |
How the list is built today:
joinSessionExperimentinexperiments/store.tsadds each experiment the engine assigns on a page to a list in sessionStorage underdot_events_session_experiments, keyed by the analytics session id. An entry for the same experiment replaces the older one.leaveEndedExperimentsinexperiments/store.tsdrops the experiments thatisUserIncludedreports inexcludedExperimentIdsEnded; the engine calls it after eachisUserIncludedanswer.contextExperiments(sessionId)inexperiments/engine.tsreturns that list (getSessionExperiments) while the visit on screen runs an experiment the visitor is in (visitInExperiment === navigations), and an empty list otherwise.- The
dot-events-experimentsplugin (experiments/plugin.ts) puts whatcontextExperimentsreturns intocontext.experimentson everypageandtrackcall.
The session list existed because the analytics service filters events by experiments before grouping them by session, so Reach Page and URL Parameter goals reached on other pages only counted if those pages' events carried the earlier experiments. With attribution by session moving to the backend, the SDK only reports what is on screen.
What changes
- The engine keeps, for the current visit only, the experiments that visit runs and the visitor is in, built from the same
assigneddecision that callsjoinSessionExperimenttoday. A navigation inside the page starts an empty list for the new visit. contextExperimentsreturns that per-visit list and no longer reads storage. ThesessionIdparameter goes away if nothing else needs it, and the plugin'ssession_idguard with it.getSessionExperiments,joinSessionExperiment,leaveEndedExperiments, theSessionExperimentstype andSTORAGE_KEYS.sessionExperimentsare removed. The SDK stops writingdot_events_session_experiments.- Behavior that stays as it is: no
context.experimentson pages that run no experiment the visitor is in; nothing added when the route ignoresvariantName(theignoreddecision); a page restored from the back/forward cache keeps its experiment, since a restore is not a navigation;experiments: falsestill leaves the plugin out; the shape of each entry (id,running_id,variant) does not change.
Files
| File | Change |
|---|---|
core-web/libs/sdk/events/src/lib/experiments/store.ts |
Remove the session experiment functions and type |
core-web/libs/sdk/events/src/lib/experiments/constants.ts |
Remove STORAGE_KEYS.sessionExperiments |
core-web/libs/sdk/events/src/lib/experiments/engine.ts |
Per-visit list replaces visitInExperiment and the session store; drop the leaveEndedExperiments call; update the contextExperiments doc comment |
core-web/libs/sdk/events/src/lib/experiments/plugin.ts |
Follow the new contextExperiments signature; update the doc comment |
core-web/libs/sdk/events/src/lib/pipeline/models.ts |
EventContext.experiments doc comment: the page's experiments, not the session's |
core-web/libs/sdk/events/src/lib/experiments/store.spec.ts |
Remove the session experiments block |
core-web/libs/sdk/events/src/lib/experiments/engine.spec.ts |
Rewrite the "sends every experiment of the session" test to expect only the current page's experiment; drop the sessionExperiments storage assertion in the variantName warning test |
core-web/libs/sdk/events/README.md |
Experiments section, "What It Sends" list and storage table (remove the dot_events_session_experiments row) |
core-web/libs/sdk/events/CLAUDE.md |
Experiments section: replace the session-list rule and its rationale |
Acceptance Criteria
- On a page that runs one experiment the visitor is in, every event carries
context.experimentswith exactly that experiment, itsrunning_idand the visitor's variant. - On a page that runs two experiments the visitor is in, every event carries both, and no other experiment.
- After an SPA navigation from a page with experiment A to a page with experiment B, the events of the second page carry only B.
- After an SPA navigation from a page with experiment A to a page without an experiment, the events of the second page carry no
context.experiments, and the events of a third page with experiment B carry only B. - A full page load of a page with experiment B, after earlier pages with experiment A in the same session, sends only B.
- A page restored from the back/forward cache keeps sending its own experiment.
- When the route ignores
variantName, the page's events carry nocontext.experiments, as today. - Events already queued keep the context they were created with: events created on the page with A and sent after the navigation to B still carry A.
- The SDK no longer reads or writes
dot_events_session_experiments, andgetSessionExperiments,joinSessionExperiment,leaveEndedExperimentsandSTORAGE_KEYS.sessionExperimentsno longer exist in the codebase. - Unit tests in
engine.spec.tscover the navigation cases above;store.spec.tsno longer tests the removed functions. -
README.mdandCLAUDE.mdof@dotcms/eventsdescribe the new rule, and the storage table no longer listsdot_events_session_experiments. -
pnpm nx test sdk-events,pnpm nx lint sdk-events, the spectsccheck andpnpm nx test sdk-bundle-budgetspass.
Additional Context
- Out of scope: the backend attribution by session, and any change to the entry shape or to the event types.
- A
dot_events_session_experimentsentry left in a browser by an earlier build is ignored once the SDK stops reading it, and sessionStorage clears it when the tab closes, so no cleanup code is needed. - This removes code from the
events-initbundle (29,208 B gzip against a 30,000 B ceiling), so the size budget should go down, not up. - Part of Create @dotcms/events: one SDK for analytics and experiments #37683 (create
@dotcms/events, one SDK for analytics and experiments).
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNew
Activity