Shared JavaScript projects powering privacy features and special pages in DuckDuckGo's native apps (macOS, Windows, iOS, Android).
This is an npm workspace monorepo with four sub-projects:
JavaScript features injected into web pages for privacy protections. Features extend ConfigFeature and integrate with remote configuration for per-site enable/disable.
Features (in injected/src/features/):
api-manipulation- API behavior modificationsautofill-import- Credential import supportbreakage-reporting- Site breakage reportsbroker-protection- Data broker removal automationclick-to-load- Social embed blockingcookie- Cookie managementduck-player/duck-player-native- YouTube privacy playerelement-hiding- Hide page elementsexception-handler- Error handlingfavicon- Favicon privacyfingerprinting-*- Audio, battery, canvas, hardware, screen, storage fingerprint protectiongoogle-rejected- Google rejection handlinggpc- Global Privacy Controlharmful-apis- Dangerous API restrictionsmessage-bridge- Page↔content script messagingnavigator-interface- Navigator API modificationsperformance-metrics- Performance trackingreferrer- Referrer protectionweb-compat- Site compatibility fixesweb-interference-detection/web-telemetry- Monitoring
Docs: injected/docs/README.md (index to all docs)
Preact-based HTML/CSS/JS applications embedded in browsers. Each page lives in special-pages/pages/<name>/.
Pages:
duckplayer- YouTube privacy player UIerrorpage- Browser error pagesexample- Template for new pageshistory- Browsing history viewernew-tab- New Tab Pageonboarding- First-run experiencerelease-notes- Browser release notesspecial-error- SSL/certificate error pages
Docs: special-pages/README.md, plus readme.md in each page directory
Abstraction layer for web↔native messaging: notify (fire-and-forget), request (async response), subscribe (push updates).
Docs: messaging/docs/messaging.md
Generates TypeScript types from JSON Schema files. Used by other workspaces.
Run from root. Use nvm use to set the correct Node version.
| Command | Purpose |
|---|---|
npm run build |
Build all workspaces |
npm run test-unit |
Unit tests (all workspaces) |
npm run test-int |
Integration tests (Playwright) |
npm run lint |
ESLint + TypeScript + Prettier |
npm run lint-fix |
Auto-fix lint issues |
npm run serve |
Serve injected test pages (port 3220) |
npm run serve-special-pages |
Serve special pages (port 3221) |
Follow the error handling guidelines in guides/error-handling.md. Key rules:
- Errors are for exceptional conditions (invariant violations, unreachable code), not control flow
- Never leave promises unhandled — use
.catch()ortry/catchwithawait - Return
null/sentinel values for expected missing data instead of throwing
All new source files under injected/src/ must be added to the CORE_FILES set in scripts/check-strict-core.js. This enforces TypeScript strict mode (strict: true, noUncheckedIndexedAccess). Run npm run tsc-strict-core to verify. Do not remove existing entries from the set.
See guides/debugging.md for debugging resources including script integrity validation, feature triage checklist, and platform-specific troubleshooting.
- When running Playwright commands, use
--reporter listto prevent the Shell tool from hanging - Use
.github/pull_request_template.mdwhen creating a pull request.
- Node 22 and npm are pre-installed. Playwright browsers + system deps are pre-installed. Just run
npm cito refresh dependencies. npm run serve-special-pagesactually serves on port 3210 (not 3221 as the Commands table above states). The injected test pages serve on port 3220 as documented.- Integration tests for injected workspace may show 2 flaky iOS mobile drawer timeouts (
duckplayer-mobile-drawer.spec.js); these are pre-existing timing issues, not environment problems. - No Docker, databases, or external services are needed. All tests are self-contained with local HTTP servers and mocked native messaging.
- On headless Linux,
xvfbis pre-installed. The injected workspace providesnpm run test-int-xwhich wraps Playwright withxvfb-run, but standardnpm run test-intalso works in this environment.