Calculate target heart rate zones with the Karvonen method
This target heart rate zone calculator uses age and resting heart rate to estimate five personalized training ranges with the Karvonen method.
Run — free
Unlike a simple percentage of maximum heart rate, Karvonen calculations first find heart rate reserve, then add the resting rate back into each intensity target. The result gives rounded beats-per-minute boundaries from easy aerobic work through maximal effort. It is a practical planning reference for workouts, though it does not replace individualized medical or exercise-testing advice.
How the Karvonen calculation personalizes intensity
The Karvonen method begins with an estimated maximum heart rate of 220 minus age. It then subtracts resting heart rate to obtain heart rate reserve, the span between rest and the estimated maximum. Each training intensity is applied to that reserve, and the resting rate is added back: target heart rate equals resting heart rate plus heart rate reserve multiplied by intensity. This matters because two people of the same age can have different resting pulses and therefore different target ranges. For example, a person with a lower resting heart rate generally has a larger reserve than someone of the same age with a higher resting rate. This calculator divides the reserve into five conventional bands: 50–60%, 60–70%, 70–80%, 80–90%, and 90–100%. Every boundary is rounded to the nearest whole beat per minute so it can be compared easily with a watch, chest strap, exercise machine, or a manual pulse count. The estimated maximum and unrounded reserve are also returned for transparency.
Measure and enter a useful resting heart rate
Resting heart rate is most useful when it reflects a genuinely relaxed state. Measure it after several quiet minutes, or shortly after waking before caffeine, exercise, or a stressful commute changes the reading. Count beats for a full minute or use a reliable monitor, and consider taking measurements on several mornings rather than relying on one unusual day. Enter age in years and the resting value in beats per minute. Age must be positive, and the resting rate must be lower than the age-based estimated maximum; otherwise there is no positive heart rate reserve to divide into training zones. Illness, dehydration, heat, medication, poor sleep, and accumulated training fatigue can all shift pulse responses. Treat the calculated zones as planning estimates rather than exact physiological thresholds. If a measured resting rate changes substantially or symptoms such as chest pain, faintness, or unusual shortness of breath occur, stop exercising and seek appropriate professional guidance instead of attempting to solve the issue by changing a calculator input.
Use the five zones in a training plan
Zone 1 is the lightest range and often suits warm-ups, cool-downs, gentle recovery, and easy movement. Zone 2 is commonly used for comfortable aerobic endurance sessions where breathing remains controlled. Zone 3 introduces a moderate, sustained workload, while Zone 4 represents hard work that is normally maintained for shorter periods. Zone 5 reaches from very hard effort toward the estimated maximum and is generally reserved for brief intervals by people prepared for that intensity. These labels describe increasing cardiovascular demand, not a universal prescription for how much time anyone should spend in each band. Fitness, sport, experience, health status, environmental conditions, and the purpose of a session all affect appropriate intensity. Heart rate also lags behind abrupt changes in effort, so a short sprint may finish before the monitor reaches its corresponding zone. Use the ranges alongside perceived exertion, breathing, pace, power, and recovery. Recalculate when age or a stable resting measurement changes, but avoid adjusting zones in response to every small daily fluctuation.
What you can do with it
Plan an aerobic workout
Turn age and a measured resting pulse into clear bpm ranges for easy, moderate, and hard segments.
Configure monitor alerts
Use the rounded lower and upper boundaries when setting zone notifications on a compatible watch or chest-strap app.
Document a coaching baseline
Record the formula inputs and five calculated ranges before discussing how a broader training plan should use them.
FAQ
What formula does this calculator use?
It estimates maximum heart rate as 220 minus age, calculates heart rate reserve by subtracting resting heart rate, then adds resting heart rate to each selected percentage of the reserve.
What does an API calculation cost?
Each API request costs $0.002. The calculation is deterministic and does not call an external service.
Why does resting heart rate affect the zones?
Karvonen intensities are percentages of the range between rest and estimated maximum, so the same age can produce different targets for different resting rates.
Are these zones medical advice?
No. They are estimates for planning and education. A clinician or qualified exercise professional can advise on safe intensity for an individual condition.
Why are target values rounded?
Heart rate monitors and manual pulse counts are normally read as whole beats per minute, so each calculated boundary is rounded to the nearest integer.
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/calc2/heart-rate-zones \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"age":40,"resting_heart_rate":60}'const res = await fetch("https://api.kit.forhosting.com/calc2/heart-rate-zones", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"age": 40,
"resting_heart_rate": 60
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/calc2/heart-rate-zones",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"age": 40,
"resting_heart_rate": 60
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/calc2/heart-rate-zones", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"age":40,"resting_heart_rate":60}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"age":40,"resting_heart_rate":60}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/calc2/heart-rate-zones", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"age": 40,
"resting_heart_rate": 60
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "calc2.heart_rate_zones",
"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. |