Skip to content

ENG-2679: Set gdprApplies value on 3rd party TCF stubs in non-TCF bundles#7556

Merged
gilluminate merged 2 commits intomainfrom
gill/ENG-2679/add-support-for-generic-tcf-stub-in-non-tcf-experi
Mar 5, 2026
Merged

ENG-2679: Set gdprApplies value on 3rd party TCF stubs in non-TCF bundles#7556
gilluminate merged 2 commits intomainfrom
gill/ENG-2679/add-support-for-generic-tcf-stub-in-non-tcf-experi

Conversation

@gilluminate
Copy link
Contributor

@gilluminate gilluminate commented Mar 3, 2026

Ticket ENG-2679

Description Of Changes

When a publisher loads the open-source IAB TCF stub (__tcfapi) on their page before fides.js, the stub defaults gdprApplies to undefined. If the non-TCF fides bundle is served (i.e. the visitor's experience doesn't require TCF), gdprApplies would remain undefined forever — leaving compliant ad scripts stuck waiting for a boolean value.

This adds a new updateTcfStubGdprApplies() function that is called during initialization of non-TCF bundles (fides.js, fides-headless.js). It detects any existing TCF stub and calls setGdprApplies(false) to unblock those downstream scripts.

Also consolidates the __tcfapi type declaration from fides-tcf.ts into global.d.ts so the type is available to all bundles, and updates the TCF stub callback signatures to use the more permissive global type.

Code Changes

  • clients/fides-js/global.d.ts - Add global Window.__tcfapi type declaration
  • clients/fides-js/src/lib/cmp-stubs.ts - Add updateTcfStubGdprApplies() function
  • clients/fides-js/src/fides.ts - Call updateTcfStubGdprApplies() during init
  • clients/fides-js/src/fides-headless.ts - Call updateTcfStubGdprApplies() during init
  • clients/fides-js/src/fides-tcf.ts - Remove duplicate __tcfapi type (now in global.d.ts)
  • clients/fides-js/src/lib/tcf/stub.ts - Update callback signatures to match global type
  • clients/fides-js/__tests__/lib/cmp-stubs.test.ts - Unit tests for updateTcfStubGdprApplies()
  • clients/privacy-center/cypress/e2e/fides-js/consent-banner.cy.ts - E2E test verifying the stub is updated

Steps to Confirm

  1. Add the IAB TCF CMP stub to clients/privacy-center/public/fides-js-demo.html before the fides.js <script> block (right after the <meta> tag, before the existing script):

    <!-- IAB TCF CMP stub (simulates a 3rd-party stub pre-loaded before fides.js) -->
    <script>
    (function() {
      var queue = [];
      var gdprApplies;
    
      function addFrame() {
        var doc = window.document;
        if (!window.frames['__tcfapiLocator']) {
          if (doc.body) {
            var iframe = doc.createElement('iframe');
            iframe.style.cssText = 'display:none';
            iframe.name = '__tcfapiLocator';
            doc.body.appendChild(iframe);
          } else {
            setTimeout(addFrame, 5);
          }
        }
      }
    
      function tcfAPIHandler() {
        var args = Array.prototype.slice.call(arguments);
        if (!args.length) return queue;
        if (args[0] === 'setGdprApplies') {
          if (args.length > 3 && parseInt(args[1], 10) === 2 && typeof args[3] === 'boolean') {
            gdprApplies = args[3];
            if (typeof args[2] === 'function') args[2]('set', true);
          }
        } else if (args[0] === 'ping') {
          if (typeof args[2] === 'function') {
            args[2]({ gdprApplies: gdprApplies, cmpLoaded: false, cmpStatus: 'stub' });
          }
        } else {
          queue.push(args);
        }
      }
    
      addFrame();
      window.__tcfapi = tcfAPIHandler;
    })();
    </script>

    Then visit the demo page with a geolocation that serves a non-TCF experience (e.g. ?geolocation=us-ca).

  2. After fides.js initializes, call window.__tcfapi("ping", 2, console.log) in the browser console

  3. Verify the ping response shows gdprApplies: false (not undefined)

  4. Load a TCF experience (e.g. ?geolocation=eea) on the same page and verify TCF functionality is unaffected

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Updates unreleased work already in Changelog, no new entry necessary
  • UX feedback:
    • No UX review needed
  • Followup issues:
    • No followup issues
  • Database migrations:
    • No migrations
  • Documentation:
    • No documentation updates required

Made with Cursor

@vercel
Copy link
Contributor

vercel bot commented Mar 3, 2026

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

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
fides-plus-nightly Ignored Ignored Preview Mar 3, 2026 7:47pm
fides-privacy-center Ignored Ignored Mar 3, 2026 7:47pm

Request Review

