Skip to content

fix: Duplicate inline A/B test scripts injected when multiple Content components render on the same page#4552

Open
midhunadarvin wants to merge 2 commits intomainfrom
midhun/ENG-12260
Open

fix: Duplicate inline A/B test scripts injected when multiple Content components render on the same page#4552
midhunadarvin wants to merge 2 commits intomainfrom
midhun/ENG-12260

Conversation

@midhunadarvin
Copy link
Copy Markdown
Contributor

@midhunadarvin midhunadarvin commented May 6, 2026

Description

  • Fix Duplicate inline A/B test scripts injected when multiple Content components render on the same page

Loom
Issue: https://www.loom.com/share/21d436c93fae4cc6836042fe15ca40e6
Fix: https://www.loom.com/share/8f4f24a45db3431cbc69d5bf77cc5ec1


Note

Medium Risk
Touches variant/personalization bootstrap script injection and adds DOM-based deduping, which could affect A/B test execution order across SDK targets if incorrect. Covered by new e2e assertions ensuring only one init script is present.

Overview
Prevents duplicate inline initialization scripts from being injected when multiple Content/ContentVariants instances render on the same page.

InlinedScript now supports an opt-in dedupe mode (skips rendering if a matching script[data-id] already exists), and ContentVariants wraps the A/B and personalization init script strings with a removeDuplicateScript(...) guard that removes extra tags and runs the script only once per page.

E2E A/B tests were updated to assert a single builderio-init-variants-fns script tag is present after navigation.

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

@midhunadarvin midhunadarvin requested review from a team and anaghav2023 and removed request for a team May 6, 2026 05:12
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 6, 2026

⚠️ No Changeset found

Latest commit: 795f86c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 6, 2026

View your CI Pipeline Execution ↗ for commit 795f86c

Command Status Duration Result
nx test @builder.io/react -- packages/react/src ✅ Succeeded 9s View ↗
nx test @builder.io/sdk ✅ Succeeded 5s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-06 05:15:44 UTC

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 6, 2026

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 795f86c

Command Status Duration Result
nx test @e2e/gen1-next15-app ❌ Failed 7m 34s View ↗
nx test @e2e/gen1-remix ❌ Failed 7m 29s View ↗
nx test @e2e/gen1-react ❌ Failed 7m 18s View ↗
nx test @e2e/sveltekit ❌ Failed 7m 37s View ↗
nx test @e2e/gen1-next14-pages ❌ Failed 6m 42s View ↗
nx test @e2e/react-sdk-next-pages ❌ Failed 6m 31s View ↗
nx test @e2e/remix ❌ Failed 6m 13s View ↗
nx test @e2e/hydrogen ❌ Failed 5m 49s View ↗
Additional runs (38) ❌ Failed ... View ↗

☁️ Nx Cloud last updated this comment at 2026-05-06 05:24:30 UTC

Copy link
Copy Markdown

@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.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 795f86c. Configure here.

!isBrowser() ||
!document.querySelector(`script[data-id="${props.id}"]`)
);
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Dedupe causes SSR hydration mismatch in React

Medium Severity

The shouldRender getter evaluates differently during SSR vs client hydration. During SSR, isBrowser() is false, so shouldRender is true and the <script> renders. During hydration, isBrowser() is true and document.querySelector finds the SSR'd script, so shouldRender becomes false — the virtual DOM has no script, but the DOM still has it. This causes a React hydration mismatch. The existing codebase carefully avoids this pattern — checkShouldRenderVariants handles it by having scripts remove themselves from the DOM before hydration (via document.currentScript?.remove()), but removeDuplicateScript intentionally keeps the first script in the DOM. The removeDuplicateScript wrapper alone already prevents duplicate execution via the window[scriptKey] flag, so the dedupe/shouldRender guard adds a hydration regression without additional functional benefit for SSR targets.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 795f86c. Configure here.

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.

1 participant