The no-code heatmap-tracker codeblock covers
frontmatter. A dataviewjs block covers everything else:
computed values, several sources merged, a colour per entry, values
that live in inline fields or in the note body. You build an
entries array and hand it to
renderHeatmapTracker().
What you need first
- The Dataview plugin, installed and enabled.
-
Dataview → Settings → Enable JavaScript Queries, which is
off by default. Without it a
dataviewjsblock renders nothing at all. -
Heatmap Tracker itself, which registers the global
renderHeatmapTracker(container, trackerData).
The minimal working block
```dataviewjs
const trackerData = {
entries: [],
heatmapTitle: "Steps",
heatmapSubtitle: "Pulled from my daily notes",
separateMonths: true,
};
const FOLDER = "daily notes";
const PROPERTY = "steps";
for (let page of dv.pages(`"${FOLDER}"`).where((p) => p[PROPERTY])) {
trackerData.entries.push({
date: page.file.name,
filePath: page.file.path,
intensity: page[PROPERTY],
});
}
trackerData.basePath = FOLDER;
renderHeatmapTracker(this.container, trackerData);
```
Three fields carry the weight. date places the square,
intensity decides its colour, and
filePath is what a click opens.
The shape of an entry
| Field | Type | What it does |
|---|---|---|
date |
string | A plain YYYY-MM-DD string. Required. |
intensity |
number | Feeds the colour scale. |
filePath |
string | Absolute vault path, so a click opens the right note. |
customColor |
string | Overrides the palette for that one day. |
content |
string | Extra text shown for the day. |
Getting dates right
The single most common bug in scripted heatmaps is an off-by-one
day, and it is almost always a timezone issue. Pass plain
YYYY-MM-DD strings. A JavaScript Date or a
full ISO timestamp carries a time component, and that time can cross
midnight once it is interpreted in the local zone.
// Good — the filename of a daily note is already YYYY-MM-DD
date: page.file.name
// Good — a Dataview date, formatted explicitly
date: page.due.toFormat("yyyy-MM-dd")
// Risky — a Date object or an ISO timestamp with a time part
date: new Date(page.created)
Computed and combined values
Because it is JavaScript, the value does not have to exist in any note. Sum several fields, count tasks, or weigh categories differently:
```dataviewjs
const trackerData = { entries: [], heatmapTitle: "Focus score" };
for (let page of dv.pages('"daily notes"')) {
const deep = page["deep-work"] ?? 0;
const meetings = page["meetings"] ?? 0;
const score = deep * 2 - meetings;
if (score <= 0) continue;
trackerData.entries.push({
date: page.file.name,
filePath: page.file.path,
intensity: score,
customColor: score > 8 ? "#39d353" : undefined,
});
}
renderHeatmapTracker(this.container, trackerData);
```
Counting completed tasks per day works the same way — iterate
page.file.tasks and use the count as the intensity.
How a click resolves a file
-
If the entry has
filePath, that exact file opens. If it is missing, the plugin offers to create it at the same path. -
Otherwise, if
trackerData.basePathis set, it proposesbasePath/YYYY-MM-DD.md. - Otherwise it falls back to your Daily Notes folder and format.
Use page.file.path rather than
page.file.name whenever two notes in the vault can
share a filename. Set disableFileCreation: true if you
would rather empty squares did nothing.
Useful trackerData options
| Option | Effect |
|---|---|
year |
Which year to open on. Defaults to the current one. |
colorScheme |
paletteName from settings, or an inline
customColors array.
|
intensityConfig |
scaleStart / scaleEnd, plus
excludeFalsy.
|
layout |
"monthly" for a calendar-style view instead of
the year grid, or "month" / "week"
for a single calendar period.
|
monthsToShow, daysToShow,
startDate/endDate
|
Show a window instead of a full year. |
insights |
Your own metrics in the Statistics tab. |
The configuration reference documents every parameter, each with a worked example in the example vault.
Does it have to be Dataview?
renderHeatmapTracker(container, trackerData) only cares
about the entries array. Any JavaScript that can build
one — a Templater script, a fetch from a local file — works the same
way. Dataview is simply the most convenient source of dated pages,
and the heatmap-tracker codeblock does depend on it.