Search...Search plugins and themes...
⌘K
Sign in
  • Get started
  • Download
  • Pricing
  • Enterprise
  • Account
  • Obsidian
  • Overview
  • Sync
  • Publish
  • Canvas
  • Mobile
  • Web Clipper
  • CLI
  • Learn
  • Help
  • Developers
  • Changelog
  • About
  • Roadmap
  • Blog
  • Resources
  • System status
  • License overview
  • Terms of service
  • Privacy policy
  • Security
  • Community
  • Plugins
  • Themes
  • Discord
  • Forum / 中文论坛
  • Merch store
  • Brand guidelines
Follow us
DiscordTwitterBlueskyThreadsMastodonYouTubeGitHub
© 2026 Obsidian

Heatmap Tracker

mokkiebearmokkiebear40k downloads

Visualize your activity and track goals, progress, habits, tasks, exercise, finances, and more—all in a single, interactive heatmap!

Add to Obsidian
  • Overview
  • Scorecard
  • Updates109
Heatmap Tracker Plugin

The Heatmap Tracker plugin for Obsidian is a powerful and customizable tool designed to help you track, visualize, and analyze data over a calendar year. Perfect for habit tracking, project management, personal development, or any kind of data visualization, this plugin enables you to create beautiful, interactive heatmaps directly within Obsidian. Whether you’re monitoring progress, visualizing trends, or staying on top of daily goals, the Heatmap Tracker enhances your productivity and organization. Discover its intuitive features, flexible customization options, and seamless integration with Obsidian in the detailed guide below.

Tip: Check Example Vault. There're lots of good examples (and I update it often).

Prerequisites

This plugin requires the Obsidian Dataview plugin to be installed and enabled to automatically fetch data from your notes.

Getting Started

  1. Install Dataview: Ensure the Dataview plugin is active in your Obsidian vault.
  2. Add Data to Daily Notes: Add a frontmatter property to your daily notes (e.g., YYYY-MM-DD.md) that you want to track.
    • Numeric: photo-taking: 10
    • Boolean: photo-taking: true (counts as 1)
  3. Insert Heatmap: Use the command Insert Heatmap Tracker to generate a heatmap through the interactive modal.

Basic Usage

This plugin comes with frontmatter tracking out of the box. You can use the heatmap-tracker codeblock with the following parameters:

```heatmap-tracker
property: <frontmatter_property_key>
```

This will look for frontmatter_property_key in your daily notes and activate a spot on the heatmap wherever that property is set.

You can also use an array of property names as such:

```heatmap-tracker
property: [<frontmatter_property_key_1>, <frontmatter_property_key_2>, ...]
```

This will aggregate the values of all specified properties on the heatmap.

You can narrow down which notes are included with path, tags, and filters — all optional, and all can be combined:

```heatmap-tracker
property: exercise
path: "daily notes"
tags: [journal]
filters:
  - property: status
    operator: equals
    value: done
```
  • path: folder to search in. Leave unset to search the whole vault.
  • tags: only include notes with at least one of these tags (the leading # is optional).
  • filters: additional frontmatter conditions a note must satisfy — all conditions must match. Each entry has:
    • property: the frontmatter key to check.
    • operator: equals, contains, or notEmpty.
    • value: compared against property's value (ignored, and not required, for notEmpty).

Basic Usage 2.0

You can add a heatmap tracker using command: Insert Heatmap Tracker. This is the easiest way to get started.

Modal to insert Heatmap Tracker to the note

Advanced Usage

If you want something more involved, you may use a dataviewjs codeblock as such (update trackerData with your own dataset to visualize custom data points):

// Update this object
const trackerData = {
    entries: [],
    separateMonths: true,
    heatmapTitle: "This is the title for your heatmap",
    heatmapSubtitle: "This is the subtitle for your heatmap. You can use it as a description.",
}

// Path to the folder with notes
const PATH_TO_YOUR_FOLDER = "daily notes preview/notes";
// Name of the parameter you want to see on this heatmap
const PARAMETER_NAME = 'steps';

// You need dataviewjs plugin to get information from your pages
for(let page of dv.pages(`"${PATH_TO_YOUR_FOLDER}"`).where((p) => p[PARAMETER_NAME])){
    trackerData.entries.push({
        date: page.file.name,
        // Use absolute file path so clicks open the exact note (for cases when you have multiple notes with the same name)
        filePath: page.file.path,
        intensity: page[PARAMETER_NAME],
    });
}

// Optional: set base path so new files are created here if missing
trackerData.basePath = PATH_TO_YOUR_FOLDER;

renderHeatmapTracker(this.container, trackerData);

Notes

  • If you provide filePath for each entry (page.file.path), clicking a heatmap box opens that exact file. If the file is missing, the plugin offers to create it at the same path.
  • If filePath is not set on a box but trackerData.basePath is provided, the plugin proposes creating/opening trackerData.basePath/YYYY-MM-DD.md.
  • If neither is available, it falls back to the Daily Notes settings (folder/format) via the Daily Notes API.

Tracker Settings Documentation

This section is the authoritative reference for every trackerData parameter. EXAMPLE_VAULT has copy-pasteable dataviewjs examples for each one — each parameter below links to its example.

year

  • Type: number
  • Default: Current year (new Date().getFullYear())
  • Description: Specifies the year for which the heatmap should display data by default.
  • Example: year

heatmapTitle

  • Type: string | number
  • Default: undefined
  • Description: Title displayed above the heatmap. Supports HTML for custom styling.
  • Example: heatmapTitle

heatmapSubtitle

  • Type: string | number
  • Default: undefined
  • Description: Subtitle/description displayed under the title. Supports HTML for custom styling.
  • Example: heatmapSubtitle

colorScheme

  • Type: object
  • Default:
{
  "paletteName": "default",
  "customColors": []
}
  • Description: Defines the color scale used for representing different intensity levels in the heatmap. Each color corresponds to a specific range of data intensity. Use paletteName to reference a palette from plugin settings, or customColors to provide your own array of colors inline.
  • Example: colorScheme

customColor

  • Type: string
  • Default: undefined
  • Description: Entry property (set on an item inside entries, not on trackerData itself). Sets the color for that specific entry, overriding colorScheme.

entries

  • Type: array
  • Default:
[
  { "date": "1900-01-01", "customColor": "#7bc96f", "intensity": 5, "content": "" }
]
  • Description: A list of data entries for the heatmap. Each entry includes:
    • date: The date of the entry (ISO string format).
    • intensity: The data intensity for that date.
    • content: Optional tooltip or note associated with the date.
    • customColor: Overrides the color for that entry.
    • filePath: Absolute path to the file to open when clicked.
    • customHref: Custom URL to open when clicked (takes precedence over filePath).
  • Example: entries

showCurrentDayBorder

  • Type: boolean
  • Default: true
  • Description: Indicates whether the current day should be highlighted with a border on the heatmap.
  • Example: showCurrentDayBorder

intensityConfig

  • Type: object
  • Default:
{
  "scaleStart": undefined,
  "scaleEnd": undefined,
  "defaultIntensity": 4,
  "showOutOfRange": true,
  "excludeFalsy": undefined
}
  • Description: Configures the intensity scale used to map entry values to colors.
    • scaleStart / scaleEnd: The minimum/maximum values of the intensity scale. Useful for a custom range, e.g. tracking reading time only between 30 minutes and 2 hours.
    • defaultIntensity: Intensity assigned to entries that don't specify one.
    • showOutOfRange: Whether entries outside scaleStart/scaleEnd are still shown (clamped) or hidden.
    • excludeFalsy: When true, entries with falsy intensity (0, undefined, null, false) are excluded from the heatmap and don't break streaks.
  • Example: intensityConfig

Migrating from defaultEntryIntensity/intensityScaleStart/intensityScaleEnd: these top-level parameters are removed as of the API described here. Old codeblocks using them keep working (they're folded into intensityConfig automatically), but new heatmaps should use intensityConfig directly.


basePath

  • Type: string
  • Default: undefined
  • Description: Base folder used to collect entries. If set, the plugin will propose creating new files in this folder when clicking on empty heatmap boxes.
  • Example: basePath

separateMonths

  • Type: boolean
  • Default: true
  • Description: Determines whether months should be visually separated within the heatmap layout.
  • Example: separateMonths

disableFileCreation

  • Type: boolean
  • Default: false
  • Description: When true, clicking an empty heatmap box will not offer to create a new file.
  • Example: disableFileCreation

insights

  • Type: array
  • Default: []
  • Description: Powerful property for calculating and displaying your own insights in Statistics.
  • Example: insights

layout

  • Type: "default" | "monthly"
  • Default: "default"
  • Description: Controls the heatmap grid arrangement. "default" renders the traditional GitHub-style week-column grid. "monthly" renders one row per month with days 1–31 as columns, providing a compact calendar-style view.
  • Example: layout

Date range: monthsToShow, daysToShow, startDate/endDate

These four parameters all narrow which dates the heatmap displays instead of the full year. Only one wins when several are set — they're resolved in this order (highest priority first):

  1. monthsToShow (number, default undefined) — current month plus the N previous months. monthsToShow: 3 displays 4 rows (current month + 3 prior). Best used with layout: "monthly".
  2. daysToShow (number, default undefined) — the last N days ending today.
  3. startDate + endDate (string, format YYYY-MM-DD, default undefined) — an explicit range. Both must be set, and startDate must not be after endDate.

If none of these are set, the heatmap falls back to showing the full year. This precedence is implemented once, in resolveDateRange — that function's doc comment is the source of truth if this section and the code ever disagree.

  • Example: Date Range Parameters

Exporting a Report

Every heatmap has an Export tab alongside Heatmap Tracker / Statistics / Legend / Documentation. It turns your tracked data and daily notes into a single shareable report — a status update, a work log for a manager, an end-of-year summary — sitting between a bare calendar (too little context) and a folder of raw notes (too much noise).

  • Note content, aggregated: below the calendar and legend, the report walks every week and day in range and pulls in that day's own note content (frontmatter stripped, bullet points kept as written; a day with no note just shows -), grouped under "Week of ..." and per-day headings. The reader gets everything that actually happened, day by day, in one document instead of clicking through each note individually.
  • Layout: "Weeks as columns" or "Weeks as rows", rendered pixel-for-pixel like the heatmap itself — including exact day-level month-splitting (with a year label whenever the range crosses a year boundary) and, when a date range is too wide/tall for one grid, automatic wrapping into multiple bands, evenly split rather than front-loading one band and leaving a small leftover.
  • Date range: pick start/end dates directly, or jump to a range with a preset — Logged (the full span of your tracked data), Last year, Year to date, Last month, or Month to date.
  • Display options: which day the week starts on, whether to show each week's start date, split the grid by month, show month labels, and hide weekends.
  • Legend editor: colors are pre-populated from what's actually used in your data, so you just fill in what each one means. Reorder entries by drag-and-drop, and toggle per-category whether it's counted in the summary line.
  • Summary line: a compact, customizable breakdown like Workday: 22 · Leave: 1 · Rest day but worked: 1 with a total (e.g. Total hours: 169) — or hide the breakdown, the total, or all values entirely.
  • Output: save as a Markdown note or a self-contained HTML file, to whichever folder in your vault you choose.

All of these preferences persist across sessions, so you only need to set them up once.

To be used with Obsidian Dataview, but could be used standalone or with other plugins as well (if you know some javascript).

📦 Plugin Features

1. Easy switch between years. Render a dynamic heatmap for the selected year, displaying data intensity for each day.

Easily switch between years using left and right navigation arrows, allowing you to explore data across multiple years effortlessly.

2. Customizable Colors and Intensity. Define your own color schemes and intensity ranges to match your data's theme.

You have lots of options for defining colors:

  1. Create your own palette in plugin settings (or use default one)
  2. Use `customColors` to set your set of colors for specific plugin
  3. Use `customColor` for specific entry
Снимок экрана 2025-02-08 в 11 11 34
3. User-Defined Insights. This feature allows you to analyze data in ways that matter most to you.

Customize insights such as:

  • The most productive day
  • The longest streak without breaks
  • The most active month
  • Your average daily intensity

Check this file for more information Insights

4. Monthly Separation Option. Choose whether to separate months visually within the heatmap for better clarity and structure.

5. Localization. Plugin supports 9 languages: English, German, Russian, Chinese, Hindi, Spanish, French, Portuguese, and Polish.

See src/localization/locales for the current list, and docs/add-new-language.md if you'd like to contribute a translation.

6. Statistics View. View your progress with an integrated statistics panel.

7. Display Week Numbers. View week numbers alongside the heatmap for better time tracking.

8. Insert Heatmap Tracker. Easily add a heatmap tracker to your notes using a simple command.

9. Customizable Font. Use your favorite font with this plugin.

Additionally, you can use HTML to further customize the plugin's appearance.

Font Customization
10. Monthly Layout. Display your heatmap as a compact calendar with one row per month.

Set layout: "monthly" to switch from the default GitHub-style grid to a calendar-style view with days 1–31 as columns. Combine with monthsToShow to display only recent months.

11. Export a Report. Turn your tracked data and daily notes into a single shareable Markdown or HTML report.

The Export tab renders a grid that matches your heatmap exactly (columns or rows, with automatic day-level month-splitting and band-wrapping for long ranges), then aggregates each day's own note content underneath it, grouped by week — plus a customizable legend, summary line, and date-range presets. See Exporting a Report above for details.

Roadmap

📍 Check out the Roadmap to see what's planned for the future!

Development (Windows/Mac):

📐 New to the codebase? ARCHITECTURE.md maps how data flows from a codeblock/dataviewjs script through to the rendered heatmap.

npm run dev - will start an automatic TS to JS transpiler and automatically copy the generated JS/CSS/manifest files to the example vault when modified (Remember to run npm install first).

After the files have been transpiled, the hot-reload plugin (https://github.com/pjeby/hot-reload) then reloads Obsidian automatically. Hot-reload is installed in the example vault by default. its used to avoid restarting obsidian after every change to code.
(remember to add an empty .hotreload file to "EXAMPLE_VAULT/.obsidian/plugins/heatmap-tracker/" if not already present, as this tells hot-reload to watch for changes)

npm run build generates the files ready for distribution.

 

Tip: ctrl-shift-i opens the devtools inside Obsidian.


Inspired by:

https://github.com/Richardsl/heatmap-calendar-obsidian

HealthExcellent
ReviewRisks
About
Create interactive yearly heatmaps to track and visualize numeric or boolean frontmatter data across daily notes. Use Dataview to pull and aggregate multiple properties, customize display, and insert heatmaps via an interactive modal for habit tracking, project progress, or trend analysis.
VisualizationCalendarProperties
Details
Current version
2.7.0
Last updated
2 days ago
Created
2 years ago
Updates
109 releases
Downloads
40k
Compatible with
Obsidian 0.1.0+
Platforms
Desktop, Mobile
License
Apache-2.0
Report bugRequest featureReport plugin
Sponsor
Buy Me a Coffee
Author
mokkiebearmokkiebear
GitHubmokkiebear
  1. Community
  2. Plugins
  3. Visualization
  4. Heatmap Tracker

Related plugins

Advanced Canvas

Supercharge your canvas experience. Create presentations, flowcharts and more.

Yearly Glance

Year at a glance - overview of annual events with customizable management options.

Excalidraw

Visual PKM powerhouse. Create and edit Excalidraw drawings.

TaskNotes

Note-based task management with calendar, pomodoro and time-tracking integration.

Meta Bind

Make your notes interactive with inline input fields, metadata displays, and buttons.

Breadcrumbs

Visualise the hierarchy of your vault using a breadcrumb trail or matrix view.

Maps

Adds a map layout to bases so you can display notes as an interactive map view.

Multi Properties

Add properties to multiple notes at once. Either right-click a folder or select multiple notes and right-click the selection.

Mermaid Tools

Improved Mermaid.js experience: visual toolbar with common elements and more.

Tracker

Track occurrences and numbers in your notes.