UserAgent-Switcher: spoofing the header and the navigator at the same time
A User-Agent spoofer browser extension that is highly configurable
At a glance
- What is it?
- UserAgent-Switcher is an MPL-2.0 licensed browser extension that changes the User-Agent string in request headers and in the JavaScript navigator object, covers Client Hints and navigator.userAgentData, and can apply different values per hostname, per tab or per Firefox container, with a random pick from your own list. It ships on the Chrome, Firefox, Edge and Opera stores, and the repository also documents loading it unpacked from source.
- Who is it for?
- Adopt UserAgent-Switcher if you need to test how a site behaves for a different client, and you have concluded that the request header alone is not enough, because the extension changes the navigator properties as well and handles the modern Client Hints path.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two layers, because one is not enough
UserAgent-Switcher is a highly configurable browser extension for spoofing your User-Agent string, and the first thing it fixes is the most common mistake people make when they try to do this by hand.
Changing the `User-Agent` request header is only half of it. A page can also read the browser's identity from JavaScript, through `navigator.userAgent`, `navigator.appVersion` and `navigator.platform`, and those are separate strings that a server never sees. A header-only spoof is detected by any script that compares the two.
The extension therefore modifies both the User-Agent in your browser's request headers and the relevant JavaScript `navigator` properties, and it also supports the modern browser identification mechanisms, Client Hints headers and the `navigator.userAgentData` object, ensuring consistent and comprehensive spoofing across all detection methods.
That last clause is the part that distinguishes this from the older crop of user agent switchers, which predate Client Hints entirely. When a browser sends `Sec-CH-UA` headers and exposes `navigator.userAgentData`, a page that reads either of them can tell that the request header and the JavaScript environment disagree, or that neither matches the browser it claims to be. Handling that path is what makes the extension useful against current detection code rather than only against sites that check a single string.
The intended user is a developer or tester who needs a specific client identity, and a user who wants a different identity for one site without changing it everywhere. The primary language is JavaScript, the licence is MPL-2.0, the default branch is `master`, and the last push was on 2026-10-03 with the repository not archived. There are no GitHub releases, since the distribution channel is the browser add-on stores, and the project page is the webextension.org listing.
Granularity: per host, per tab, per container
The control model is the second thing that makes the extension configurable rather than merely a switch, and it has three levels.
The first is per specific hostname. You can set a User-Agent for one site and leave the rest of the browser alone, which is the difference between a testing tool and a global masquerade.
The second is per individual browser tab. Two tabs can carry different identities at the same time, which matters when you are reproducing a bug that only appears for one client type and need the same site open in another configuration next to it.
The third is Firefox's container feature, which gives distinct User-Agents per container, so that a set of tabs belonging to one identity can be separated from the rest. The README is explicit about a limit here: the container feature is not available on manifest v3 yet. That is a real constraint, since the manifest versions in the repository directory structure, `v2/` and `v3/`, indicate the project maintains code for both generations, and the container trick belongs to the older one.
On top of the three scopes there is randomisation. The extension can randomly select a User-Agent from a list that the user defines, which is a way of emulating a population of clients rather than a single one.
And the lists themselves are manageable in bulk. The extension supports easy import and export of User-Agent lists, which is the feature that makes it practical at scale: you can maintain one list, move it between browsers, and share it, rather than typing strings into a field one at a time.
The configuration story is documented separately from the README, on a usage guide hosted at webextension.org, and the README directs readers there for detailed instructions on configuration options and features.
Installing from the stores, and the names differ per browser
The official route is the add-on store of whichever browser you use, and the listing names are not the same everywhere, which is worth noting before you go looking.
On Chrome it is listed as User-Agent Switcher and Manager, on Firefox as User-Agent String Switcher, on Edge as UserAgent Switcher and Manager, and on Opera as User-Agent Switcher. The project links all four.
The store route is what most people want, because it gives you updates and it does not require a developer mode toggle. The README also links a video review of the extension and the project listing page, which is where the configuration documentation lives.
There is a second reason the store route is preferable, which the README does not say outright but which the manual installation section makes clear. An unpacked extension in Chromium or a temporary add-on in Firefox is tied to a directory and to a session, and the identifier assigned to it can change, which breaks anything that depends on the extension's identity.
So the choice is between a maintained, identified, automatically updated extension from the store, and a locally built copy that you control the source of and that reflects whatever is in the repository, including the code that has not been reviewed yet.
Loading from source in Chromium and in Firefox
The manual installation instructions are detailed, and the two browsers differ enough that it is worth following the matching section.
For Chromium-based browsers, which the README groups as Google Chrome, Microsoft Edge and Opera, you need the extension's source files, including `manifest.json` at the root of the extension's directory, and if there is a build process such as `npm run build` you run it first to generate the distributable files. Then you open the browser's extensions page, which is one of:
chrome://extensions
edge://extensions
opera://extensionsYou enable Developer mode using the toggle switch in the top-right or bottom-left corner, and then a Load unpacked button appears, which you click and point at the directory containing `manifest.json`. If you make changes to the source code you return to the extensions page and click Reload for the extension.
Firefox has two methods. The first loads a temporary add-on: go to `about:debugging`, select This Firefox in the left-hand sidebar, click Load Temporary Add-on, and select the `manifest.json` file, or any file within the extension's root directory. It stays installed until you restart Firefox or remove it manually, and changes need a click on the Reload button next to the extension's entry.
The second method is more persistent. You make sure all the source files are present with `manifest.json` at the root, select all the files and subfolders inside that directory, compress them into a ZIP archive, and change the extension from `.zip` to `.xpi`. You then open the Add-ons Manager at `about:addons` or with `Ctrl+Shift+A`, click the gear icon on the Extensions panel, choose Install Add-on From File, and select the `.xpi`.
The `manifest.json` must be at the root level within the archive, and that constraint is the most common way to get an `.xpi` that Firefox refuses to install.
Extension ID stability, the quiet failure mode
The last section of the README is about something that looks like a footnote and is in practice a common source of confusion.
The extension ID consistency matters for stable development and testing, especially if your extension uses storage or needs a consistent ID for APIs. The fix differs by browser.
In Chromium-based browsers you can add a `key` field to your `manifest.json`. It is a Base64 encoded public key, and if the `key` field is present when loading an unpacked extension, Chrome, Edge and Opera will derive a consistent ID. Without it, the ID may change if the path to the extension folder changes.
In Firefox you ensure the `manifest.json` includes a unique add-on ID via the `browser_specific_settings.gecko.id` field, for example:
"browser_specific_settings": {
"gecko": {
"id": "[email protected]"
}
}The repository layout explains why this matters more than it might appear. The top level holds `v2/`, `v3/`, `node/`, `store/` and `test/`, so the project carries code for two manifest generations, and the `node/` directory is what a browser loads for the newer one, while the `v2/` directory carries the older manifest. The `store/` directory is what is published to the add-on stores.
A user agent switcher is exactly the kind of extension where an ID change is annoying rather than fatal, since it holds a list of strings rather than account data. But for a developer testing an extension that stores state, an ID that moves with the directory is a source of settings that appear to vanish, and the fix is a two-line manifest change that the README documents.
Where a User-Agent switcher is the wrong tool
There are three cases where this extension does not solve the problem it appears to solve, and the first is the most common disappointment.
The first is anonymity. Spoofing the User-Agent does not make you anonymous, and the README does not claim otherwise. A request that carries a different user agent still carries your IP address, your cookies, your `Accept-Language`, your `Sec-CH-UA` client hints beyond the ones the extension covers, and any fingerprinting script that looks at canvas, fonts, screen dimensions or timing will see a browser that does not match the string it was told. If the goal is privacy, the extension is the wrong instrument.
The second is a site that has already moved past the User-Agent. Plenty of services now treat the header as a hint and use the client hints and the JavaScript environment together, and a site that cross-checks them will reject the mismatched pair that this extension produces, because a real browser would not send a header and a navigator that disagree.
The third is a test that needs a whole browser rather than a string. A user agent string describes a client in one line and cannot reproduce the behaviour of a specific mobile device with a specific engine version, its headers, its APIs and its quirks. That is what a device farm or a real device is for.
The alternative approach, and the one to weigh against, is to use a browser that actually is the client you want to be. If the goal is to check how the site behaves in Safari on iOS, then running Safari on iOS answers the question exactly, while any spoofed string only approximates it. The difference in approach is between changing what a site is told and being what a site expects, and for anything beyond a quick look at a user agent parsing routine, the second is the one that gives you a true answer.
Used as what it is, a testing instrument with three levels of scoping and a bulk list import, it is well built. The extension's own feature list, comprehensive spoofing, granular control, randomisation and easy import and export, describes that instrument accurately, and the honest framing of the project is that it is a developer tool rather than a privacy tool.
Editorial conclusion
Adopt UserAgent-Switcher if you need to test how a site behaves for a different client, and you have concluded that the request header alone is not enough, because the extension changes the navigator properties as well and handles the modern Client Hints path. Do not adopt it if the goal is to hide your identity from sites that fingerprint more deeply than the User-Agent, since no user agent string defeats that, and treat it as a development and testing tool rather than a privacy tool. Verify three things first: that the value you need actually exists in the list you configure, since the extension spoofs a string you supply rather than a catalogue it maintains, that the target site is not one where a mismatched Client Hints header produces a different failure than the one you are reproducing, and that the extension ID stays stable, because on Chromium an unpacked extension without a `key` field in `manifest.json` changes its ID when the path changes.
Frequently asked questions
What does the UserAgent-Switcher extension actually change?
It modifies the User-Agent in the browser's request headers and the relevant JavaScript navigator properties such as navigator.userAgent, navigator.appVersion and navigator.platform. It also supports Client Hints headers and the navigator.userAgentData object, so spoofing is consistent across modern detection methods.
How finely can UserAgent-Switcher control the User-Agent?
Per specific hostname, per individual browser tab, and per Firefox container. The container feature is not available on manifest v3 yet, and the extension can also randomly pick a User-Agent from a list you define, with import and export for managing those lists.
How do I install the extension from source in Chrome?
Make sure the source files including manifest.json are on disk, run the build first if there is one such as npm run build, then open chrome://extensions, edge://extensions or opera://extensions, enable Developer mode, click Load unpacked and select the directory containing manifest.json. Click Reload after code changes.
How do I load the extension in Firefox from source?
Open about:debugging, select This Firefox, click Load Temporary Add-on and pick the manifest.json, which lasts until Firefox restarts. For a persistent install, zip the extension files with manifest.json at the root, rename the archive to .xpi, then install it from about:addons via the gear icon and Install Add-on From File.
Why does the UserAgent-Switcher extension ID change?
Because an unpacked Chromium extension without a key field in its manifest.json gets an ID that can change when the path to the folder changes. Add a Base64 encoded public key in the key field, and on Firefox set browser_specific_settings.gecko.id to a unique value such as [email protected].
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ray-lothian-useragent-switcher)Was this useful?