Transparency Report
At a Glance
rules.muga.app, disable it any time in Settings. Short-link resolution, split by privacy risk: resolving a short link when you open it is on by default, since you were navigating there anyway; resolving one when you merely hover is off by default and opt-in. Either way the extension fetches the shortener host directly, with credentials omitted, and no MUGA server is involved. The list is a fixed 19 hosts (bit.ly, t.co, tinyurl.com and 16 more), enumerated in full in the privacy policy. No cookies, no identifiers, no POST body. Auditable open-source code.
rules.muga.app weekly, on by default (an Ed25519-signed public payload carrying no user data; disable it any time in Settings). Short-link resolution makes a direct HTTPS GET to one of 19 fixed shortener hosts (bit.ly, t.co and the rest, listed in full in the privacy policy), on by default for links you open and opt-in for links you only hover; no MUGA server is contacted either way.
esbuild, used only to bundle the cleaning library into the content script; output is committed to the repo). Development tooling such as the linter and the web-ext packager does not ship in the extension and does not transform what runs.
What MUGA Does With Your Data
URLs. Cleaned locally inside your browser by the content script's bundled cleaning library. The cleaning runs inline in the page's content script. It does not round-trip through the service worker or any external server. URLs are never sent anywhere. Session history (this session's list of cleaned URLs, per-tab badge counts, debug logs) lives in chrome.storage.session and is automatically cleared when the browser restarts. One record outlives the session: Recent activity (attributionLedger) keeps the last 10 URLs MUGA cleaned for you in chrome.storage.local, on this device only, and its switch in Settings > Advanced turns it off. Two other local records carry no full URLs: parameter names seen per site, with values stored only as one-way hashes (crossSiteFreq), and per-site counts of removed parameters for up to 50 sites (domainStats). Each has its own switch.
Behavioural preferences. Stored in chrome.storage.sync: language, blacklist, whitelist, custom tracking parameters, and the default values for the affiliate toggle and remote-rule-updates toggle. Encrypted and managed by your browser, synced to your Google or Firefox account, not to any server we control or can access.
Consent and per-device decisions. Stored in chrome.storage.local (this device only): your acceptance of the Terms (onboardingDone, consentVersion, consentDate), and per-device overrides for remoteRulesEnabled when a synced preference arrives enabled and you decline to inherit it. The reasoning is captured in ADR-0001: consent is an act between you and the device you are using; inheriting it across devices silently would deny each device's user the chance to read and decide.
Stats. Local counters only: URLs cleaned, parameters removed, referrals spotted. Stored in chrome.storage.local. No personally identifiable information. No timestamps tied to individual URLs.
Domain stats. Domain names and parameter counts only. No full URLs, no paths, no timestamps. Stored locally, capped at 50 domains to prevent unbounded growth. Never transmitted.
Affiliate tags. MUGA does not add any affiliate tag of its own. By default, it respects the original referral: if a creator you follow earned an affiliate tag on a link, it stays in place, locally, with no API call involved. If you enable "Remove all affiliate tags from other sources", the third-party affiliate tags MUGA recognises are stripped from the URL; this is an optional extra, off by default, and MUGA never adds its own tag in their place.
Architecture: Where the Work Happens
MUGA is split into two small components that talk to each other only when strictly necessary:
The content script. Runs in every page (subject to your blacklist/whitelist). It owns the user-visible work: URL cleaning on click, on copy, and on page load; <a ping> attribute removal; redirect-wrapper unwrapping; and (on Firefox) AMP-to-canonical redirect. The cleaning library ships inside the content script as a pre-built bundle (src/content/cleaner-bundle.js), generated from the ES module sources under src/lib/ by tools/bundle-content.mjs. The bundle is committed to the repository so reviewers can verify it matches the unbundled source byte-for-byte.
The service worker. Runs in the background. It owns three things: (1) cross-cutting state that the content script doesn't need to compute itself, namely incrementing the badge counter and stats on a fire-and-forget message (the BADGE_AND_STATS side-channel), (2) cross-page coordination such as the toolbar action surface, the context-menu entries, and the optional weekly remote-rules fetch, and (3) the consent state machine, covering onboarding, soft and hard re-onboard, and the migration from legacy sync-stored consent to local. The service worker does not see or process URLs in transit; cleaning is finished before the service worker hears about it.
Why this split matters for transparency. Most extensions route URLs through their service worker so the worker can decide what to do. MUGA does the opposite: the cleaning runs in the page where you clicked, the service worker hears only the post-cleaning summary it needs to update the badge. There is no central pipeline that observes your URLs.
Per-Device Consent
MUGA records your acceptance of its Terms and Privacy Policy per device, not per browser account. Installing and using MUGA is what constitutes acceptance, and each device records that for itself rather than inheriting it from another one. Behavioural preferences (language, toggles) still follow your account through sync, but the consent to act on them is local. The full reasoning is in ADR-0001.
No re-prompting. Changing the Terms does not interrupt you and does not gate any feature until you acknowledge it. MUGA follows the model uBlock Origin uses: the documents are permanently reachable rather than announced once, linked from onboarding, from the popup and from the Settings footer. The versioned re-acceptance engine that used to gate features was removed, along with roughly a thousand lines whose only job was deciding when to interrupt you about a document change. The reasoning is in ADR-0007.
Migration on upgrade. If you previously installed MUGA before per-device consent shipped and your acceptance was stored across devices via sync, MUGA migrates that acceptance to local storage on the first run after upgrade. The migration is one-way (sync → local) and idempotent. You keep your acceptance state without re-onboarding. Implemented in src/lib/sync-migration.js.
What We Deliberately Don't Do
- No telemetry or usage analytics. We have no idea how often you use MUGA or which features you use.
- No crash reporting. If the extension throws an error, it logs to your browser console. Nowhere else.
- No remote configuration or feature flags. Every toggle is a local preference. There is no server that can change your extension's behavior remotely.
- No server-side rule delivery beyond a weekly signed check. The 361+ tracking parameter list and domain rules ship bundled with the extension at install time; that baseline never depends on the network. On top of it, Remote rule updates is on by default: the extension fetches a signed parameter list at most once per 7 days from
rules.muga.appvia HTTPS GET withcredentials: "omit"andcache: "no-store": no browsing data is sent, no cookies, no account, no identifiers in the request. Like any request to any website, it does reveal your IP address and the time of the request to whoever serves the file; MUGA neither logs nor stores this. You can disable it any time in Settings. Turn off both "Follow shortener redirects" switches as well and the extension makes zero outbound requests; resolving a short link you open is on by default and contacts that link's host. This default was flipped in the release documented in the CHANGELOG (#888), once the rule-signing infrastructure and defense-in-depth verification were ratified as production-ready. - No server-side redirect for affiliate links. Creators come first. We evaluated 10+ affiliate programs that require routing your click through an external tracking server. We rejected every one of them.
- No A/B testing infrastructure. Every user runs the same code.
- No user accounts or sign-in. We have no concept of a MUGA user identity.
What We Used To Claim, And No Longer Do
For a product whose identity is honesty, silently retiring a claim is weaker than naming it. These are commitments MUGA made publicly and later reversed, and why.
- MUGA injects its own affiliate tag on supported stores (retired 2026-07-28, ADR-0006). MUGA now adds no affiliate tag of its own on any store, and never monetizes a click. Only third-party creator referrals are preserved, best-effort.
- MUGA refuses redirect-based affiliate networks on principle (retired 2026-05-24, ADR-0002). That exclusion silently cut most long-tail creators out of the "fair to creators" promise, so it was dropped. MUGA is creator-agnostic and attribution-model-agnostic.
Permissions Explained
Every permission MUGA requests, across its Chrome (manifest.json) and Firefox (manifest.v2.json) manifests, has a specific, minimal purpose. Here is what each one is and why it exists.
How to Verify
Every claim on this page is verifiable. You don't have to take our word for it.
- Read the source code. github.com/yocreoquesi/muga. Every line that runs in your browser is published there.
- Build from source. Clone the repo and run
npm ci && npm run build. The packages it writes todist/chrome/anddist/firefox/are the ones uploaded to the Chrome Web Store and Firefox AMO; the release workflow (.github/workflows/release.yml) runs the same two commands. - Verify the content-script bundle matches its source. The cleaning library is bundled into the content script via esbuild (
tools/bundle-content.mjs, ~30 lines) because MV3 content scripts cannot use ES module imports portably across Chrome and Firefox MV2. The unbundled source lives undersrc/lib/and the committed bundle output issrc/content/cleaner-bundle.js. Runnpm run build:contentand diff the regenerated output against the committed file. It must match exactly. There is no TypeScript, Babel or JSX: everything else is plain vanilla JavaScript. - Know every build-time transformation. Besides the committed content bundle,
npm run buildmakes three changes on the way to the store package, all in the repository:tools/strip-test-seams.mjsrewriteslib/test-fixtures.jsto an inert stub and removes the__MUGA_TRUSTED_KEYS__test seam frombackground/service-worker.js; the Firefox build swapssrc/manifest.v2.jsonin asmanifest.json(scripts/with-firefox-manifest.sh); and a few development-only files are left out with--ignore-files(see thebuild:chromeandbuild:firefoxscripts inpackage.json). - Diff the published extension. Unpack the installed extension (Chrome:
chrome://extensionsin developer mode; Firefox: extract the XPI) and diff it against the packagenpm run buildproduced for that browser from the same release tag, not against rawsrc/. Againstsrc/you should expect exactly the differences listed above (lib/test-fixtures.js,background/service-worker.js, andmanifest.jsonon Firefox), plus the signature files each store adds (Chrome's_metadata/, Firefox'sMETA-INF/). - Check network requests yourself. Open your browser's DevTools Network tab while using MUGA. On a default install you will see at most one HTTPS GET to
rules.muga.appper 7 days (Remote rule updates is on by default). Resolving a short link you open is also on by default, so opening abit.ly-style link shows a request to that link and the hops it redirects through. Disable Remote rule updates and both "Follow shortener redirects" switches in Settings and you will see zero outbound requests initiated by the extension. - Read the coding standards.
AGENTS.mdandCONTRIBUTING.mdin the repository document the automated review rules that enforce these constraints on every pull request. - Read the architectural decision records.
docs/adr/captures the reasoning behind decisions like per-device consent. If you want to know why something is built the way it is, the ADRs are where the trade-offs are written down.