Skip to content

feat(scripts): use c15t to load scripts based on shopper consent preferences#2659

Merged
matthewvolk merged 1 commit intocanaryfrom
feat/consent-manager-script-loader
Oct 31, 2025
Merged

feat(scripts): use c15t to load scripts based on shopper consent preferences#2659
matthewvolk merged 1 commit intocanaryfrom
feat/consent-manager-script-loader

Conversation

@matthewvolk
Copy link
Copy Markdown
Contributor

@matthewvolk matthewvolk commented Oct 30, 2025

Note

This PR is a replacement for #2651

Closes #2651

What/Why?

This PR adds script loading functionality to Catalyst's consent manager, achieving parity with Stencil's consent-aware script loading behavior.

The implementation replaces the custom <ScriptManagerScripts /> component with the native Script Loader feature of the c15t.com library.

Additionally, the consent categories exposed by c15t are different than the consent categories available in the BigCommerce API. The consent categories in the c15t library are hardcoded, so we added a scriptsTransformer to map BigCommerce's consent categories to C15T's standardized categories:

const BC_TO_C15T_CONSENT_CATEGORY_MAP = {
  ESSENTIAL: 'necessary',
  UNKNOWN: 'necessary', // Matches Stencil behavior of always loading "UNKNOWN" scripts
  FUNCTIONAL: 'functionality',
  ANALYTICS: 'measurement',
  TARGETING: 'marketing',
}

It's also worth noting that we maintain feature parity with Stencil in determining which scripts load based on consent preferences:

  1. If the user has not provided any consent preference (cookie banner still visible): Only ESSENTIAL and UNKNOWN scripts are loaded.
  2. If the user has "Accepted All" consent categories, all scripts load
  3. If the user has "Rejected All" consent categories, only ESSENTIAL and UNKNOWN scripts load.

Testing

Demo video:
https://github.com/user-attachments/assets/7f859c23-8419-46e7-b86e-a1e24127879a

Migration

This PR modifies the following files that you may encounter merge conflicts with:

  1. core/app/[locale]/layout.tsx:

    • Added ScriptsFragment import and inclusion in RootLayoutMetadataQuery
    • Added scriptsTransformer import
    • Transformed scripts are now passed to <ConsentManager scripts={scripts}>
    • Resolution tip: The ConsentManager component now requires a scripts prop. You'll need to query scripts using the ScriptsFragment and transform them via scriptsTransformer() before passing them to the component.
  2. core/components/consent-manager/index.tsx and consent-providers.tsx:

    • Both now accept and forward a scripts prop
    • ConsentManagerProvider passes scripts to ClientSideOptionsProvider
    • Resolution tip: Ensure the scripts prop flows through: ConsentManagerConsentManagerProviderClientSideOptionsProvider
  3. New files added:

    • core/components/consent-manager/scripts-fragment.ts - GraphQL fragment for querying scripts
    • core/data-transformers/scripts-transformer.ts - Transforms BC scripts to C15T format
    • Resolution tip: These files should not conflict, but if you've added similar functionality, consider consolidating the logic.

If you've customized your consent manager implementation, ensure that:

  • Scripts are queried in your layout/page where the ConsentManager is rendered
  • The scriptsTransformer is applied to the raw script data before passing to ConsentManager
  • The scripts prop is threaded through all consent manager components

@matthewvolk matthewvolk requested a review from a team October 30, 2025 21:46
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Oct 30, 2025

🦋 Changeset detected

Latest commit: 675089c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@bigcommerce/catalyst-core Minor

Not sure what this means? Click here to learn what changesets are.

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

@vercel
Copy link
Copy Markdown

vercel Bot commented Oct 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
catalyst-b2b Ready Ready Preview Comment Oct 31, 2025 8:22pm
catalyst-canary Ready Ready Preview Comment Oct 31, 2025 8:22pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
catalyst Ignored Ignored Oct 31, 2025 8:22pm

Comment thread core/app/[locale]/layout.tsx Outdated
Comment on lines +40 to +44
// eslint-disable-next-line no-console
console.warn(
`[scripts-transformer] Unknown BigCommerce Script Consent Category ` +
`"${bigCommerceCategory}", defaulting to UNKNOWN`,
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This will probably log in production. We probably want to remove this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove or just run when not in prod?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd just remove here, otherwise we'd need to add some sort of invariant logger here.

Copy link
Copy Markdown
Contributor

@jorgemoya jorgemoya left a comment

Choose a reason for hiding this comment

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

💯 , love how clean this is. Minor observations before the final approve 👍 .

Comment thread core/app/[locale]/layout.tsx Outdated
Comment on lines +40 to +44
// eslint-disable-next-line no-console
console.warn(
`[scripts-transformer] Unknown BigCommerce Script Consent Category ` +
`"${bigCommerceCategory}", defaulting to UNKNOWN`,
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove or just run when not in prod?

}
entityId
consentCategory
location
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we remove location since we don't use it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah good catch, we can always add it back later when the library adds support (which they are considering)

Comment on lines +9 to +11
integrityHashes {
hash
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are we still using integrityHashes for anything?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should be.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch! I added a fix that

  1. .map()'s over site.content.scripts.edges.node.integrityHashes
  2. Filters out falsy (null)
  3. If resulting array contains hashes, join them with a single space (following HTML spec)
  4. Add them to the arbitrary attributes object to be added to the <script> element when rendered

@matthewvolk matthewvolk force-pushed the feat/consent-manager-script-loader branch from 3b51c8a to 675089c Compare October 31, 2025 20:20
@matthewvolk matthewvolk added this pull request to the merge queue Oct 31, 2025
Merged via the queue into canary with commit abaa461 Oct 31, 2025
11 checks passed
@matthewvolk matthewvolk deleted the feat/consent-manager-script-loader branch October 31, 2025 20:24
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