Flameshot to XBackBone on Linux: The Keyboard Shortcut Graveyard
series: plane-of-infrastructure
The Goal
Press a key. Flameshot opens. Annotate if needed. Confirm. Image uploads to your self-hosted XBackBone instance. URL lands in your clipboard. Desktop notification appears. No extra clicks.
On Windows with ShareX, this is a settings toggle. On Linux, the script is ten lines. The keyboard shortcut took two hours and a tour through four different KDE subsystems, all of which confidently claimed to own the problem while solving none of it.
This post documents what works and why everything else does not.
Why Flameshot Does Not Just Do This
Flameshot v13+ deliberately removed its built-in Imgur uploader. The maintainers were right to do it — uploaders do not belong in a screenshot tool. They are working on a plugin system. Until that ships, there is no settings toggle for “upload to XBackBone”. The closest built-in option is “Open with…”, which requires a manual click after every capture.
The workaround that actually works is flameshot gui -r, which writes the captured PNG as raw bytes to stdout. A shell script captures those bytes, uploads them with curl, parses the JSON response with jq, and copies the URL to the clipboard. The Flameshot GUI stays fully intact — you get annotation tools, the capture preview, and the ability to cancel.
Prerequisites
# Fedora / Bazzitesudo dnf install flameshot curl jq wl-clipboard xbindkeysDo not use the Flatpak version of Flameshot. Its sandboxing prevents it from running external scripts reliably. The native RPM package is what you want.
Check that everything is present:
for cmd in flameshot curl jq wl-copy xbindkeys; do which "$cmd" && echo "✓ $cmd" || echo "✗ $cmd MISSING"doneThe Upload Script
Get your XBackBone token by logging into your instance → Profile → download the Linux script → note the token value. You do not need the script itself, just the token and your instance URL.
~/.local/bin/flameshot-xbackbone.sh#!/usr/bin/env bashXBACKBONE_URL="https://xb.yourdomain.com/upload"XBACKBONE_TOKEN="token_your_token_here"LOGFILE="$HOME/.local/share/flameshot-xbackbone/upload.log"mkdir -p "$(dirname "$LOGFILE")"
for cmd in flameshot curl jq wl-copy notify-send; do if ! command -v "$cmd" &>/dev/null; then notify-send "flameshot-xbackbone" "Missing: $cmd" -i dialog-error exit 1 fidone
TMPFILE=$(mktemp /tmp/flameshot-XXXXXX.png)trap 'rm -f "$TMPFILE"' EXIT
# -r writes raw PNG bytes to stdout; exits cleanly if user cancelsflameshot gui -r > "$TMPFILE" 2>/dev/null
if [[ ! -s "$TMPFILE" ]]; then echo "$(date '+%F %T') cancelled" >> "$LOGFILE" exit 0fi
# Note: field name is "upload", not "file"# Token field must come before the file field (see XBackBone notes below)RESPONSE=$(curl -s \ -F "token=$XBACKBONE_TOKEN" \ -F "upload=@$TMPFILE" \ "$XBACKBONE_URL")
URL=$(echo "$RESPONSE" | jq -r '.url // empty' 2>/dev/null)
if [[ -n "$URL" ]]; then printf '%s' "$URL" | wl-copy notify-send "Screenshot uploaded" "$URL" -i flameshot -t 6000 echo "$(date '+%F %T') OK: $URL" >> "$LOGFILE"else ERROR=$(echo "$RESPONSE" | jq -r '.message // "Unknown error"' 2>/dev/null) notify-send "Upload failed" "$ERROR" -i dialog-error -t 10000 echo "$(date '+%F %T') FAIL: $RESPONSE" >> "$LOGFILE" exit 1fichmod +x ~/.local/bin/flameshot-xbackbone.sh# Test it directly first~/.local/bin/flameshot-xbackbone.shTake a screenshot. If a notification appears with the URL and it is in your clipboard, the script works. The keyboard shortcut is the hard part.
The Keyboard Shortcut Graveyard
This section documents every approach that failed and why, so you do not have to repeat the journey.
Attempt 1: KDE Custom Shortcuts UI
System Settings → Shortcuts → Custom Shortcuts → New → Global Shortcut → Command/URL.
On Plasma 6 Wayland, this did not work. The shortcut was accepted but never fired. The underlying mechanism (khotkeys) was removed in KDE Plasma 6 without a direct replacement. The settings UI still exists but the daemon it configures does not ship on Fedora-based distributions.
Attempt 2: Service Shortcut via .desktop file
Adding X-KDE-GlobalAccel-CommandShortcut=true to a .desktop entry and registering it via kglobalacceld. This is the documented approach for KDE service shortcuts.
The entry appeared in ~/.config/kglobalshortcutsrc with the correct key binding. kglobalacceld was running. The shortcut never fired.
The problem: kglobalacceld requires the .desktop entry to be registered during session startup via kbuildsycoca6. Even after rebuilding the cache and restarting the service, the component was not registered:
qdbus org.kde.kglobalaccel /component/flameshot-xbackbone.desktop \ org.kde.kglobalaccel.Component.shortcutNames# Returns empty. kglobalaccel does not know this component exists.Attempt 3: Bare Print Screen
Before settling on a workaround, a long detour chasing what was intercepting PrtSc.
Suspected culprits in order: Spectacle, NVIDIA App, Steam, KWin built-in, xdg-desktop-portal.
Actual culprit: Plasma 6’s compositor-level screenshot, which fires at the Wayland protocol layer before the global shortcut system is consulted. It produces .jpg files in ~/Pictures/ with names like Screenshot_2026-04-06_15-17-57.jpg. Disabling it requires setting screenshotEnabled=false in kwinrc and rebooting. Even then, Ctrl+PrtSc triggered a green region-select frame from the same system.
The lesson: do not fight KDE’s screenshot key infrastructure. Pick a key it does not touch.
Attempt 4: Meta+PrtSc
The Meta key is captured by KDE’s application launcher before the shortcut dialog can record it. Attempting to set a Meta+ combo in any KDE dialog causes the launcher to open.
Setting it directly via kwriteconfig6 and python3 file manipulation wrote the correct value to kglobalshortcutsrc but it still did not fire, for the same kglobalaccel registration reason as Attempt 2.
What Actually Works: xbindkeys
xbindkeys is a standalone X11 key binding daemon. It has no interaction with KDE’s shortcut system. It reads ~/.xbindkeysrc, watches for key combinations, and runs commands. That is all it does.
# Check if installed (it ships with Bazzite)which xbindkeys
# Create the configcat > ~/.xbindkeysrc << 'EOF'# Flameshot to XBackBone"/home/YOUR_USERNAME/.local/bin/flameshot-xbackbone.sh" control + PauseEOF
# Start it nowxbindkeys
# Verifypgrep -a xbindkeysTest Ctrl+Pause. Flameshot should open.
Ctrl+Pause is the recommended key combination. Nothing in KDE, Steam, Spectacle, or the NVIDIA driver stack touches the Pause key. It will never be intercepted.
Autostart
cat > ~/.config/autostart/xbindkeys.desktop << 'EOF'[Desktop Entry]Name=xbindkeysComment=Key bindings daemonExec=xbindkeysType=ApplicationTerminal=falseStartupNotify=falseX-KDE-AutostartPhase=1EOFxbindkeys will now start automatically on login.
First Run: The Wayland Portal Prompt
On the first capture after installation (whether on X11 or Wayland), KDE may show a portal permission dialog: “Allow [application] to take a screenshot?” Click Allow. This is a one-time Wayland security prompt. It will not appear again.
If you are on a Wayland session and the permission was previously denied, reset it:
flatpak permissions # if using Flatpak Flameshot# or for native install:# The prompt will appear again on next captureXBackBone API Notes
Two non-obvious things that will waste your time if you do not know them.
The upload field is named upload, not file. Most generic uploader configurations, tutorials, and AI suggestions use file. XBackBone uses upload. Using the wrong field name results in a silent failure with no error message.
Send the token field before the file field. When a POST body exceeds PHP’s post_max_size, PHP silently drops all POST fields including the token. The response is {"message":"Token not specified."} even though the token is correct. Sending token first means it is received even in partial-read scenarios. If you see this error on large screenshots, raise both post_max_size and upload_max_filesize in your server’s php.ini, and client_max_body_size in nginx — both layers must be configured.
HTTP 413 returns HTML, not JSON. nginx’s size limit fires before PHP sees the request and returns an HTML error page. Check the HTTP status code before parsing the response body.
The Working Setup
~/.local/bin/flameshot-xbackbone.sh — upload script~/.xbindkeysrc — Ctrl+Pause binding~/.config/autostart/xbindkeys.desktop — autostart entry~/.local/share/flameshot-xbackbone/upload.log — log fileCtrl+Pause → Flameshot GUI opens → annotate → confirm → upload → URL in clipboard → notification.
The script, the binding, and the autostart entry are all under 30 lines combined. Everything between the goal and the working result was KDE shortcut infrastructure.
Related
- Reference implementation and XBackBone plugin stub (for the forthcoming Flameshot plugin system): forgejo.wanderingmonster.dev/WanderingMonster/flameshot-post-capture-command
- Upstream RFC issue: github.com/flameshot-org/flameshot/issues/4623
- XBackBone: github.com/sergix44/XBackBone