A Decky plugin for tracking per-game playtime on your Steam Deck. Records sessions automatically, shows activity heatmaps, streaks, milestones, and goals through a built-in interface.
Supports multiple games simultaneously - with session history, daily/weekly/monthly breakdowns, docked vs handheld split, and editable sessions for backfilling missing data.
- Automatic session tracking - detects the running game every 10 seconds
- Docked vs handheld time split per session (via
/sys/class/drm) - Battery level recorded at session start and end
- Activity heatmap - 7×24 grid by day-of-week and hour-of-day
- Play streaks - current consecutive days and all-time best
- Milestones - notifications at 10/25/50/100/250/500/1000 hours per game
- Goals - daily/weekly/monthly targets per game or across all games
- Session editor - modify start/end time, duration, notes, docked/handheld split
- Manual session creation for backfilling past playtime
- Export/import - full data backup as JSON
- 10 languages: English, Russian, Chinese, Spanish, Portuguese-BR, German, French, Polish, Turkish, Japanese
- Quick Access Menu widget with live elapsed timer and 7-day mini chart
.
├── README.md
├── main.py # Python backend (Decky plugin host)
├── plugin.json # Plugin metadata (name, author, tags)
├── package.json # Node dependencies
├── rollup.config.js # Rollup bundler config (@decky/rollup)
├── tsconfig.json # TypeScript config
└── src/
├── index.tsx # Plugin entry point & QAM widget
├── api.ts # RPC client wrappers
├── types.ts # TypeScript interfaces
├── components/
│ ├── FullPage.tsx # Main stats page (4 tabs)
│ ├── SectionHeader.tsx # Reusable section label
│ ├── EditGoalModal.tsx # Goal creation/editing modal
│ ├── EditSessionModal.tsx # Session editing modal
│ └── tabs/
│ ├── OverviewTab.tsx # Dashboard: totals, streaks, heatmap, top games
│ ├── ByGameTab.tsx # Per-game stats ranked by playtime
│ ├── SessionsTab.tsx # Paginated session list with edit/delete
│ └── SettingsTab.tsx # Goals, export/import, language, clear data
├── charts/
│ ├── ActivityHeatmap.tsx # 7×24 hour heatmap component
│ └── BarChart.tsx # Generic bar chart component
├── utils/
│ ├── format.ts # Duration, datetime, file size formatters
│ ├── colors.ts # Color palette & deterministic game colors
│ └── ui.ts # Spacing, typography, card/row styles
└── i18n/
├── index.ts # i18n system with auto language detection
└── en.ts, ru.ts, zh.ts ... # Language files (10 languages)
main.pyruns an async 10-second polling loop - detects the active Steam game by scanning/proc/*/environ, records session start/end times, accumulates docked and handheld seconds, and fires Decky events to refresh the UIOverviewTab.tsxshows all-time, today, week, month, and year totals with deltas; current/best streaks; top 10 games; 7-day bar chart; and the 7×24 activity heatmapByGameTab.tsxlists every game ranked by total playtime with per-game heatmaps, 30-day trends, milestone progress, and goal trackingSessionsTab.tsxrenders a paginated session list (25 per page) with inline edit and delete; supports creating sessions manuallySettingsTab.tsxmanages goals, language preference, JSON export/import, and full data wipeindex.tsxprovides the QAM widget: current game with live elapsed timer, 7-day mini bars, and a tracking toggle
| Tab | What it shows |
|---|---|
| Overview | Totals by period, streaks, top games, heatmap, session-length buckets |
| By Game | Per-game playtime ranking with individual heatmaps, milestones, goals |
| Sessions | Full session history - editable and deletable, manual creation |
| Settings | Goals, language, export/import, data management |
SQLite database stored in the Decky plugin data directory.
CREATE TABLE sessions (
id INTEGER PRIMARY KEY,
app_id TEXT NOT NULL,
app_name TEXT NOT NULL,
start_time REAL NOT NULL,
end_time REAL,
duration REAL,
notes TEXT DEFAULT '',
docked_seconds REAL DEFAULT 0,
handheld_seconds REAL DEFAULT 0,
battery_start INTEGER,
battery_end INTEGER,
was_charging INTEGER DEFAULT 0
);
CREATE TABLE goals (
id INTEGER PRIMARY KEY,
app_id TEXT NOT NULL,
target_hours REAL NOT NULL,
period TEXT NOT NULL, -- 'daily', 'weekly', 'monthly'
created_at REAL NOT NULL,
UNIQUE(app_id, period)
);
CREATE TABLE milestones (
id INTEGER PRIMARY KEY,
app_id TEXT NOT NULL,
threshold_hours REAL NOT NULL,
reached_at REAL NOT NULL,
UNIQUE(app_id, threshold_hours)
);
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);All Python methods are called from TypeScript via @decky/api.
| Method | Description |
|---|---|
get_overview() |
Totals, streaks, top games, recent sessions, session buckets |
get_by_game() |
All games ranked by playtime |
get_game_detail(app_id) |
Full stats for one game including heatmap and milestones |
get_weekly_summary() |
7-day playtime per game |
get_daily_series(days) |
Daily totals for the last N days |
list_sessions(page, size, app_id) |
Paginated session list |
list_goals() |
All active goals with current progress |
get_milestones(app_id) |
Reached milestones for a game |
update_session(id, fields) |
Edit session fields |
delete_session(id) |
Remove a session |
create_session(...) |
Add a session manually |
set_goal(app_id, period, hours) |
Create or update a goal |
delete_goal(id) |
Remove a goal |
export_to_file(path) |
Save all data as JSON |
import_from_file(path) |
Restore from JSON backup |
clear_all_data() |
Wipe all sessions, goals, milestones |
set_tracking_enabled(bool) |
Pause or resume tracking |
getDbInfo() |
Session count, date range, DB file size |
getLanguage() / set_language(lang) |
Language preference |
Install via the Decky Plugin Store - search for Deck Stats.
- Enable Developer Mode in Decky settings
- Download the latest release and extract it to
~/homebrew/plugins/deck-stats/ - Restart Decky
# Install Node dependencies
npm install
# Build the frontend
npm run buildThe bundled output goes to dist/index.js. Deploy the whole repo directory to ~/homebrew/plugins/deck-stats/ on the Steam Deck.
- Steam Deck with Decky Loader installed
- Plugin API version 1