Parham Forati107 downloadsTime tracking that lives in your notes and survives restarts — then slice the stats by any files, folders, or dates you choose.
A modern, minimal multi-purpose time tracker for your Obsidian notes.
Tempo lets you track time directly inside your notes using a simple code block. Press the play button when you begin a task and the stop button when you finish — Tempo records the timestamps, saves them as plain JSON in your note, and shows you a clean table with per-segment and total durations. Because time is tracked purely by timestamps, a tracker keeps running even if you switch notes, close Obsidian, or shut down your device.
This version also adds Tempo Stats — a companion code block that aggregates the tracked time from the sources you choose into a clear summary: total time, number of tracked tasks, and number of files scanned.
https://github.com/user-attachments/assets/33966c3e-238d-4aa4-9967-61d2681e93fa
tempo code block turns any note into a live
timer with named segments.tempo-stats) — aggregate the time tracked across the
sources you pick:Requirements: Node.js 18+ and npm.
# 1. Clone this repository
git clone <your-repo-url> Tempo
cd Tempo
# 2. Install dependencies
npm install
# 3. Build the plugin (produces main.js, manifest.json, styles.css at the root)
npm run build
Then copy the three built files into your vault:
<vault>/.obsidian/plugins/.tempo (this must match the plugin id in
manifest.json).main.js, manifest.json, and styles.css into that tempo folder.⚠️ Folder name matters. Obsidian matches the plugin folder name to the
idfield inmanifest.json. If the folder is named anything other thantempo, the plugin will not load.
📌 Requires Obsidian 1.13.0 or later. This version uses Obsidian's declarative settings API, so the
minAppVersioninmanifest.jsonis set to1.13.0. On older Obsidian versions the plugin will not enable.
Tempo: Insert Time Tracker (or type a
```tempo code block manually).The tracker data lives as JSON inside the code block, so it stays in your note and syncs with the rest of your vault.
Tempo: Insert Time Tracker Stats from the command
palette (or add a ```tempo-stats code block).Open Settings → Tempo (or search "Tempo" in Obsidian's settings search).
| Setting | Description |
|---|---|
| Timestamp display format | moment.js format for timestamps in tracker tables (e.g. YY-MM-DD HH:mm:ss). |
| CSV delimiter | Character used when copying a table as CSV. Useful for locales that use ; instead of ,. |
| Fine-grained durations | Include days, months, and years in durations. When off, larger units roll into the hours display. |
| Timestamp durations | Show durations as 12:15:01 instead of 12h 15m 1s. |
| Display segments in reverse order | Show older segments at the bottom instead of the top. |
| Show total today | Display the total time spent today in the tracker table. |
| Use monospaced font for times | Use your monospaced font for the title timer so digits don't shift while counting. |
| Pretty-print tracker data | Pretty-print the code block JSON (larger files, easier sync merges). |
Tempo exposes a public API for use with plugins like
Dataview. Access it via the
Obsidian app object:
app.plugins.plugins["tempo"].api;
Example — using DataviewJS to load every tracker in the vault and print the total duration of each:
// get the Tempo plugin api instance
let api = dv.app.plugins.plugins["tempo"].api;
for (let page of dv.pages()) {
// load trackers in the file at the given path
let trackers = await api.loadAllTrackers(page.file.path);
if (trackers.length)
dv.el("strong", "Trackers in " + page.file.name);
for (let { section, tracker } of trackers) {
// print the total duration of the tracker
let duration = api.getTotalDuration(tracker.entries);
dv.el("p", api.formatDuration(duration));
}
}
Available functions:
loadTracker(json) — parse a single tracker's JSON.loadAllTrackers(fileName) — load all trackers in a file.getDuration(entry) / getTotalDuration(entries) — durations in ms.getDurationToday(entry) / getTotalDurationToday(entries) — today's totals.getDurationDate(entry, date) / getTotalDurationDate(entries, date).getRunningEntry(entries) / isRunning(tracker).formatTimestamp(timestamp) / formatDuration(totalTime) — using your settings.orderedEntries(entries) — entries ordered per your segment-order setting.A time tracker is just a special code block that stores the timestamps of when you pressed the play and stop buttons. Because only timestamps are stored, you can switch notes, close Obsidian, or shut down your machine while a tracker is running — when you return, it's still running. The segment names, start times, and end times are saved as JSON in the code block and rendered as a table in preview/reading mode.
npm install # install dependencies
npm run dev # watch mode; rebuilds on change into main.js + test-vault
npm run build # production build (tsc typecheck + minified esbuild bundle)
npm run lint # eslint (includes Obsidian-specific rules)
The dev build also copies main.js, manifest.json, and styles.css into
test-vault/.obsidian/plugins/simple-time-tracker/ so you can test against the
bundled sample vault.
Tempo is built on top of ObsidianSimpleTimeTracker by Ellpeck (MIT licensed) — thanks for such a solid foundation to build on, and for kindly approving this fork.
MIT — see the original project for license details.