Updated: 2025-06-12
(If you just want to know my solution, skip to Reading .desktop
Files.)
Linux is a very powerful operating system that gets more user-friendly by the year, but it still has glaring holes. Today, I discovered there is no reliable method to finding out if a browser is installed.
Searching online reveals that most people only care about knowing if specific browsers are installed, or are content with the incomplete option of only checking for the most popular browsers (currently Chrome, Firefox, and Opera). The which
command works fine combined with a resource like LinuxConfig.org’s List of Browsers available on Linux, but now your script requires periodic maintenance to add more browsers to the list1.
The next most common answer online is to see if xdg-open
exists, based on the assumption that a browser must be installed if xdg-open is installed – this is simply false. You also can’t query xdg-open to see if it can handle URLs without opening a URL. If you use this method, you are effectively attacking the user with a pop-up2.
I’ve also found documentation for update-alternatives
, but it requires knowing exactly what name it uses for browser entries. I was told to use x-www-browser
, gnome-www-browser
, and just www-browser
. None of these work, and the command doesn’t allow you to list all of its entries because the --all
option forces you into an interactive session to configure every single option it has. I refuse to go through that mess just to find how browsers are defined.
This should be simple, shouldn’t it?
Worse, I’ve also found multiple users stating that this fails to adhere to system defaults on Ubuntu, despite it being Ubuntu’s official default method.. and it doesn’t even WORK.
There’s also Debian Wiki’s DefaultWebBrowser which is somehow too dense and too sparse, and in light of what I’ve already tried – nonsensical. Suggesting the use of a $BROWSER
environment variable strikes me as particularly insane6.
The best option I can find right now is to manually scan every menu entry for programs categorized with WebBrowser
3. This still excludes some options, is convoluted, and has the possibility of failing due to mistakes in menu entries. But it’s the closest to a future-facing solution I could find.
(While asking an unrelated question on the Linux Mint Forums, I did get more information about browser defaults, which you may find useful.)
Reading .desktop
Files
Update: xdg-settings get default-web-browser
basically has already done what I was doing here5. If anything has a .desktop
file for a browser, that should return whatever default has been selected, thus telling you a browser is installed.4
Menus in Linux use a standard format to describe programs/actions so they can be automatically organized. Even some CLI apps create these entries as well. These are organized by predefined Categories, including WebBrowser
. While this may still exclude some niche browsers, the users of such browsers likely will know how to handle this incompatibility, and are very very rare.
The only issue with this solution is finding the files and having to parse them yourself. This is still a little tedious, but will last longer and detect new browsers automatically. Unfortunately, the only information I found on where these files should be is conflicting slightly. The Arch wiki says they are in 3 specific locations, but the actual spec excludes one of those and specifies an environment variable where the rest are located. So I check all of these locations, scan every file, and look for two things: 1) A Categories key with “WebBrowser” in it. 2) No Hidden key.
For my specific use case, since I only need to know a browser is installed, I can exit this search on the first hit, but obviously you can use the spec to actually find which browsers are installed, and even launch them or show their icons!
For reference’ sake, here’s what a .desktop
file for LibreWolf could look like:
[Desktop Entry]
Type=Application
Name=LibreWolf
Comment=Privacy-focused web browser
Exec=/path/to/librewolf
Icon=/path/to/icon.png
Categories=Network;WebBrowser;
What the hell am I doing this for anyhow?
I’m writing a script to help me automatically select and install packages on a Linux system so that I don’t have to remember or constantly look up how to install things that aren’t part of the standard package management of my system, or the names of things I may have forgotten about because I use them rarely.
The fundamental design of this script includes the ability to run installs and configurations in any order, except where dependencies require a specific order. Part of it removes Firefox due to Mozilla’s recent privacy violations7, another part adds a replacement browser, but other parts of the script require a functioning browser to function. Initially, I thought I just needed a check to see if any browser is present, but later I realized I need to be able to count how many browsers are installed. While I’m glad I found out there is a simpler way to check for any browser, I’m still using a manual scan of .desktop
files because I need to count them.
(As I write this, I realize that while my current solution addresses most of my needs, I should have each browser-requiring section of the script verify a browser is present, instead of requiring the user to briefly have two browsers installed at once. While I still think it’s better to not remove a browser until its replacement is installed just in case, there is a hole in my dependency management here – especially because the user can do their own things outside of my script, obviously.)
Footnotes
- Any decision that adds future maintenance costs should be made very carefully and avoided if possible. Do you really want to devote a portion of the rest of your life to making sure this keeps functioning? Do you really want to limit your list of acceptable browsers to only what’s popular now?
- How long has it been and we still don’t force applications to open without stealing window focus at an OS level? There are always heavyweight applications, no matter how fast computers get, and computers are fundamentally designed for multitasking. We should be able to start a program and do something else while waiting for it to open, without the risk of random inputs being sent to the program when it is finally ready. Combine this with the fact that many programs steal focus before they’re even ready to accept input and it’s a garbage user experience.
- Thanks to Arran Ubels on StackOverflow for helping me find this answer.
- In theory, a browser could still be installed that has its desktop file in the wrong place, but then it is likely the system won’t recognize it for using
open
or similar commands anyhow. For my use case, that means it is not worth continuing to look for a browser being installed, but depending on what you’re doing, you may want to search further. Heck, if it’s really important, you might want to find every desktop file on the computer to check for a browser – though at that point you should probably just be doing something to ensure a browser is ready yourself instead of trying so hard to find an extant badly configured browser.. - Thanks to @CcxCZ on Telegram for telling me about this command! It’s really strange that it didn’t appear anywhere in my searches for information on this.
- It was pointed out to me that I should elaborate on this: Environment variables are easily manipulated and overwritten accidentally when they have simple names. (For a counter-example, I don’t worry about referencing
$XDG_DATA_DIRS
because it is unlikely to be screwed up.) - A more aggressive take on it. While they can legally defend themselves on the basis of no evidence of violation occurring so far, so can every company that regularly destroys your privacy. Companies don’t remove assurances about privacy unless they’re going to stop protecting your privacy. Companies do not care about your privacy.
Updates
- Updated 2025-06-12: Added a link to a thread on Linux Mint Forums that has additional information about default browsers.
- Updated 2025-06-08: Added a section explaining why I’m doing this differently than the simple solution at the end.