Habit tracking streak calculator
This habit streak calculator turns a list of completion dates into two useful measurements: the consecutive-day streak ending on the latest recorded completion and the longest consecutive run anywhere in the history.
Run — free
Dates may arrive out of order, and repeated entries are counted only once, so exports from trackers, journals, or spreadsheets can be used directly. The calculation is deterministic and based on calendar days rather than elapsed local hours, making the result stable across time zones and daylight-saving changes.
Prepare a clean completion history
Provide every calendar date on which the habit was completed using the YYYY-MM-DD format. The list does not need to be sorted, because the calculator orders the dates before measuring any run. Repeated dates are also safe: if an app exported the same completion twice, that day contributes only once. A completion at any time during a calendar day represents that whole day, so timestamps, hours, and time-zone offsets are intentionally not accepted. This keeps the meaning of a streak clear and avoids treating two entries on one day as two days of progress. Include the entire history when you want a trustworthy longest streak, not merely the most recent month or the portion visible in a dashboard. The list must contain at least one date, and every entry must describe a real calendar date. Values such as February 30, partial dates, or differently formatted text are rejected instead of being silently corrected. That strictness helps reveal bad exports before they produce a misleading personal record.
Understand current and longest streaks
The current streak is the consecutive sequence that ends on the latest completion date supplied. This definition does not consult today's date, which means the same input always returns the same answer and historical exports remain reproducible. For example, if the latest recorded dates are Monday, Tuesday, and Wednesday, the current streak is three even when the calculation is performed later. A missing Tuesday breaks a Monday-to-Wednesday sequence, because streaks require adjacent calendar dates. The longest streak is the greatest such sequence anywhere in the complete history, so it may be older and larger than the current streak. The result also reports the number of unique completion days and the latest date used, which makes it easier to confirm that duplicates were removed and that the intended history was received. Leap days, month boundaries, and year boundaries are handled as ordinary adjacent calendar days. These rules provide useful tracker metrics without relying on the machine clock or a visitor's location.
Use the result in trackers and reviews
Use the current streak to summarize the momentum present at the end of a recorded history, and use the longest streak as a personal benchmark. A habit application can calculate both after importing an event log, while a spreadsheet workflow can send one date column and store the returned metrics beside a monthly review. Because input order has no effect, clients do not need a separate sorting step. Because duplicates count once, retries and merged exports do not inflate the answer. Still, interpret streaks with care: they measure consistency of recorded completion, not effort, quality, or long-term benefit. If your habit permits rest days or follows a weekly schedule, a strict consecutive-day streak may not represent the behavior you intend to reward. In that case, transform the dates according to your own schedule before using this calculator. API requests use the displayed $0.002 base price. The browser version uses the same pure calculation logic, with no network, randomness, or current-date dependency in the algorithm.
What you can do with it
Add streaks to a habit tracker
Calculate current momentum and the historical record whenever a user imports or updates completion dates.
Review a journal export
Turn a column of dated check-ins into concise consistency metrics without manually sorting the entries.
Merge tracking histories
Combine dates from multiple sources while ensuring duplicate completions do not inflate either streak.
FAQ
What does current streak mean?
It is the consecutive-day run ending on the latest date in the supplied history. It is not compared with today's date.
Do duplicate dates increase a streak?
No. Each calendar date is counted once, even if it appears repeatedly in the input.
Do the dates need to be sorted?
No. Dates are validated, deduplicated, and sorted before streaks are calculated.
What happens when the date list is empty?
The request returns an invalid input error because a streak cannot be calculated without at least one completion date.
Are leap years and month boundaries supported?
Yes. Valid adjacent calendar dates remain consecutive across month, year, and leap-day boundaries.
What does an API request cost?
Each API request uses the $0.002 base price.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/final3/habit-streak-calculate \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"dates":["2026-07-20","2026-07-21","2026-07-23","2026-07-24","2026-07-25"]}'const res = await fetch("https://api.kit.forhosting.com/final3/habit-streak-calculate", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"dates": [
"2026-07-20",
"2026-07-21",
"2026-07-23",
"2026-07-24",
"2026-07-25"
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/final3/habit-streak-calculate",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"dates": [
"2026-07-20",
"2026-07-21",
"2026-07-23",
"2026-07-24",
"2026-07-25"
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/final3/habit-streak-calculate", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"dates":["2026-07-20","2026-07-21","2026-07-23","2026-07-24","2026-07-25"]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"dates":["2026-07-20","2026-07-21","2026-07-23","2026-07-24","2026-07-25"]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/final3/habit-streak-calculate", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"dates": [
"2026-07-20",
"2026-07-21",
"2026-07-23",
"2026-07-24",
"2026-07-25"
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "final3.habit_streak_calculate",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |