Water hardness converter
Put a city water report and a softener manual on the same scale: one grain per gallon is 17.1 ppm and one German degree is 17.8 ppm, and every reading bridges through ppm. Ready for plumbers, homeowners and students. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Value
- 100
- Source unit of 'value'
- ppm
- To
- gpg
- Result
- 5.8479532164
- From label
- parts per million
- To label
- grains per gallon
- Value ppm
- 100
This water hardness converter turns a numeric hardness reading from one common reporting unit into another and returns the converted magnitude with canonical unit labels. Supported systems are parts per million as calcium carbonate, milligrams per liter, grains per US gallon, and German degrees of hardness. For dilute aqueous solutions one part per million equals one milligram per liter, one grain per gallon equals 17.1 parts per million, and one German degree equals 17.8 parts per million, so every conversion bridges through a single ppm intermediate with fixed factors. Conversion uses only finite arithmetic with no network calls, no sampling, and no date-dependent shortcuts. Typical checks include one hundred parts per million to grains per gallon and ten German degrees back to milligrams per liter.
Where water hardness conversion fits in plumbing, labs, and software
Municipal reports, European softener manuals, and North American appliance guides often mix parts per million, milligrams per liter, grains per gallon, and German degrees, so a single deterministic converter prevents hand-calculator drift when a plumber, homeowner, student, or developer compares readings across devices and papers.
Softener installers convert a municipal ppm report into grains per gallon for capacity tables; European product sheets map °dH setpoints into mg/L for export markets; teachers assign homework that needs a fast, offline check of the 17.1 and 17.8 factors without trusting opaque apps that silently change precision. Developers call the same contract from scripts to seed deterministic test vectors for water-treatment UIs, to normalize user-entered hardness before charting demos, or to satisfy programming-challenge statements that demand exact factors rather than a hand-waved estimate.
Product tools use the rewrite when a learner or agent types one hundred ppm and the UI must show grains per gallon side by side. Pair it with general concentration converters when you need molarity for other solutes, and remember this tool does not classify soft versus hard water or recommend treatment equipment.
What you can do with it
Softener and plumbing unit alignment
Convert municipal ppm or mg/L reports into grains per gallon so softener capacity tables, install notes, and appliance manuals share one hardness unit.
Cross-region product and lab sheets
Map German degrees (°dH) into ppm or mg/L for export specs, European manuals, and dual-system lab printouts without hand-calculator drift.
FAQ
What does the water hardness converter cost?
It is free in your browser on this page.
What conversion factors are used?
All conversions bridge through parts per million as CaCO3 equivalent.
Does this tool classify soft or hard water or recommend a softener?
No. It only converts hardness units among ppm, mg/L, gpg, and German degrees. It does not provide treatment advice or hardness category labels.
How do I convert ppm hardness to grains per gallon?
Divide the ppm figure by 17.1. A report of 100 ppm becomes 5.8479532164 grains per gallon, a little under 6, which is the unit most softener capacity tables use.
How many mg/L is 10 German degrees of hardness?
It is 178 mg/L. Each German degree equals 17.8 ppm, and for dilute water one ppm equals one milligram per liter, so you simply multiply by 17.8.
Related tools
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/conv/water-hardness \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"value":100,"from":"ppm","to":"gpg"}'const res = await fetch("https://api.kit.forhosting.com/conv/water-hardness", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"value": 100,
"from": "ppm",
"to": "gpg"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/conv/water-hardness",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"value": 100,
"from": "ppm",
"to": "gpg"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/conv/water-hardness", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"value":100,"from":"ppm","to":"gpg"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"value":100,"from":"ppm","to":"gpg"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/conv/water-hardness", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"value": 100,
"from": "ppm",
"to": "gpg"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "conv.water_hardness",
"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.
Limits
max_abs_value | 1000000000000 |
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. |
Technical notes
Everyday aliases such as mg/L, gpg, grains, °dH, and deutsche haerte are accepted so lab printouts, softener manuals, and spreadsheet cells can share one contract.
What the water hardness converter returns and which units it understands
A water hardness unit conversion answers a narrow question: given a hardness magnitude in one common reporting unit, what is the equivalent magnitude in another unit that labs, softener manuals, and municipal reports actually use. This calculator accepts a numeric value, a source unit, and a target unit, then returns the converted result rounded to a stable precision, the canonical from and to identifiers, human-readable labels, the intermediate value in parts per million, and the fixed factors 17.1 grains per gallon and 17.8 German degrees used for the bridge. Everyday spellings such as mg/L, mg/l, milligrams per liter, grains per gallon, grain, °dH, dH, and deutsche haerte normalize to those ids so forms, query strings, and spreadsheets can reuse the same contract without inventing private enums. Canonical ids are ppm for parts per million as calcium carbonate, mg_l for milligrams per liter, gpg for grains per US gallon, and dH for German degrees. There is no approximate temperature correction and no lab-specific hardness scale path: the engine either multiplies and divides by the fixed ppm factors inside the supported magnitude range or rejects the input with invalid_input. Rejected cases include missing value, from, or to; non-finite numbers; magnitudes above the documented ceiling; negative hardness; and any unit string that is not on the supported list.
How the ppm bridge is applied and how results stay reproducible
Optional scientific notation on the value string is allowed when it parses as a finite decimal; embedded spaces, hex prefixes, and non-numeric tokens are rejected with a clear message so a bad cell does not become a wrong softener setpoint. Zero is a valid value and simply yields zero in the target unit. Computation multiplies value by the source factor in parts per million, then divides by the target factor: one grain per gallon is exactly 17.1 ppm and one German degree is exactly 17.8 ppm, while ppm and mg/L share a one-to-one ratio. One hundred parts per million therefore becomes one hundred divided by 17.1 grains per gallon, and ten German degrees becomes ten times 17.8 milligrams per liter. The preferred fields are value for the hardness magnitude, from for the source unit, and to for the target unit, with aliases amount, hardness, n, quantity, and level for the value, unit, from_unit, source, and input_unit for from, and target, to_unit, output_unit, and into for to so heterogeneous clients can share one contract. Negative values fail with invalid_input because physical hardness cannot be negative. An optional precision field, with aliases decimals and dp, chooses how many decimal places to expose for value, result, and value_ppm, defaulting to ten and capped at fifteen so JSON goldens stay stable. Pair the free browser run on this page with the priced API when you need the identical mathematical result inside an automated pipeline without re-implementing unit tables yourself.
Where water hardness conversion fits in plumbing, labs, and software
On this page the work runs entirely in your browser; through the API each successful lookup costs $0.002, failed validation is not charged, and nothing is stored after the response returns. That split — free interactive exploration and a priced, identical API — matches the rest of the KIT tier-A catalog and lets you move from a classroom demo to an automated pipeline without changing the mathematical result.
Integration use cases
Homework and CI fixtures
Generate reproducible water hardness conversions for worksheets, tutoring software, and unit tests that assert the fixed 17.1 gpg and 17.8 °dH factors.
Technical questions
Which water hardness units are supported?
Parts per million (ppm), milligrams per liter (mg_l / mg/L), grains per US gallon (gpg), and German degrees (dH / °dH). Common aliases such as grains, deutsche haerte, and mg per liter are accepted.
What happens if I send an unknown unit?
The request fails with invalid_input and a message listing the supported units. Unknown strings are never silently remapped.