Skip to content

Conversation

@daniel-graham-amplitude
Copy link
Collaborator

@daniel-graham-amplitude daniel-graham-amplitude commented Jan 28, 2026

Summary

Currently, if you set "optOut=true" on init, and you have autocapture enabled (sessions, attribution) it will still track "session_start" and "identify" (for attribution) but it will be dropped because it's optOut=true; and will never be called again because the session has already started.

This pull request makes it so that if a session is started while optOut, the session creation will be deferred until later when optOut becomes "false".

When optOut becomes false (either via setOptOut(false) or calling init again with optOut != true) than it will call session_start, identify (attribution) and page_viewed

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: No

Note

Medium Risk
Touches session lifecycle, opt-out state transitions, and initialization ordering; bugs here could cause missing or duplicated session/attribution/page-view events when users toggle opt-out.

Overview
When initialized with optOut: true, the browser SDK now defers starting a session (and the resulting session_start / configured identify) by storing a deferredSessionId and only applying it once opt-out is turned off.

It also defers web attribution and page view tracking while opted out by skipping attribution initialization and delaying page-view plugin registration until setOptOut(false) (or a subsequent init with opt-out disabled) triggers new opt-out listeners.

Core changes add a small async opt-out listener mechanism to Timeline, persist deferredSessionId in browser config/user session storage, and adjust setOptOut ordering to update config before notifying listeners; tests and a new test-server page cover the new opt-out/opt-in behavior.

Written by Cursor Bugbot for commit 4ee8599. This will update automatically on new commits. Configure here.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Jan 28, 2026

Defer session start and web attribution initialization when config.optOut is true in analytics-browser by adding deferredSessionId handling across BrowserConfig, AmplitudeBrowser, and Timeline

Add optOut to attribution options and short-circuit WebAttribution.init; introduce deferredSessionId in config and cookies; update AmplitudeBrowser.init and setSessionId to store and start the deferred session on opt-in; invoke registered opt-out listeners via Timeline and reorder _setOptOut to set config before notifying.

🖇️ Linked Issues

Addresses AMP-147858 and contributes to the epic AMP-147857 by deferring session start and attribution while opted out and starting the stored deferred session on opt-in.

📍Where to Start

Start with AmplitudeBrowser.init and setSessionId in browser-client.ts, then review BrowserConfig deferred session handling in config.ts, and Timeline opt-out listener flow in timeline.ts.

Changes since #1509 opened

  • Converted opt-out listeners in Timeline class from synchronous to asynchronous callbacks and added an opt-out listener in AmplitudeBrowser.init method that reinitializes WebAttribution when optOut becomes false [86370ae]
  • Updated tests in browser-client.test file to verify session and attribution deferral behavior under optOut conditions [86370ae]
  • Deferred page view tracking plugin registration when optOut is true [3a85cb8]
  • Added error handling to opt-out listener execution [3a85cb8]
  • Introduced jest.useFakeTimers() in beforeEach hooks and jest.useRealTimers() in afterEach hooks for opt-out true test contexts within analytics-browser test suite [f9b3536]
  • Provisioned an Identify instance with test-property set to test-value during init calls when optOut is true across test suite and test server demo page [f9b3536]
  • Removed assertions verifying web attribution currentCampaign state and plugin registration from opt-out true test cases [f9b3536]
  • Added timer advancement calls in analytics-browser tests verifying session_start and attribution deferral behavior [0be52cb]
  • Replaced Jest fake timers with real timers and async waits in the config.optOut when optOut is true test suite [4ee8599]

📊 Macroscope summarized 86370ae. 9 files reviewed, 8 issues evaluated, 2 issues filtered, 1 comment posted. View details

@daniel-graham-amplitude daniel-graham-amplitude changed the title Amp 147858 opt out sessions fix fix(analytics-browser): defer session_start and attribution when optOut is "true" Jan 28, 2026
@daniel-graham-amplitude daniel-graham-amplitude marked this pull request as draft January 28, 2026 17:46
@daniel-graham-amplitude daniel-graham-amplitude marked this pull request as ready for review January 28, 2026 23:19
@Mercy811
Copy link
Contributor

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Copy link
Contributor

@Mercy811 Mercy811 left a comment

Choose a reason for hiding this comment

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

When optOut=true, don’t start a session (do not even set sessionId). Invoke the session logic later when optOut=false.

Hi @daniel-graham-amplitude, according to the design, we should not event set session id when opt out. But the current implementation save it to cookie storage which doesn't align with the design.

I have a local test with the test sever

  • visit http://localhost:5173/opt-out/index.html?ampSessionId=123456789 first
  • then go to http://localhost:5173/opt-out/index.html
  • click "Turn off opt out" and a new session with the session id 123456789 is started

I'd expect we start the session with the session id at the time when i click "turn off opt out". wdyt?

@daniel-graham-amplitude
Copy link
Collaborator Author

@Mercy811 it doesn't set sessionId it sets deferredSessionId and then when the session starts deferredSessionId becomes sessionId.

This was to cover a case that Jin had flagged, he pointed out that a customer could call setSessionId while optOut=true, then the ID that was set should match.

@Mercy811
Copy link
Contributor

This was to cover a case that Jin had flagged, he pointed out that a customer could call setSessionId while optOut=true, then the ID that was set should match.

It makes sense to me to let the SDK remember customer's setSessionId call and ampDeviceId from url. But if they just call amplitude.init() and setOptOut(false) later, shouldn't the session id be the time setOptOut(false) is called instead of amplitude.init() is called like the design doc

I recommend Solution # 2. It’s simpler and I don’t see any problem with deferring session start until after the user has “opted-in”. In fact, I would reverse the question and ask: why do we currently set sessionId for users who aren’t opted-in? If they’re not “opted-in” should they even have a “session”?

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.

3 participants