gilluminate added a commit that referenced this pull request Mar 3, 2026
Made-with: Cursor
@gilluminate gilluminate changed the title ENG-2679: Set gdprApplies=false on existing TCF stubs in non-TCF bundles ENG-2679: Set gdprApplies value on 3rd party TCF stubs in non-TCF bundles Mar 3, 2026
When a publisher loads the open-source IAB TCF stub before fides.js,
the stub's gdprApplies defaults to undefined. Non-TCF bundles (fides.js,
fides-headless.js) now call setGdprApplies(false) during init so that
compliant ad scripts waiting on a boolean value can proceed.

Also consolidates the __tcfapi type declaration into global.d.ts and
updates the TCF stub callback signatures accordingly.

Made-with: Cursor
Made-with: Cursor
@gilluminate gilluminate force-pushed the gill/ENG-2679/add-support-for-generic-tcf-stub-in-non-tcf-experi branch from 1e87859 to f88dc5e Compare March 3, 2026 19:47
@gilluminate gilluminate marked this pull request as ready for review March 3, 2026 20:22
@gilluminate gilluminate requested a review from a team as a code owner March 3, 2026 20:22
@gilluminate gilluminate requested review from jpople and removed request for a team March 3, 2026 20:22
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 3, 2026

Greptile Summary

This PR fixes a real-world interoperability issue where third-party ad scripts using the IAB TCF __tcfapi stub would be permanently blocked waiting for gdprApplies to become a boolean when only the non-TCF Fides bundle was served. It adds updateTcfStubGdprApplies() to cmp-stubs.ts and calls it early in the init() function of both fides.js and fides-headless.js, so any pre-loaded TCF stub gets gdprApplies=false set as soon as Fides initializes.

  • The Window.__tcfapi type is consolidated from a local declaration in fides-tcf.ts into global.d.ts, widening the parameter union to include boolean (required for the setGdprApplies call) and the callback to a variadic (...args: unknown[]) signature — enabling use from all bundles without importing the @iabtechlabtcf/cmpapi TCData type in shared code.
  • stub.ts callback signatures are updated to align with the new global type, with safe destructuring of args[0] for the debug addEventListener handler.
  • Unit tests cover the absent-stub, non-function, and happy-path cases; an E2E test in Cypress installs a minimal TCF stub and verifies gdprApplies is false after Fides initializes.
  • The one minor gap is that the try/catch error-swallowing path inside updateTcfStubGdprApplies() has no unit test, leaving a regression risk if the guard is ever accidentally removed.

Confidence Score: 5/5

  • This PR is safe to merge; changes are well-scoped, non-breaking, and covered by both unit and E2E tests.
  • The change is narrow and targeted: a new exported function with a guard and error swallowing, called once during non-TCF bundle init. The TCF bundle is unaffected. Type consolidation is clean. The only gap is a missing unit test for the catch path, which does not block correctness.
  • No files require special attention.

Important Files Changed

Filename Overview
clients/fides-js/src/lib/cmp-stubs.ts Adds updateTcfStubGdprApplies() with proper null-guard, type-check, and error swallowing. Clean implementation.
clients/fides-js/tests/lib/cmp-stubs.test.ts Good tests for undefined, non-function, and happy-path cases, but the catch block for error-swallowing is not tested.
clients/fides-js/global.d.ts Consolidates Window.__tcfapi type into the global declaration file with a broader parameter union (boolean added) and variadic callback, enabling use from all bundles.
clients/fides-js/src/fides.ts Adds updateTcfStubGdprApplies() call early in init with a clear comment; correct placement before config overrides are resolved.
clients/fides-js/src/fides-headless.ts Identical to fides.ts change — adds updateTcfStubGdprApplies() call at the same point in the headless init flow.
clients/fides-js/src/fides-tcf.ts Removes the now-redundant local Window.__tcfapi declaration and the TCData import, relying on the new global type instead.
clients/fides-js/src/lib/tcf/stub.ts Updates callback signatures to match the new global type; retValue/success are destructured from args at runtime and data?.eventStatus is safely accessed.
clients/privacy-center/cypress/e2e/fides-js/consent-banner.cy.ts Adds an E2E test that installs a minimal TCF stub via window:before:load, waits for Fides init, then verifies gdprApplies was set to false via a ping call.
changelog/7556-tcf-stub-gdpr-applies.yaml Changelog entry correctly describes the added behaviour.

Last reviewed commit: f88dc5e

Copy link
Contributor

@jpople jpople left a comment

Choose a reason for hiding this comment

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

Tested locally, working as expected.

@gilluminate gilluminate added this pull request to the merge queue Mar 5, 2026
Merged via the queue into main with commit 0e8f39e Mar 5, 2026
42 checks passed
@gilluminate gilluminate deleted the gill/ENG-2679/add-support-for-generic-tcf-stub-in-non-tcf-experi branch March 5, 2026 22:02
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