I enjoy the process of collecting and processing my thoughts in Obsidian, but I’ve never been happy with the existing quick capture solutions. For those unfamiliar: quick capture is the idea of writing down any in-the-moment ideas for processing at a later point in time. This makes sure you don’t lose your interesting thoughts, without ripping you out of whatever you are doing while the idea arises.

The best way I’ve found was Obsidian Telegram Sync, which lets you send Telegram messages to a bot you’ve created. The next time you open Obsidian, it polls the Telegram Bot API for any new messages, and processes them into a new note. While this generally works, I’ve found one fundamental issue: reliability. The Telegram API only stores messages to bots for 24 hours. Afterwards, a consumer of the API has no way to retrieve this message, and can’t even find out that it misses a message. This means, that if I do not open Obsidian while having an internet connection for more than 24 hours, my quick captures are lost. Even worse: I am not notified. This destroys the trust that anything I send gets actually captured, which of course is the only reason I’m using such a system in the first place. To be clear: the creator of the Obsidian plugin is not to blame for this, that’s just an inherent limitation of the architecture they’ve decided on.

As a solution, I’ve built qcap. It runs on my personal server, and polls the Telegram Bot API for new messages every 3 seconds. Captured thoughts are stored in a RON file and then deleted from the Telegram message history. Later on, the qcap Obsidian plugin polls the API, and receives and writes any new notes. If you’re interested in the technical details (and my Rust overengineering), you can find them here.

Since then, all Telegram messages have been reliably captured, and I’ve not lost a single thought. Still, the process felt clunky. Since I now have a proxy server running anyways, I realized I can just directly send it an HTTP request, and just skip the Telegram step entirely. My capture flow on mobile is currently still Telegram-based, but the desktop flow has been simplified even more: Super+B now triggers an input prompt, and typing into it saves the thought directly to my qcap proxy server.1

The following is the entire bash script for this flow. Note that this is slightly simplified, since in reality, I store the bearer token in 1Password.

#!/usr/bin/env bash
set -euo pipefail
 
input=$(fuzzel --dmenu --lines 0 --prompt "qcap > ") || exit 0
[[ -z "$input" ]] && exit 0
 
response=$(curl -s -w "\n%{http_code}" -X POST https://qcap.alexbaron.me/capture \
    -H "Authorization: Bearer TOKEN" \
    -H "Content-Type: text/plain" \
    --data-raw "$input" 2>&1)
 
status=$(echo "$response" | tail -n1)
body=$(echo "$response" | head -n-1)
 
if [[ "$status" =~ ^2 ]]; then
    notify-send "qcap" "Captured"
else
    echo -n "$input" | wl-copy
    echo "HTTP $status" >&2
    echo "$body" >&2
    notify-send -u critical "qcap" "Request failed: HTTP $status"
fi
 

Footnotes

  1. A reasonable, and simpler approach on desktop would be to just write the new file directly into the vault as a new markdown file. While this does work, it has two significant drawbacks. For one, this assumes i always have Obsidian running. While this is typically the case, it does open me up to the edgecase of me capturing an idea on my laptop without Obsidian running, and then later on opening my phone to process notes. In this situation, I would not see the new note, which is the whole thing I’m trying to avoid. Additionally, the solution is less portable (especially onto mobile, where I want to add the same approach later on).