Heatmap TrackerHabit tracker

How to build a habit tracker in Obsidian

Record the habit in your daily note, add a three-line codeblock, and read the streaks off a year-long grid. No spreadsheet, no external app, no scripting required.

A habit tracker in Obsidian needs three things: a place to record the habit, a way to read those records back, and a view that makes a streak obvious. With the Heatmap Tracker plugin, the first is a line of frontmatter in your daily note, the second and third are a three-line codeblock. No spreadsheet, no external app, no account.

1. Record the habit in your daily note

Anything you can put in frontmatter can be tracked. Booleans are the natural fit for a yes/no habit and count as 1; numbers let you record a quantity as well as the fact that it happened.

daily notes/2026-09-19.md
---
meditated: true
exercise: 45
water: 6
pages-read: 30
---

Felt sluggish this morning, better after the walk.

The note's filename is what dates the entry, so keep the usual YYYY-MM-DD convention. If you use Obsidian's core Daily notes plugin with a template, add the habit keys to that template once and every new day starts with the fields ready to fill.

2. Render the tracker

Add a codeblock wherever you want the tracker to live — a dashboard note is the usual place. One property, one heatmap:

Habits.md
```heatmap-tracker
property: meditated
```

Prefer not to write it by hand? Run Insert Heatmap Tracker from the command palette; the modal builds the codeblock and inserts it at the cursor.

3. Read the streaks

Each square is a day. Filled means the habit happened, and the colour gets stronger as the value does. Two things make the grid worth more than a checklist:

  • Gaps are visible. A monthly total of 22 hides whether you missed a day here and there or fell off for a week. The grid shows which one it was.
  • Every square is a link. Click a filled day to open that note. Click an empty one and the plugin offers to create it, so backfilling is one click.

The Statistics tab next to the heatmap keeps the numbers a habit tracker actually needs — total, days tracked, and your longest unbroken run.

Tracking several habits at once

Two approaches, and they combine. Put one codeblock per habit on a dashboard note to get a separate grid for each, or aggregate related habits into one grid by passing an array:

Fitness.md
```heatmap-tracker
property: [running, cycling, swimming]
```

Aggregation answers "did I move today", not "which sport" — pick it when consistency matters more than the breakdown.

Only counting the right notes

By default the plugin searches your Daily Notes folder, falling back to the whole vault. If your logs live somewhere else, or other notes happen to use the same property name, narrow the query:

Habits.md
```heatmap-tracker
property: meditated
path: "journal/daily"
tags: [habit]
filters:
  - property: status
    operator: equals
    value: done
```
Parameter What it does
path Folder to search in.
tags Only notes carrying at least one of these tags.
filters Extra frontmatter conditions — equals, contains or notEmpty. All must match.

Making the colours mean something

A boolean habit only ever has one filled level, which is fine. A numeric one benefits from a scale that matches the range you care about. Reading minutes between 30 and 120, for example:

Reading.md
```dataviewjs
const trackerData = {
    entries: [],
    heatmapTitle: "Reading",
    intensityConfig: { scaleStart: 30, scaleEnd: 120 },
};
// fill trackerData.entries from your notes, then:
renderHeatmapTracker(this.container, trackerData);
```

Without it, a year where most days sit between 30 and 40 minutes renders as one flat colour. See the Dataview guide for the full scripted form.

When the grid comes up empty

  1. Is Dataview installed and enabled? Heatmap Tracker reads notes through it.
  2. Does the property name match exactly? Meditated and meditated are different keys.
  3. Are the notes in the searched folder? Set path if they are not.
  4. Is the year right? The heatmap opens on the current year; use the arrows or set year.

Since v2.8.0 a codeblock that cannot render says why in the note itself rather than failing silently, and a query that matched nothing tells you which property and path it looked for.

Get the plugin

Heatmap Tracker is a free, open-source Obsidian community plugin. Install it from Settings → Community plugins → Browse, or open the plugin page directly.

Install Heatmap Tracker Source on GitHub