Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save schmunk42/fbbcdee420af674798e4d2fc32a62165 to your computer and use it in GitHub Desktop.

Select an option

Save schmunk42/fbbcdee420af674798e4d2fc32a62165 to your computer and use it in GitHub Desktop.

ActivityWatch Automatic Startup on GNOME/Wayland

Problem

ActivityWatch (awatcher-bundle) doesn't start automatically after login on GNOME with Wayland. The desktop app shows "localhost refused the connection."

Root Cause

The XDG autostart method (.desktop files in ~/.config/autostart/) has timing issues:

  • Watchers try to connect before GNOME is fully initialized
  • D-Bus and Mutter/IdleMonitor are not yet available
  • Database worker crashes with RecvError

Solution: systemd User Service

Step 1: Create systemd Service File

Create the file ~/.config/systemd/user/activitywatch.service:

[Unit]
Description=ActivityWatch (awatcher-bundle) - Activity tracking service
Documentation=https://docs.activitywatch.net/
After=graphical-session.target org.gnome.Shell.target
Wants=graphical-session.target

[Service]
Type=simple
ExecStartPre=/home/schmunk/.local/bin/prepare-activitywatch.sh
ExecStart=/usr/bin/awatcher-bundle -vv --no-tray
Restart=on-failure
RestartSec=10
KillMode=mixed
# Ensure the service has access to the display
Environment="DISPLAY=:0"
# For Wayland
Environment="WAYLAND_DISPLAY=wayland-0"
# XDG runtime directory
Environment="XDG_RUNTIME_DIR=/run/user/%U"

[Install]
WantedBy=default.target

Step 2: Create Prepare Script

Create the script ~/.local/bin/prepare-activitywatch.sh:

#!/bin/bash
# Prepare ActivityWatch: Wait for required dependencies
# - GNOME Shell Extension (focused-window-dbus)
# - ActivityWatch server (port 5600)

set -e

TIMEOUT=30

# Wait for D-Bus interface
wait_for_dbus() {
    local interface="org.gnome.shell.extensions.FocusedWindow"
    local path="/org/gnome/shell/extensions/FocusedWindow"
    local elapsed=0

    echo "Waiting for GNOME Extension D-Bus interface..."

    while [ $elapsed -lt $TIMEOUT ]; do
        if busctl --user introspect org.gnome.Shell "$path" 2>/dev/null | grep -q "$interface"; then
            echo "✓ GNOME Extension available after ${elapsed}s"
            return 0
        fi
        sleep 1
        elapsed=$((elapsed + 1))
    done

    echo "ERROR: GNOME Extension not available after ${TIMEOUT}s" >&2
    return 1
}

# Wait for ActivityWatch server
wait_for_server() {
    local port=5600
    local elapsed=0

    echo "Waiting for ActivityWatch server on port $port..."

    while [ $elapsed -lt $TIMEOUT ]; do
        if curl -s "http://127.0.0.1:$port" >/dev/null 2>&1; then
            echo "✓ ActivityWatch server available after ${elapsed}s"
            return 0
        fi
        sleep 1
        elapsed=$((elapsed + 1))
    done

    echo "WARNING: ActivityWatch server not available after ${TIMEOUT}s (will retry on start)" >&2
    return 0  # Not critical, awatcher-bundle will retry
}

# Execute checks
wait_for_dbus || exit 1
wait_for_server

echo "✓ All dependencies ready"
exit 0

Make the script executable:

chmod +x ~/.local/bin/prepare-activitywatch.sh

Step 3: Enable and Start Service

# Reload systemd
systemctl --user daemon-reload

# Enable service for autostart
systemctl --user enable activitywatch.service

# Start service immediately
systemctl --user start activitywatch.service

Step 4: Remove Old Autostart Entry

# If present, delete old XDG autostart entry
rm ~/.config/autostart/awatcher.desktop

Step 5: Verify

# Check service status
systemctl --user status activitywatch.service

# Test server connection
curl http://localhost:5600/api/0/info

Important Configuration Details

--no-tray Flag

  • Starts server and watchers without GUI tray icon
  • Prevents issues with display access in systemd services
  • Web app still works normally

Prepare Script (ExecStartPre=/home/schmunk/.local/bin/prepare-activitywatch.sh)

  • Intelligently waits for GNOME Shell Extension (focused-window-dbus) via D-Bus
  • Checks availability of D-Bus interface org.gnome.shell.extensions.FocusedWindow
  • Optionally waits for ActivityWatch server (port 5600)
  • 30-second timeout for robust error handling
  • Prevents the RecvError crash at startup by ensuring all dependencies are available

Environment Variables

  • DISPLAY=:0 - X11 Display
  • WAYLAND_DISPLAY=wayland-0 - Wayland Display Socket
  • XDG_RUNTIME_DIR=/run/user/%U - User Runtime Directory

Service Dependencies

  • After=graphical-session.target org.gnome.Shell.target - Starts after graphical session AND GNOME Shell
  • Wants=graphical-session.target - Dependency without hard failure
  • WantedBy=default.target - Started automatically at login

GNOME Shell Extension Dependency

  • Requires focused-window-dbus extension for window tracking on Wayland
  • Prepare script explicitly waits for extension's D-Bus interface
  • Without the extension, window watcher would not function

Useful Commands

# Show service status
systemctl --user status activitywatch.service

# Restart service
systemctl --user restart activitywatch.service

# Stop service
systemctl --user stop activitywatch.service

# Disable service (no autostart)
systemctl --user disable activitywatch.service

# Show logs (live)
journalctl --user -u activitywatch.service -f

# Show logs from current boot
journalctl --user -u activitywatch.service -b 0

Result

After a reboot:

  • ✓ ActivityWatch server runs automatically on http://127.0.0.1:5600
  • ✓ Idle watcher active (Gnome idle/Mutter/IdleMonitor)
  • ✓ Window watcher active (Gnome window extension)
  • ✓ Chromium Web-Desktop App can connect
  • ✓ Automatic restart on crashes

Tested On

  • Arch Linux
  • GNOME with Wayland
  • awatcher-bundle v0.13.1 (rust)
  • systemd 256.7

Created: 2025-11-11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment