Transparency Report

MUGA: Clean URLs, Fair to Every Click  ·  Version 1.13.5  ·  2026-05-05  ·  Source code

Privacy policies say "we don't collect your data." This page shows the evidence behind that claim: what MUGA actually does, which permissions it uses and why, and how you can verify every statement yourself.

At a Glance

Version 1.13.5
External server connections 0 by default zero. 1 HTTPS GET per week to rules.muga.app if you enable Remote rule updates in Settings (off by default). No cookies, no identifiers, no POST body. Auditable open-source endpoint.
Data collected None
Data sent anywhere None. Not even to us.
Third-party dependencies 1 runtime (browser-polyfill.min.js for Firefox compatibility) + 1 build-time (esbuild, used only to bundle the cleaning library into the content script; output is committed to the repo)
Open source license GPL v3

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 stored beyond the current session. Session history (recently cleaned URLs, per-tab badge counts, debug logs) lives in chrome.storage.session and is automatically cleared when the browser restarts.

Behavioural preferences. Stored in chrome.storage.sync: language, blacklist, whitelist, custom tracking parameters, and the default values for the affiliate toggles 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 injectOwnAffiliate and 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. Injected locally by the content script when you visit a supported store with no existing tag. No API call is made to decide when or where to inject. The logic runs entirely in your browser against a list of domains that ships with the extension. If you also enable "Remove all affiliate tags from other sources", MUGA's own tag is preserved only when you also have affiliate injection enabled on this device, symmetric with your stated preference.

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. If you install MUGA on a second device, you'll be asked to read and accept the documents on that device too, even if you already accepted them somewhere else. 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.

Re-onboarding. If we materially change the Terms, MUGA surfaces a re-acceptance flow on each device the next time the service worker wakes up; affected features are gated until you re-accept. If we only add clauses (without changing existing ones), MUGA shows you the new clauses and lets you accept or decline; declining keeps you under the previously accepted Terms.

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

Permissions Explained

Every permission in manifest.json has a specific, minimal purpose. Here is what each one is and why it exists.

storage
Save your preferences, local stats, and session data. Without this, your settings would reset every time the browser restarts.
activeTab
Read the current tab's URL when you open the popup, use the keyboard shortcut (Alt+Shift+C), or trigger the context menu. This permission only activates on your explicit action. MUGA cannot read your tabs in the background.
contextMenus
Add the "Copy clean link" and "Copy clean selection" entries to your right-click menu. Without this permission, the entries cannot be registered.
clipboardWrite
Copy cleaned URLs to your clipboard when you use the context menu or keyboard shortcut. This is a fallback for pages where the modern Clipboard API is blocked by the page's own content security policy.
declarativeNetRequest (Firefox) / declarativeNetRequestWithHostAccess (Chrome)
Strip tracking parameters and (on Chrome) redirect AMP pages to their canonical URLs before the page loads, using the browser's own built-in rule engine. The rules run entirely inside the browser. No request is sent to an external service to evaluate them. The WithHostAccess variant on Chrome is required to apply redirect rules across all sites. On Firefox MV2, the AMP redirect happens locally via the content script instead of the network-layer engine, because the equivalent dynamic-rules API is not available.
host_permissions: <all_urls>
Required for content scripts to run on every page (URL cleaning, ping blocking, AMP redirect, redirect unwrapping) and for declarativeNetRequest redirect rules to apply on all sites. Without this, MUGA would only work on a predefined list of domains.
optional_host_permissions: https://rules.muga.app/* (Chrome MV3) / optional_permissions (Firefox MV2)
Granted only when you enable Remote rule updates. Used to perform a single HTTPS GET (at most once per 7 days) to fetch the signed tracking-parameter list from the project's public endpoint (https://rules.muga.app/rules/v1/params.json). The request is sent with credentials: "omit" and cache: "no-store": no cookies, no user identifiers, no POST body. The refresh is triggered by natural service-worker wake events (a page visit, a browser startup, a message from the popup) combined with a stored "last-fetched" timestamp; no background alarm permission is used. The endpoint is open source and auditable. You can revoke this permission at any time via your browser's extension settings.

How to Verify

Every claim on this page is verifiable. You don't have to take our word for it.