This document provides platform-specific build instructions, troubleshooting steps, and local development tips for integrating and working with Content Scope Scripts (C-S-S) across iOS, macOS, Android, Windows, and browser extensions.
Ensure the injected C-S-S script matches what you expect across all three locations.
Check the build directory in the content-scope-scripts repo:
build/[platform]/contentScope.js (or build/[platform]/inject.js for extensions)Sources/ContentScopeScripts/dist/contentScope.js instead of build/apple/Check where it lives in the native application:
apple-browsers/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/contentScope.jsandroid/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js (referenced by build.gradle files)windows-browser/WindowsBrowser/Application/ContentScripts/contentScope.js (embedded resource from submodules/content-scope-scripts/build/windows/contentScope.js)windows-browser/WindowsBrowser.DataBrokerProtection.Agent/Resources/dbp-contentScopeScriptsextension/node_modules/@duckduckgo/content-scope-scripts/build/[platform]/inject.js (where [platform] is chrome-mv3 or firefox)Check in the web inspector:
C_S_S_SOURCEMAPS=1 when building)All three locations must have the same file contents. If they don't match, your changes aren't being properly built or injected.
Enable inline source maps to see original file names and line numbers in browser DevTools instead of the bundled output (e.g., web-compat.js:142 instead of contentScope.js:10484).
C_S_S_SOURCEMAPS=1 npm run build
content-scope-scripts folder from Finder into the Xcode project navigatorPackage.swift file and set it up as a local package
Option 2: Change Swift PM dependency to local pathapple-browsers/SharedPackages/BrowserServicesKit/Package.swift, change the dependency from:.package(url: "https://github.com/duckduckgo/content-scope-scripts.git", exact: "12.27.0")
to:.package(path: "../../../../content-scope-scripts")
(Adjust the relative path based on your directory structure)npm run build-content-scope-scripts in the apple-browsers repo. The Swift Package Manager will handle the build process automatically.cmd+K~/Library/Developer/Xcode/DerivedDatanpm link @duckduckgo/content-scope-scripts or npm link @duckduckgo/autofill to link to your local checkout.npm link in the dependency folder.npm build in C-S-S (not run automatically like in the extension).build.gradle to an absolute path on your machine.
autofill.js (or other submodules) on WindowsFor native engineers using build branches pr-<version-number>:
Installing before the CI completes or before the hash changes means you're testing old code. The hash change is a build CI indicator - make sure it has finished before running install again.
Always validate that the config loaded from remote config or cache config is in the correct state that is injected into Content Scope Scripts.
processConfig function (located in injected/src/utils.js).enabled, disabled, internal, preview) are correctunprotectedTemporary domains are correctly setsite.isBroken, site.allowlisted, and site.enabledFeatures are correctPlatform parameters control internal and version state, and thus the enabled state of your features.
processConfig method as a breakpoint.preferences parameter passed to processConfig:
platform.version - version numberplatform.internal - internal build flagplatform.preview - preview build flagWhy This Matters: Platform parameters determine feature enablement states. A feature set to internal state will only be enabled if platform.internal === true. Incorrect platform parameters can silently disable features.
Note: For config version validation, see privacy-configuration/.cursor/rules/debugging.mdc.
Use this when a feature "is not working" to confirm it is enabled and wired end-to-end.
$CONTENT_SCOPE$.processConfig (see above) and inspect:
features.<featureName>.state and features.<featureName>.settingssite.enabledFeatures includes the feature namesite.allowlisted and site.isBroken are falseinjectName-based overrides, confirm the correct injectName is being applied.injected/src/features.js to confirm the platform bundle includes the feature.injected/entry-points/).build/<platform>/contentScope.js or inject.js) contains the feature code.settings + conditionalChanges).this.settings) or use
getFeatureSettingEnabled() to confirm the specific behavior is enabled.messageSecret is present.messagingContextName and featureName match what the native layer expects.Use this test page to validate that ContentScopeScripts has been injected correctly:
https://privacy-test-pages.site/features/navigator-interface.html
This page provides a quick way to verify C-S-S injection is working as expected.