Running age-grade calculator
This running age-grade calculator turns a race result into a percentage that can be compared across ages, sex categories, and common road distances.
Run — free
It uses fixed performance standards and age-factor tables, then reports the underlying factor and benchmark times as well as a plain-language classification. The calculation is deterministic, works entirely offline, and accepts kilometres or miles plus familiar clock formats. It is useful for tracking how strong a performance was in context, while keeping the original finishing time visible and unchanged.
What an age-grade percentage means
Age grading compares a finishing time with a benchmark performance for a runner of the same age and sex category over the same distance. A result near 60 percent is commonly associated with a solid local-level performance, 70 percent with regional class, 80 percent with national class, and 90 percent or more with world class. Those labels are broad orientation, not selection standards or medical judgments. A percentage can exceed 100 when a supplied result is faster than the table-derived age standard. That does not make the input invalid; it signals that the result is beyond the particular fixed benchmark set used here. Because age grading normalizes context, it is especially helpful when comparing performances several years apart or following runners of different ages. It should not replace the actual time, course conditions, elevation, weather, or race certification. Treat it as one consistent lens on performance rather than a complete verdict about fitness or competitive rank.
How the calculator uses its tables
The calculator first converts the entered distance to kilometres and the finishing time to seconds. It selects a male or female open-standard table containing fixed benchmark times at established road distances from one mile through 100 kilometres. When the entered distance falls between two listed distances, it interpolates in logarithmic distance and time space, which produces a smooth pace curve without a network lookup. It then selects the age-factor table for the chosen sex category. Factors are listed at fixed age knots and linearly interpolated between them. The open-standard time divided by that factor gives the age-specific standard time; dividing that standard by the runner's actual time produces the percentage. Every table is embedded with the capability, so repeated input always produces identical output. These figures are suitable for consistent comparison within this calculator. Different governing bodies, table editions, event surfaces, or calculators may publish slightly different standards, so record the method when comparing results from separate systems.
Enter a result and interpret it carefully
Enter age as whole years on race day, choose the applicable sex category, provide a positive distance, and select kilometres or miles. Finishing time may be written as hours, minutes, and seconds; minutes and seconds; or a plain count of seconds. For example, 48:30 means forty-eight minutes and thirty seconds, while 1:42:15 means one hour, forty-two minutes, and fifteen seconds. The accepted distance range is one mile through 100 kilometres because extrapolating beyond the embedded standards would be misleading. The response includes the normalized distance, parsed time, age factor, open standard, age-specific standard, percentage, and classification. Use the detailed fields to audit the result rather than copying only the label. For longitudinal tracking, keep sex category, distance, and calculator method consistent. Course difficulty, wind, heat, altitude, trail terrain, and measurement error are not adjusted, so comparisons work best for accurately measured races under broadly similar conditions. The API price is $0.002 per request, while the browser calculation uses the same pure logic offline.
What you can do with it
Compare seasons fairly
Normalize race performances from different ages to see whether competitive level is holding steady over time.
Review club results
Add a consistent contextual percentage to mixed-age race results without hiding each runner's actual finishing time.
Set a benchmark goal
Use the returned age-specific standard and percentage to estimate the improvement needed for a chosen classification band.
FAQ
What does the percentage compare?
It compares the entered finishing time with a table-derived standard for the same age, sex category, and distance.
Can an age grade exceed 100 percent?
Yes. It means the entered time is faster than the age-specific benchmark derived from this calculator's fixed tables.
Why does another calculator give a different result?
Table editions, benchmark sources, interpolation methods, event categories, and rounding can differ. Compare results made with the same method.
Does this adjust for hills or weather?
No. It uses distance and finishing time only; course profile, surface, altitude, wind, and temperature are not adjusted.
What time formats are accepted?
Use H:MM:SS, MM:SS, or a positive number of seconds. Seconds may include a decimal fraction.
How much does the API request cost?
The API price is $0.002 per request. The browser version runs offline using the same deterministic logic.
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/health/age-grade-running \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"age":52,"sex":"female","distance":10,"finishing_time":"48:30"}'const res = await fetch("https://api.kit.forhosting.com/health/age-grade-running", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"age": 52,
"sex": "female",
"distance": 10,
"finishing_time": "48:30"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/health/age-grade-running",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"age": 52,
"sex": "female",
"distance": 10,
"finishing_time": "48:30"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/health/age-grade-running", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"age":52,"sex":"female","distance":10,"finishing_time":"48:30"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"age":52,"sex":"female","distance":10,"finishing_time":"48:30"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/health/age-grade-running", 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": 52,
"sex": "female",
"distance": 10,
"finishing_time": "48:30"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "health.age_grade_running",
"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. |