Skip to content

fix: gate Fullstory capture on Osano Analytics consent - #7062

Merged
jennifer-shehane merged 1 commit into
mainfrom
osano/gate-fullstory-on-consent
Nov 7, 2026
Merged

jennifer-shehane merged 1 commit into
mainfrom
osano/gate-fullstory-on-consent

Conversation

@jennifer-shehane

@jennifer-shehane jennifer-shehane commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Summary

Fullstory now starts capture only when Osano reports Analytics consent. It shuts down the moment a visitor withdraws consent and restarts if they grant it again, all without a page reload.

Why

Follow-up to #7061. While checking that Osano still blocks the new snippet's fs.js?org=… address, we found:

  • Osano blocks on the next load only. It stops fs.js loading after a decline (confirmed), but it can't stop a script that's already running. A visitor who declined through Cookie Preferences kept being recorded until the next page load.
  • Accepting mid-session didn't start capture. A visitor who accepted mid-session wasn't recorded until the next page load either.
  • Capture depended on script matching. Whether Fullstory ran depended on Osano matching Fullstory's script address, which changes whenever the snippet does.

What changed

  • plugins/fullstory.js: a second head script runs right after the verbatim 2.1 snippet. It:
    1. Queues FS('init', { env: { captureOnStartup: false } }), so Fullstory never starts on its own. The snippet's own init call merges with this one, per Fullstory's Configure Capture docs.
    2. Reads Osano.cm.getConsent() on load and listens for osano-cm-consent-saved. When Analytics is accepted, it calls FS('start') (or FS('restart') after a shutdown). When Analytics is withdrawn, it calls FS('shutdown').
    3. Never starts capture when osano.js is blocked (by an ad blocker, for example), since there's no consent to read.
    4. Does nothing when FS belongs to another script. The snippet backs off in that case and never sets _v.
  • plugins/fullstory.test.js: 9 vitest tests: the gate's state changes, the no-Osano case, the foreign FS global case, and the plugin's org ID and production checks.
  • package.json: adds test:fullstory-plugin to test:plugins.
  • plugins/AGENTS.md: lists the new test.

How this was tested

  • npm run test:plugins: all suites pass, including the 9 new tests. As a check that the tests can fail, removing the shutdown call fails the withdraw/restart test.

  • End to end with the real Osano script (FULLSTORY_ORG_ID=test-org npm run build, npm run serve, headless Chromium, fs.js stubbed), checking the calls queued on FS:

    Scenario Calls after the snippet's init
    First visit (US default: Analytics accepted) init {captureOnStartup:false}, start
    Decline Analytics in Cookie Preferences, no reload adds shutdown
    Accept again, no reload adds restart
    Reload after declining init {captureOnStartup:false} only, no start
    cmp.osano.com blocked init {captureOnStartup:false} only, no start
  • Lint: npm run lint:fix and Prettier are clean.

Not tested: the real fs.js processing the queued calls. The test org isn't real, and the session's network doesn't reach edge.fullstory.com. The calls used are Fullstory's documented 2.1 API. After deploy, check that sessions still arrive in Fullstory, and that a session stops when you decline in Cookie Preferences.

Notes for reviewers

  • US capture timing is unchanged. For US visitors, Osano reports Analytics as accepted on the first page load, and its banner closes itself after about 8 seconds, which counts as acceptance. So Fullstory still starts right away for them. That default is set in the Osano dashboard (the US jurisdiction rules and the banner timeout), not in this repo.
  • Visitors with Osano blocked aren't recorded. If an ad blocker stops osano.js but not Fullstory, that visitor used to be recorded and now isn't. That's deliberate: no consent signal means no capture.
  • No e2e coverage, by design. CI builds don't set FULLSTORY_ORG_ID, and cypress.config blocks *fullstory.com, so the e2e suite never loads Fullstory. The unit tests cover the gate instead.

Generated by Claude Code


Note

Medium Risk
Changes production analytics behavior (when Fullstory records) and injects new client-side consent logic; mistakes could under- or over-record sessions relative to policy.

Overview

Summary

Production Fullstory injection now runs a second head script after the 2.1 snippet that disables startup capture, reads Osano cm consent, and calls FS('start') / FS('restart') / FS('shutdown') when Analytics is accepted, re-accepted, or withdrawn—so consent changes apply without a full reload. If Osano is missing or FS is not the Fullstory snippet global, the gate does not start capture.

Why

Osano only blocks fs.js on the next navigation, so visitors who declined in Cookie Preferences could keep recording until reload; accepting mid-session did not start capture until reload either. This follows up on work in #7061 by driving capture directly from Osano consent events instead of relying on script blocking alone.

Notes for reviewers

  • plugins/fullstory.test.js covers gate state transitions, no-Osano and foreign-FS cases, and plugin head-tag behavior; npm run test:plugins includes test:fullstory-plugin.
  • plugins/AGENTS.md documents the new test. Intentional product change: if osano.js is blocked (e.g. ad blocker) there is no consent signal, so capture does not start.

Reviewed by Cursor Bugbot for commit 9696acc. Bugbot is set up for automated code reviews on this repo. Configure here.

Osano blocks fs.js on page load when a visitor has declined Analytics,
but it can't stop a script that's already running. A visitor who declined
mid-session kept being recorded until the next page load, and a visitor
who accepted mid-session wasn't recorded until then either. Capture also
depended on Osano recognizing Fullstory's script URL.

- Queue FS('init', { env: { captureOnStartup: false } }) right after the
  snippet, so Fullstory never starts capture on its own.
- Read Osano's consent on load and on every osano-cm-consent-saved event:
  start capture when Analytics is accepted, shut it down when it's
  withdrawn, and restart it if it's granted again.
- Never start capture when osano.js is blocked, since there's no consent
  to read.
- Add plugins/fullstory.test.js and run it from npm run test:plugins.

US visitors still get Osano's default of accepting Analytics on load, so
this doesn't change when their capture starts. That default is an Osano
dashboard setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WUv8r1UmXksNKFmsHaYoTF
@cypress

cypress Bot commented Nov 6, 2026

Copy link
Copy Markdown

cypress-documentation    Run #2797

Run Properties:  status check passed Passed #2797  •  git commit ac51b46827 ℹ️: Merge 9696acc4195d42f9fd6af767f2c95875e57be70a into 16522ef1f7c161b6453da6eb240b...
Project cypress-documentation
Branch Review osano/gate-fullstory-on-consent
Run status status check passed Passed #2797
Run duration 02m 02s
Commit git commit ac51b46827 ℹ️: Merge 9696acc4195d42f9fd6af767f2c95875e57be70a into 16522ef1f7c161b6453da6eb240b...
Committer Jennifer Shehane
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 427
View all changes introduced in this branch ↗︎
UI Coverage  32.82%
  Untested elements 739  
  Tested elements 25  
Accessibility  98.9%
  Failed rules  2 critical   5 serious   4 moderate   1 minor
  Failed elements 74  

@jennifer-shehane
jennifer-shehane merged commit 435192e into main Nov 7, 2026
21 checks passed
@jennifer-shehane
jennifer-shehane deleted the osano/gate-fullstory-on-consent branch November 7, 2026 02:50
@cypress

cypress Bot commented Nov 7, 2026

Copy link
Copy Markdown

cypress-documentation    Run #2800

Run Properties:  status check passed Passed #2800  •  git commit 435192ea23: Gate Fullstory capture on Osano Analytics consent (#7062)
Project cypress-documentation
Branch Review main
Run status status check passed Passed #2800
Run duration 02m 15s
Commit git commit 435192ea23: Gate Fullstory capture on Osano Analytics consent (#7062)
Committer Jennifer Shehane
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 427
View all changes introduced in this branch ↗︎
UI Coverage  32.82%
  Untested elements 738  
  Tested elements 25  
Accessibility  98.91%
  Failed rules  2 critical   6 serious   4 moderate   1 minor
  Failed elements 152  

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.

2 participants