muga.app

Transparency Report

MUGA: Clean URLs, tracking removed  ·  Version 3.1.0  ·  2026-09-11  ·  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 3.1.0
External server connections Remote rule updates: on by default, at most 1 HTTPS GET per week to 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.
Analytics / telemetry None. No analytics, no telemetry, no usage reporting. We have no plans to add any.
Data sent anywhere Never your browsing data. Remote rule updates make HTTPS GETs to 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.
Third-party dependencies 1 runtime (browser-polyfill.min.js for Firefox compatibility) + 1 build-time transform of the shipped code (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.
Open source license GPL v3
Detection accuracy (measured) Measured against a 42-URL labelled corpus: 0 false positives, 0 false negatives (a labelled sample, not a real-world guarantee).

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

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.

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.

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, trigger the context menu, or use the keyboard shortcut (Alt+Shift+C) on browsers and platforms that support it. 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.
webRequest, webRequestBlocking (Firefox only)
On Firefox, MUGA strips tracking parameters at the network layer with a blocking webRequest listener, which is how it does on Firefox what declarativeNetRequestWithHostAccess does on Chrome. The listener runs locally in your browser, inspects the request URL only to remove known tracking parameters, and sends nothing anywhere. These permissions are not requested on Chrome, which uses the declarative rule engine instead.
optional_host_permissions: https://rules.muga.app/* (Chrome MV3) / optional_permissions (Firefox MV2)
The Remote rule updates preference is on by default (see the CHANGELOG). It is declared as an optional host permission so it stays visible; MUGA's broad host access already covers it, and the Settings switch is what turns the fetch on or off. 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. Turn off Remote rule updates in Settings to stop the fetch.

How to Verify

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