qutebrowser
qutebrowser is a free and open-source web browser designed for keyboard-focused navigation with a minimal graphical user interface.[1] It is developed using Python and the Qt framework, primarily employing the QtWebEngine rendering engine based on Chromium for displaying web content, while optionally supporting the deprecated QtWebKit backend.[2][3] Inspired by the Vim text editor as well as earlier browsers and extensions like dwb and Vimperator/Pentadactyl, qutebrowser provides vim-style key bindings for actions such as scrolling (using hjkl), following links via hints, and tab management, enabling efficient mouse-free operation.[4][5] The project was initiated by primary developer Florian Bruhin with its initial commit on December 14, 2013, and achieved its first stable release (version 1.0.0) on October 12, 2017; as of November 2025, it has reached version 3.6.1, with ongoing part-time development funded by community donations.[6][7] qutebrowser is licensed under the GNU General Public License version 3 or later and is cross-platform, supporting Linux, Windows, and macOS on systems with Python 3.9 or later and compatible Qt versions.[2][8] Key features include built-in ad blocking, session restoration, userscript support for extending functionality (such as integration with password managers), customizable key bindings and themes via a Python configuration file, and commands for tasks like searching, downloading, and quick-marking pages.[9][3][5]History
Origins and inspiration
qutebrowser was created by Florian Bruhin, known online as "The-Compiler," in late 2013 as a personal project aimed at addressing the shortcomings of existing keyboard-centric web browsers.[10] At the time, Bruhin was frustrated with the instability and limitations of options like dwb, which was facing discontinuation due to challenges in transitioning to WebKit2, as well as alternatives such as uzbl and luakit that lacked desired features or ease of development.[11] His goal was to build a more reliable, standalone browser that prioritized keyboard-driven navigation in a Vim-like style, avoiding the constraints imposed by browser extension APIs in tools like Firefox add-ons.[12] The project drew primary inspiration from dwb, a minimal GTK-based browser emphasizing keyboard controls and a sparse graphical interface, as well as the Firefox extensions Vimperator and its successor Pentadactyl, which introduced Vim-inspired keybindings for efficient, mouse-free browsing.[1] These influences shaped qutebrowser's core philosophy: a minimal GUI that places keyboard primacy at the forefront, enabling users to perform most actions through commands and bindings without relying on graphical elements or external dependencies.[2] By developing it as an independent application using Python and Qt, Bruhin sought to create a flexible platform free from the evolving restrictions of host browser ecosystems, allowing for deeper customization and stability.[13] Development began as a prototype in December 2013, with Bruhin committing the initial code on December 14.[14] After roughly a year of iteration to refine basic functionality and integrate early rendering support, the first public release, version 0.1, arrived on December 14, 2014, marking qutebrowser's debut to the open-source community via GitHub.[15] This timeline reflected Bruhin's part-time efforts to establish a solid foundation, focusing on core navigation and configuration features before broader adoption.[16]Release history
qutebrowser's development has followed a measured release cadence, with major versions typically arriving annually, supported by part-time maintenance from its primary developer, Florian Bruhin. The project began with an initial release focused on basic vim-like navigation using QtWebKit as the rendering backend. Over time, key milestones marked transitions in rendering engines, privacy features, and platform support. The shift from the deprecated QtWebKit to QtWebEngine as the default backend occurred progressively starting in version 1.x, enabling better compatibility with modern web standards.[6] Ad blocking was integrated in version 2.0 using a Rust-based parser inspired by Brave, enhancing privacy without external dependencies.[17] PDF viewing support was added via the Apache-licensed pdf.js library in version 1.11.1. The following table summarizes major milestone releases, their dates, and principal updates:| Version | Release Date | Key Updates |
|---|---|---|
| v0.1 | December 14, 2014 | Initial release with vim-like key bindings and QtWebKit backend. |
| v1.0.0 | October 12, 2017 | Stable core features, modern configuration system, and QtWebEngine as default backend.[6] |
| v2.0.0 | January 28, 2021 | Integrated Rust-based ad blocking, dropped support for Qt < 5.12 and older OS versions (macOS < 10.14, Windows < 8.1).[17] |
| v3.0.0 | August 18, 2023 | Qt 6 support as default, dropped Qt < 5.15 and older platforms (macOS < 11 Big Sur, Windows < 10 1607). |
| v3.4.0 | December 14, 2024 | Marked 11-year anniversary, full Qt 6.8 support, on-demand clipboard permission prompts. |
| v3.5.0 | April 12, 2025 | Minor enhancements and bug fixes, including updated pdf.js integration. |
| v3.5.1 | June 5, 2025 | Patch release addressing stability issues post-v3.5.0. |
| v3.6.0 | October 24, 2025 | Recent enhancements like shadow DOM hinting and hardware-accelerated canvas support via Qt 6.10.0. |
| v3.6.1 | November 3, 2025 | Patch release fixing keyboard focus regression.[18] |
Features
User interface
qutebrowser features a minimalistic graphical user interface designed to prioritize keyboard-driven interaction and reduce visual clutter. By default, it omits traditional elements such as a dedicated address bar or bookmark bar, instead relying on a status bar positioned at the bottom of the window to display essential information including the current URL, active mode, and loading progress. The tab bar is shown at the top.[1][3] The interface operates in distinct modes to facilitate different types of user input, with visual feedback provided through changes in the status bar. These include command mode as the default state for navigation and commands, insert mode for text entry in web forms, and hint mode for selecting links via overlaid labels. The status bar updates its appearance—such as color schemes or icons—to clearly indicate the current mode, enhancing usability without additional UI elements.[9][3] Customization options allow users to tailor the interface to their preferences while maintaining its core simplicity. Themes can be applied using Qt stylesheets to modify colors, fonts, and layouts for components like the status bar and completion menus; for instance, users can adjust background and foreground colors for modes or progress indicators. Completion menus for commands, URLs, and search terms appear as fuzzy-searchable popups with configurable height and categories, and fullscreen mode is supported to expand the browser window for an immersive viewing experience.[9][3] qutebrowser ensures a consistent user interface across multiple operating systems, including Linux, Windows, macOS, and FreeBSD, leveraging Qt for uniform rendering and behavior. The default search engine is set to DuckDuckGo, which integrates seamlessly into the status bar's URL display and completion features.[1][3]Keyboard navigation and bindings
qutebrowser employs a vim-like keyboard navigation system designed to facilitate efficient, mouse-free web browsing in its normal mode, where most interactions occur. This system draws from Vim's modal editing paradigm, allowing users to perform scrolling, navigation, and commands using single keystrokes or short sequences.[5] Scrolling is handled with the keysh for left, j for down, k for up, and l for right, mimicking Vim's movement commands to pan the viewport incrementally. History navigation uses uppercase variants H to go back and L to go forward in the session history. The hint mode, activated by pressing f, overlays labels on interactive elements like links and form fields; typing the corresponding label (a short string of letters or numbers) follows or activates the element, enabling rapid selection without precise mouse aiming.[3][5]
To enter commands, users press : , opening a prompt for ex-style commands such as :open <URL> to load a webpage in the current tab, :tab-new to create and focus a new tab, or :search <query> to highlight text matches on the page. Page-specific searching is invoked with / followed by the query and Enter, with n to jump to the next match and N for the previous, providing quick incremental search similar to Vim.[21][5]
Zooming in and out is achieved with + to increase the scale and - to decrease it, applying relative adjustments to the page's rendering. Media controls include bindings like m to mute or unmute the current tab's audio, and recent versions introduce defaults such as ti to toggle automatic image loading via the content.images setting. Fullscreen mode toggles with F11. The Escape key exits hint mode, search, or command prompts, returning to normal mode.[21][20][3]
Keybindings are highly configurable through the config.py file using config.bind('<key>', '<command>', mode='normal') to override or add mappings, allowing personalization while preserving the core vim-inspired layout. Quickstart essentials include o to open a URL or search in the current tab, O for a new tab, d to close the current tab, and u to undo the last closed tab.[9][5]
Tab and session management
qutebrowser provides efficient tab management through keyboard-driven controls, allowing users to navigate, create, close, and manipulate tabs without relying on the mouse. To switch between tabs, users can pressJ to move to the next tab or K to the previous one, integrating seamlessly with the browser's vim-like keybindings for fluid navigation.[5] Numbered tab selection is supported via <Alt-1> through <Alt-9> to jump directly to the corresponding tab position, while gt advances to the next tab and gT retreats to the previous.[5] For more precise control, the :tab-select command enables selection by index or substring match, and it also supports pinning tabs to keep them fixed in position or moving them via the :tab-move command, which accepts relative offsets like + or -, or absolute positions such as start or end.[21]
Session management in qutebrowser emphasizes persistence and configurability to maintain workflow across sessions. By default, sessions are not automatically saved, but this can be enabled via the auto_save.session setting, which restores open tabs upon restart.[3] Manual session saving is achieved with the :session-save command, optionally specifying a name (defaulting to the value in session.default_name), and flags like --only-active-window to limit scope or --no-history to exclude tab history.[21] Quitting with :wq (write and quit) automatically saves the current session if configured, ensuring tabs and their states are preserved.[5] Sessions can be loaded with :session-load, supporting options such as --clear to close existing windows before restoration or --lazy_restore (a related setting) to defer loading until a tab gains focus, optimizing performance.[21][3]
Window management supports multiple independent instances for compartmentalized browsing, each capable of maintaining its own session. The :open -w command (often bound to wo for opening a URL in a new window) creates a fresh window, while new_instance_open_target setting dictates how external links behave in existing instances, defaulting to opening in a new tab but configurable to window.[3] Tabs can be transferred between windows using :tab-give to move the current tab to a specified window ID or :tab-take to pull a tab from another window, preserving session integrity across instances.[21]
Advanced features enhance tab handling beyond basics. Users can undo tab closures with u, remembering an unlimited number of closed tabs and windows by default (configurable via tabs.undo_stack_size, set to -1 for no limit).[3][5] Tab stacking is natively supported through the tabs.new_position.stacking setting, which groups consecutively opened related tabs together for better organization.[3] While full tab grouping or advanced stacking requires userscripts, core functionality like pinning with :tab-pin or muting via :tab-mute provides robust control without external dependencies.[21]
Technical aspects
Rendering engines
qutebrowser primarily utilizes QtWebEngine as its default rendering engine, a Chromium-based backend introduced in version 1.0 released in October 2017.[6] This engine provides robust support for modern web standards, including HTML5, CSS3, and JavaScript ES6+, along with built-in sandboxing for enhanced security and hardware acceleration for improved rendering performance on compatible systems.[3][22] As a fork of the Chromium project maintained by the Qt team, QtWebEngine ensures compatibility with contemporary web applications while benefiting from regular security patches and feature updates derived from upstream Chromium releases.[4] For legacy compatibility, qutebrowser supports QtWebKit as an optional backend, which is based on the pre-Chromium WebKit engine and can be configured for rendering older websites that may not function optimally with QtWebEngine.[3] However, QtWebKit has been deprecated since Qt 5.6 in 2016, with its last significant update (version 5.212 alpha) occurring in 2020, resulting in the absence of recent security fixes, process isolation, or sandboxing features.[4][23] This makes QtWebKit unsuitable for general use due to known vulnerabilities and limited support for modern web technologies.[1] The choice between rendering engines is determined by thebackend configuration option, which accepts values of webengine (default) or webkit and requires a browser restart to take effect.[3] QtWebEngine mandates Qt 5.15.2 or later for Qt 5 installations, or Qt 6.2 or later for Qt 6, ensuring access to the latest Chromium integrations.[1] In terms of performance, QtWebEngine excels in JavaScript execution speed and multimedia handling compared to QtWebKit, though it consumes more system resources due to its comprehensive feature set; for PDF viewing, it integrates the pdf.js library to render documents directly within tabs without external dependencies.[3][4]
qutebrowser's rendering engines enjoy full support across Linux, Windows, and macOS platforms, where both QtWebEngine and QtWebKit can be utilized depending on system Qt installations.[8] On BSD variants like FreeBSD, however, QtWebEngine is unavailable, limiting users to the QtWebKit backend due to incomplete Qt porting efforts.[8]
Configuration and scripting
qutebrowser's primary configuration is managed through a Python-based file namedconfig.py, typically located at ~/.config/qutebrowser/config.py on Linux systems. This file allows users to define settings using Python syntax, providing flexibility for customizations such as color schemes, with examples like c.colors.webpage.bg = '#ffffff' to set the webpage background color. Key bindings can also be overridden directly in this file, for instance, config.bind('x', 'spawn-cp rm') to map the 'x' key to a custom command execution. Per-domain overrides are supported via functions like config.set('content.images', False, '*://example.com/*'), enabling site-specific behaviors.[9]
For users preferring a graphical interface, qutebrowser offers a built-in settings page accessible by running the :set command without arguments, which opens qute://settings. This point-and-click interface lists all available settings and allows immediate modifications, such as adjusting tab positions or enabling features, with changes automatically syncing to the underlying configuration file in YAML format. The GUI supports pattern-based rules for domains, like disabling images on specific sites, and integrates seamlessly with command-line options for quick tweaks.[9]
Platform-specific or automatic configurations are handled via autoconfig.yml, a YAML file generated and maintained by qutebrowser in the configuration directory (viewable at qute://version). This file stores settings from GUI or command-line changes, such as tabs.position: left, and supports key bindings like bindings.commands: {normal: {',v': 'spawn mpv {url}'}}. If a config.py file exists, autoconfig.yml is ignored unless explicitly loaded using config.load_autoconfig() in the Python file, allowing layered overrides for different environments.[9]
Extensibility in qutebrowser is achieved primarily through userscripts, which are executable scripts placed in ~/.local/share/qutebrowser/userscripts/. These can be written in JavaScript, Python, or other languages that interact via environment variables and a FIFO pipe, invoked using :spawn --userscript or key bindings. Representative examples include a URL opener script for external applications or an ad-blocking enhancer that modifies page content; a simple Bash example opens selected text in a dictionary site with #!/bin/bash followed by echo "open -t https://www.dict.cc/?s=$QUTE_SELECTED_TEXT" >> "$QUTE_FIFO". Scripts must be made executable and can leverage QtWebEngine's base for interactions like injecting JavaScript.[24]
Unlike Chromium-based browsers, qutebrowser lacks a full extension API for third-party plugins, limiting advanced additions to Qt signals, userscripts, and Python-based hooks in config.py, which constrain features like comprehensive UI modifications or background processing.[4][25]
Development and community
Core development
qutebrowser is primarily maintained part-time by its lead developer, Florian Bruhin (known online as "The-Compiler"), who has overseen the project since its inception in 2013.[2][26] Bruhin, based in Switzerland and operating through Bruhin Software, handles core development alongside other open-source commitments, such as maintaining pytest.[27] The project benefits from contributions by hundreds of developers through GitHub, enabling a collaborative effort without a full-time team. The browser is written in Python 3.9 or newer, with some integration involving JavaScript for web-related functionality, and relies on PyQt5 (version 5.15.0+) or PyQt6 (version 6.2.2+) for Qt bindings.[2][8] The source code repository is hosted at github.com/qutebrowser/qutebrowser, where development occurs using standard Git workflows.[2] Development follows an open-source model centered on GitHub for issue tracking, pull request reviews, and merging contributions.[28] The project is funded primarily through donations via GitHub Sponsors, supporting Bruhin's part-time efforts.[29] An active changelog documents changes, incorporating numerous user-reported fixes and enhancements from the community.[20] As of November 2025, qutebrowser remains under ongoing maintenance, with regular releases such as version 3.6.1 issued on November 3, emphasizing Qt 6 compatibility—now the default where available—and addressing bug fixes.[20] Qt 5.15 serves as a fallback for broader compatibility, while community input drives much of the prioritization and resolution of issues.[20] There is no dedicated full-time team, relying instead on volunteer contributions to sustain progress.[2]Licensing and distribution
qutebrowser is released as free and open-source software under the terms of the GNU General Public License version 3 or later (GPLv3+), which guarantees users the freedom to run, study, share, and modify the software.[1] Certain bundled components, such as the pdf.js PDF viewer used in Windows releases, are licensed separately under the Apache License 2.0.[8] The browser is distributed through multiple channels to support various installation preferences and platforms. It is available as a Python package via PyPI, allowing installation withpip install qutebrowser.[30] Official prebuilt binaries and installers for Windows and macOS are provided through GitHub releases.[7] Additionally, qutebrowser is packaged in the official repositories of major Linux distributions, including Debian, Arch Linux in the Extra repository, and Fedora.[8][31]
Installation requires Python 3.9 or later, along with Qt 5.15 or Qt 6.2 and corresponding PyQt bindings (PyQt 5.15+ or PyQt 6.2+).[8] On Linux systems, platform-specific dependencies such as the qtwebengine package are necessary for the Chromium-based rendering backend.[8]
For packaging, qutebrowser is maintained in the repositories of numerous Linux distributions for easy integration via package managers.[8] Windows and macOS users can obtain standalone installers directly from GitHub releases, while source code builds are supported by cloning the repository and using development scripts, such as scripts/dev/ci/run.py for continuous integration testing during compilation.[2] Community-hosted mirrors, including SourceForge for version archives and Uptodown for downloadable installers of older releases, provide alternative access points for users seeking historical versions.[32]