Skip to content

@dotcms/events: send only the current page's experiments in context.experiments #38046

Open

Description

@oidacra

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:

  • joinSessionExperiment in experiments/store.ts adds each experiment the engine assigns on a page to a list in sessionStorage under dot_events_session_experiments, keyed by the analytics session id. An entry for the same experiment replaces the older one.
  • leaveEndedExperiments in experiments/store.ts drops the experiments that isUserIncluded reports in excludedExperimentIdsEnded; the engine calls it after each isUserIncluded answer.
  • contextExperiments(sessionId) in experiments/engine.ts returns 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-experiments plugin (experiments/plugin.ts) puts what contextExperiments returns into context.experiments on every page and track call.

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 assigned decision that calls joinSessionExperiment today. A navigation inside the page starts an empty list for the new visit.
  • contextExperiments returns that per-visit list and no longer reads storage. The sessionId parameter goes away if nothing else needs it, and the plugin's session_id guard with it.
  • getSessionExperiments, joinSessionExperiment, leaveEndedExperiments, the SessionExperiments type and STORAGE_KEYS.sessionExperiments are removed. The SDK stops writing dot_events_session_experiments.
  • Behavior that stays as it is: no context.experiments on pages that run no experiment the visitor is in; nothing added when the route ignores variantName (the ignored decision); a page restored from the back/forward cache keeps its experiment, since a restore is not a navigation; experiments: false still 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.experiments with exactly that experiment, its running_id and 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 no context.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, and getSessionExperiments, joinSessionExperiment, leaveEndedExperiments and STORAGE_KEYS.sessionExperiments no longer exist in the codebase.
  • Unit tests in engine.spec.ts cover the navigation cases above; store.spec.ts no longer tests the removed functions.
  • README.md and CLAUDE.md of @dotcms/events describe the new rule, and the storage table no longer lists dot_events_session_experiments.
  • pnpm nx test sdk-events, pnpm nx lint sdk-events, the spec tsc check and pnpm nx test sdk-bundle-budgets pass.

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_experiments entry 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-init bundle (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

No one assigned

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions