Habit Tracker

Mark days on a year heatmap and watch a current streak, a longest streak and a completion rate counted from the day you created the habit. JSON export.

🌐 Español

🔒 Private by design: everything runs locally in your browser and never uploaded to any server.

Marking your first day on the grid

  1. Type a name in the New habit name box and press Enter, or click + New habit. The habit is created with today’s date as its start and picks the next colour from the preset palette.
  2. Click any past or present square in the year grid to mark that day complete. Click it again to undo. Future squares are dimmed and refuse the click entirely.
  3. Watch Current streak, Longest streak and Completion rate recalculate above the grid. Nothing is cached; all three are derived from your list of marked days every time it changes.
  4. Use the arrows either side of the year label to move between years. The forward arrow is disabled once you reach the current year.
  5. Rename the habit in the text field, change its colour with the swatch beside it, or press Delete habit to remove it after confirming.
  6. Press Export all habits (JSON) for a backup file, and Import habits (JSON) to load one back in on this device or another.

The one-day grace period in the current streak

The current streak is the run of consecutive marked days ending today, but if today is not marked yet it counts through yesterday instead. That grace period matters more than it sounds. Without it, every streak would read zero from midnight until the moment you got round to marking the day, which turns the number you are trying to protect into a source of daily false alarms.

The rule is strict about one thing: if neither today nor yesterday is marked, the current streak is zero, however long the run further back was. Take a habit marked on five consecutive days that ended a week ago. The current streak reads 0, the longest streak still reads 5, and the completion rate carries on reflecting all five days. The longest streak is a full scan of your entire history for the best run of consecutive days, so it never falls when a current run breaks. That separation is the whole point of showing two numbers instead of one.

Backfilling days you were already doing

Marking a day that predates the habit itself is allowed on purpose. You had been running for three weeks before you thought to track it, so it would be perverse to lock those squares. Backfilled days count towards both streak numbers exactly like any other day.

They do not, however, inflate the completion rate, because that percentage only looks at the window between the habit’s creation date and today. A habit created yesterday, with marks on the two days before it as well as yesterday and today, reports a current streak of 4 and a longest streak of 4, while the completion rate reads 100% from 2 days out of 2. The two days outside the window are excluded from both halves of the fraction, so the rate stays honest rather than climbing past 100%.

What the completion rate divides by

The denominator is elapsed calendar days since the habit was created, inclusive of both ends, not days since your first mark and not days in the current year. A habit created today with nothing marked shows 0%, never a blank or an error, because the denominator is 1 rather than 0. Five marked days on a habit created 32 days ago works out at 15% after rounding to the nearest whole percent, because 32 days ago through today is 33 elapsed days.

This is a deliberately unforgiving denominator. It keeps counting on the days you skip, which is what makes the number worth looking at. If you would rather measure effort in blocks of focused time than in days, pair the tracker with the Online Timer and mark the square once the session ends.

365 cells, 366 in a leap year, 53 columns

The grid is a genuine day-by-day calendar year rather than a rolling window. The cell count comes from subtracting one January the first from the next using the same day-counting helpers the Days Between Dates Calculator is built on, so 2026 renders 365 cells and 2028 renders 366 without a leap-year rule written twice.

Those cells are grouped into GitHub-style week columns of seven, Sunday at the top. Because January the first rarely lands on a Sunday, the first column is padded with blanks and so is the last: 2026 comes out as 53 columns with four blank slots before New Year’s Day and two after New Year’s Eve. Hovering any square shows its date. The month strip above the grid is thinner than it looks, though, because an abbreviation is only printed when the first of a month happens to be its column’s opening day; across 2026 that is true for four months out of twelve, so most of the strip is blank.

The JSON file is the only copy you can move

Habits and marked days live in this browser’s local storage and nowhere else. There is no account, no sync and no server, so a habit exists in exactly one browser profile until you do something about it. Export writes every habit you have, not just the selected one, as a readable JSON file named habit-tracker.json, complete with each habit’s colour, creation date and full list of marked days. That file is a real backup and a real migration path, and importing it elsewhere restores your streaks intact.

Clearing site data in this browser wipes the habits with it, which is worth remembering before a spring clean. The same local-first arrangement runs through the tools built alongside this one, such as the Kanban Board and the Online Notepad, and the rest of the collection sits on the generators hub.

See it in action

Screenshot of the Habit Tracker tool with an empty habit list with a name field and a create button, plus import and export of all habits as JSON
Habit Tracker mid-process: an empty habit list with a name field and a create button, plus import and export of all habits as JSON.
Screenshot of the Habit Tracker result screen showing a habit created and selected, with its year heatmap and streak tracking ready to record the first day
The finished result: a habit created and selected, with its year heatmap and streak tracking ready to record the first day. The download link is a local blob URL — the file never leaves your device.

Frequently asked questions

Can I scroll the heatmap back to a year before I started using this?

Yes. The left arrow has no lower limit, so you can page back as far as you like and mark days in an earlier year; only the right arrow stops, at the current calendar year. Days in a past year behave exactly like recent ones, which is what makes backfilling possible at all.

If I import the same JSON file twice, do I end up with duplicate habits?

No. Import compares the identifier of each habit in the file against the habits you already have and skips the ones that match, so re-importing your own backup is harmless. Habits from the file that are genuinely new are added alongside your existing ones rather than replacing them.

What is the "Completion rate (12/40 days since created)" label under the percentage?

The two numbers behind the percentage. The first is how many days you have marked inside the window that counts, and the second is how many calendar days have elapsed from the habit's creation date through today, counting both ends. Seeing the raw fraction makes it obvious why a percentage moved, which a bare number never does.

Can I see two habits on the same grid at once?

Not in one grid. The heatmap always shows a single habit, chosen in the dropdown at the top, and every stat above it belongs to that habit alone. Each habit keeps its own colour, which tints its marked cells and fills the swatch beside the name field once it is selected, but the switcher itself is a plain list of names, there is no combined or stacked view, and no attempt to score you across habits.

What happens if I leave the page open overnight?

Today's date is read once when the page loads, so a tab left open past midnight keeps treating the previous day as today until you reload. Marking days still works, but the cell outlined as today, and the grace period built into the current streak, will both be a day behind. Refresh the page after midnight and everything realigns.

Does the colour I pick for a habit affect anything besides the grid?

Only the appearance. The colour tints that habit's completed cells and its swatch, and it is stored with the habit, which means it travels in the JSON export and comes back on import. New habits cycle through six presets, starting green, so the seventh habit you create reuses the first colour.

Related tools