How the United Kingdom take-home pay calculator is verified
Inputs
| Input | Field | Type |
|---|---|---|
| Gross annual salary (GBP) | grossAnnual | number |
| Pension contribution (fraction, e.g. 0.05) | pensionPct | number |
The formula
Each derived value below is computed by the Valem engine from the expression shown, in this order. Nothing else runs — there is no hidden code path.
| Derived value | Field | Formula (JSONata) |
|---|---|---|
| Pension Contribution | pensionContribution | $round(grossAnnual * pensionPct, 2) |
| Adjusted Income | adjustedIncome | $round(grossAnnual - pensionContribution, 2) |
| Personal allowance | personalAllowance | ($over := adjustedIncome - $const.paTaperThreshold; $red := $over > 0 ? $over / 2 : 0; $pa := $const.paBase - $red; $round($pa > 0 ? $pa : 0, 2)) |
| Taxable income | taxableIncome | ($ti := adjustedIncome - personalAllowance; $round($ti > 0 ? $ti : 0, 2)) |
| Income tax | incomeTax | ($ti := taxableIncome; $b := $ti < $const.basicBand ? $ti : $const.basicBand; $h := $ti > $const.basicBand ? ($ti < $const.higherTaxableLimit ? $ti : $const.higherTaxableLimit) - $const.basicBand : 0; $a := $ti > $const.higherTaxableLimit ? $ti - $const.higherTaxableLimit : 0; $round($b * $const.basicRate + $h * $const.higherRate + $a * $const.additionalRate, 2)) |
| National Insurance | ni | ($m := (grossAnnual < $const.niUpperLimit ? grossAnnual : $const.niUpperLimit) - $const.niPrimaryThreshold; $m := $m > 0 ? $m : 0; $u := grossAnnual - $const.niUpperLimit; $u := $u > 0 ? $u : 0; $round($m * $const.niMainRate + $u * $const.niUpperRate, 2)) |
| Net / year | netAnnual | $round(grossAnnual - pensionContribution - incomeTax - ni, 2) |
| Net / month | netMonthly | $round(netAnnual / 12, 2) |
Rates and thresholds
The expressions above read these as $const. They are the figures the annual refresh replaces, so they live as data rather than being written into the formulas — which is what makes a year-on-year change a one-line diff instead of an edit to arithmetic.
| Constant | Value |
|---|---|
paBase | 12570 |
paTaperThreshold | 100000 |
basicBand | 37700 |
higherTaxableLimit | 112570 |
basicRate | 0.2 |
higherRate | 0.4 |
additionalRate | 0.45 |
niPrimaryThreshold | 12570 |
niUpperLimit | 50270 |
niMainRate | 0.08 |
niUpperRate | 0.02 |
Test vectors (2)
Every case is executed against this model on each build, by the Java engine and independently by a JavaScript one. A mismatch of a single cent fails the build, so the page cannot ship advertising a figure the model no longer produces.
Case 1 — S1 35,000 GBP single, no pension
given grossAnnual | 35000 |
|---|---|
given pensionPct | 0 |
expect personalAllowance | 12570 |
expect taxableIncome | 22430 |
expect incomeTax | 4486 |
expect ni | 1794.4 |
expect netAnnual | 28719.6 |
expect netMonthly | 2393.3 |
Case 2 — S3 130,000 GBP — personal allowance fully tapered
given grossAnnual | 130000 |
|---|---|
given pensionPct | 0 |
expect personalAllowance | 0 |
expect taxableIncome | 130000 |
Sources
- GOV.UK — Income Tax rates and allowances · checked 2026-08-02
- GOV.UK — NI rates & thresholds 2025-26 · checked 2026-08-02
Check it yourself — and reuse it
The whole model as JSON — inputs, outputs, formulas, vectors and sources in one re-runnable document.
This model is published under CC BY 4.0: use it, adapt it, build on it, with attribution. The licence covers the model — the expression of each rule and the arrangement of the catalog. The rates and thresholds are law, and nobody licenses those; the sources above are where they come from.
← Back to the United Kingdom take-home pay calculator
Built with Valem — a live, verifiable calculator you can fork and embed.