« Launching Git Bash
Windows Desktop Shortcuts »

qutebrowser Userscripts on Windows
Updated  2022-May-6

Page contents


Ongoing  According to Repology, the newest packaged qutebrowser is version latest packaged version of qutebrowser. To keep up with qutebrowser releases, see github.com/qutebrowser/qutebrowser/releases, listi.jpberlin.de/pipermail/qutebrowser/, or old.reddit.com/r/qutebrowser/.

2022-March-28  As of today, this evolving⁠[1] article has been on the web for 1 year.🎂



This article assumes…


About qutebrowser userscripts

A qutebrowser userscript can be run on a web page or on a fragment of a web page. To learn about userscripts, see…


⚠️Limitations of userscripts on Windows

On Windows, only userscripts with .bat, .cmd, .com, and .exe extensions will be launched by qutebrowser. This means that if you want to run a bash or python script from within Windows qutebrowser, you need to create a .bat, .cmd, .com, or .exe wrapper for it.

Examples of wrapper scripts are below.


About qutebrowser’s config and data directories

A fresh install of qutebrowser on Windows usually creates the following directory structure.

└── AppData\
    └── Roaming\
        └── qutebrowser\
            ├── config\
            │   ├── greasemonkey\
            └── data\
                └── greasemonkey\


Note that…

  • On Windows, ~ is also known as %HOME% and %USERPROFILE%.⁠[2] It is usually located at C:\Users\USERNAME (with USERNAME replaced with your user name).

  • To find out the location of your qutebrowser config and data directories, run the :version command from within qutebrowser.

  • Windows default is to hide the ~\AppData\ directory. To unhide it, click File Explorer’s View menu and check Hidden items and/or Show hidden files, folders, and drives (what you see here depends on what version of Windows you are using).


About the greasemonkey directories

Greasemonkey scripts are entirely different from qutebrowser userscripts, but I mention them here because a default installation of qutebrowser automatically creates empty greasemonkey\ directories in the config and data directories. To learn about greasemonkey scripts, which are written in JavaScript, see wikipedia.org/wiki/Greasemonkey.

If you do not use these greasemonkey directories, it’s OK to delete them.


Five steps to create a simple Windows userscript

1. Create a userscripts directory

Use either Windows File Explorer or the command line to create a userscripts\ directory in either your qutebrowser config\ or data\ directory.



If you are using qutebrowser v2.0.0+, I recommend you create config\userscripts\ because then your qutebrowser userscripts and configuration file(s) will all be located in the config directory.

If you are using qutebrowser v1.14.1 or earlier, you must use data\userscripts\ (because config\userscripts\ was introduced in v2.0.0).


After the next couple steps, your directory structure will include this (assuming you are using qutebrowser v2.0.0+):

└── AppData\
    └── Roaming\
        └── qutebrowser\
            ├── config\
            │   ├── greasemonkey\
            │   ├── userscripts\
            │   │   └── qb-env.cmd
            │   └── config.py
            └── data\
                └── greasemonkey\


2. Create qb-env.cmd batch file

In the userscripts\ directory that you created in the previous step, create a plain text file named qb-env.cmd that contains this:

@echo off

rem created: 2022-08-14
rem filename: qb-env.cmd
rem purpose: display some parts of qutebrowser's current environment

echo Hello from qb-env.cmd!

rem next line echoes a blank line
echo Working directory is...

echo Active code page is...

echo Environment variables starting with QUTE are...
set QUTE

echo Environment variables starting with PATH are...
set PATH

rem If Git Bash's sh.exe is on your path, uncomment next 7 lines
rem echo(
rem echo Git Bash: pwd
rem "sh.exe" -l -c "pwd"

rem echo(
rem echo Git Bash: printenv | grep -i qute
rem "sh.exe" -l -c "printenv | grep -i qute"


qb-env means qutebrowser environment and the above batch file displays the working directory, active code page, and some environment variables.

If you are wondering why this batch file has a .cmd rather than .bat file extension, see stackoverflow.com/questions/148968/windows-batch-files-bat-vs-cmd.


3. Create a key binding in config.py

In your config\config.py configuration file, add this line:

config.bind(',qenv', 'spawn -u -o "qb-env.cmd"')

If you do not have a config.py, which is qutebrowser’s configuration file, see Infinite Ink’s Getting Started with qutebrowser.


4. :config-source

To tell qutebrowser about this new ,qenv key binding, run the following from within qutebrowser:



5. Launch qb-env.cmd from within qutebrowser

In qutebrowser, make sure you are in command mode by pressing the Esc key and then type:


This will run qb-env.cmd and its output will be displayed in a new qutebrowser tab (thanks to the -⁠o argument specified in step 3 above).


  • In qutebrowser v2.2.0+, you can use the :process command to display the full output of a spawn command in the current qutebrowser window.

  • spawn’s -u argument is equivalent to --userscript.

  • spawn’s -o argument is equivalent to --output.

To learn about spawn’s arguments, including -⁠u and -⁠o, see qutebrowser.org/doc/help/commands.html#spawn.


The output of this qb-env userscript might be useful when you create other qutebrowser userscrpts, for example the ones below.


Calling bash scripts from Windows “wrapper” userscripts

Calling a WSL bash script from a Windows userscript

I’d rather write a bash shell script than a Windows batch file and, thanks to WSL (Windows’ Subsystem for Linux),⁠[3] most of my Windows qutebrowser scripting is actually bash scripting. In this section, I briefly describe my tumblelog-⁠wrapper.cmd Windows userscript and my tumblelog.sh bash script that it calls.


Key binding in config.py

I put the following line in my config.py.

config.bind(',t', 'spawn -u tumblelog-wrapper.cmd')

This makes it possible to use ,t to launch my tumblelog-wrapper.cmd Windows userscript, which adds qutebrowser’s current web page to Infinite Ink’s #tumblelog Portal.



When the argument to spawn -u is a relative path, it is relative to qutebrowser’s data\userscripts\ or config\userscripts\[4] directory. To put a userscript anywhere on your system, use an absolute path, for example:

config.bind(',t', 'spawn -u "C:\\Users\\USERNAME\\Sync\\qb\\tumblelog-wrapper.cmd"')


tumblelog-wrapper.cmd Windows userscript

In the Windows file system, my qutebrowser config\ directory⁠[5] contains userscripts\tumblelog-⁠wrapper.cmd, which comprises the following five lines.

@REM change code page so UTF-8 characters work
chcp 65001

@REM pass six QUTE_ variables to the bash script


  • WSLUSERNAME is my WSL user name.

  • This tumblelog-wrapper.cmd Windows userscript does not work if any tumblelog.sh argument, for example %QUTE_TITLE%, contains an ASCII double quotation mark (").⁠[6]


tumblelog.sh bash script

In the WSL file system, my ~/Scripts/tumblelog.sh starts out like this:


QHTMLPATH=`wslpath $5`
QTEXTPATH=`wslpath $6`

# below here, I use a heredoc to create a Hugo leaf bundle

I hope this is enough to get you started using a WSL bash script with qutebrowser.




Calling a Git Bash script from a Windows userscript

Instead of calling a WSL script, you can call a Git Bash script by replacing the tumblelog-wrapper.cmd batch file in the previous section with something like the following.

tumblelog-wrapper.cmd (with absolute paths)
@REM The sh.exe below is part of Git For Windows
"C:\Program Files\Git\bin\sh.exe" -l "C:\full\path\to\tumblelog.sh"

If both sh.exe and tumblelog.sh are on your path, you can use the following.

tumblelog-wrapper.cmd (pathless)
@REM IMPORTANT: Make sure the sh.exe below is not a trojan!
"sh.exe" -l "tumblelog.sh"



See also


1. Many Infinite Ink articles, including this one, are evergreen and regularly updated.
2. Unless you have redefined these Windows environment variables.
3. It would probably make more sense if WSL were called LSW (Linux Subsystem for/of/on Windows), but it is not because, according to Rich Turner in this tweet, Microsoft “cannot name something leading with a trademark owned by someone else.” Rich’s tweet has inspired me to interpret the WSL acronym as meaning Windows Subsystem for Linux (notice the apostrophe ()).
4. In qutebrowser v1.14.1 and earlier, userscripts are in data/userscripts/. In v.2.0.0+, userscripts are in either data/userscripts/ or config/userscripts/ (or both).
5. To find out your qutebrowser config and data directories, run the :version command from within qutebrowser.
6. An ASCII quotation mark is also known as a dumb, neutral, vertical, straight, or typewriter quotation mark.

Comments and questions 📝 🤔 👎 👍

Your public comment or question might immediately improve this page or help me to (eventually) improve this page.