Build guide · About 35 minutes · Rated High on the map

Catch a water leak from the bill instead of the ceiling

A running toilet costs about $60 a month. An underground irrigation break costs more than that a day and leaves no evidence above ground. Both show up as a number on a bill somewhere between thirty and sixty days after they start, and on most portfolios that bill gets coded, paid, and never compared to anything.

Why looking at the bill does not work

Anyone who has approved a utility bill has had the thought that it looked high, and then approved it, because high compared to what. Last month was a different length. Last year was a different occupancy. The rate went up in April. Without a baseline the question has no answer, so the bill gets paid and the leak keeps running.

The other reason it fails is that the number people look at is dollars. Dollars move when the utility raises rates, which they do without asking, and a 9% rate increase reads exactly like a 9% consumption increase on a P&L. Consumption is the number that tells you something is broken.

A leak does not announce itself. It shows up as a bill that is 40% high for three periods in a row, and by the time somebody notices the pattern you have paid for it three times.

What you need

The build

  1. Get consumption, not cost If the only thing you can extract is the dollar amount, this automation will produce false alarms every time the utility reprices and miss real leaks whenever a rate cut hides one. Portals almost always carry usage. If yours does not, the account number and a phone call will usually get you a twelve-month usage history as a spreadsheet.
  2. Divide by days, before anything else Billing periods are not months. They run 28 to 34 days depending on the meter reader's route, and a 34-day period is 21% larger than a 28-day one for no reason at all. Comparing raw period totals generates a spike every quarter that turns out to be a calendar.
    const days  = (new Date(end) - new Date(start)) / 86400000;
    const daily = consumption / days;   // compare this, never the raw total
  3. Build the baseline from the median, not the mean One prior leak in the history will drag a mean upward and mask the next one. The median ignores it. If you have two years, use the same calendar month from prior years so seasonality is built in. With only twelve months, use a rolling median of the last six periods and accept that the first summer will need a human eye.
    function median(xs) {
      const s = [...xs].sort((a, b) => a - b);
      const m = Math.floor(s.length / 2);
      return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
    }
    
    function expectedDaily(history, meterId, month) {
      const sameMonth = history.filter(r =>
        r.meterId === meterId && new Date(r.end).getMonth() === month);
      if (sameMonth.length >= 2) return median(sameMonth.map(r => r.daily));
      const recent = history.filter(r => r.meterId === meterId).slice(-6);
      return median(recent.map(r => r.daily));
    }
  4. Compare and rank by dollars, not by percent A 60% spike on a meter that costs $40 a month is not worth a phone call. A 25% spike on the master water meter at a 120-unit property is worth driving over. Compute the variance in units, then multiply by the rate so the alert sorts by what it is costing you.
    const expected = expectedDaily(history, r.meterId, month);
    const pct      = (r.daily - expected) / expected;
    const extraPer = (r.daily - expected) * days * ratePerUnit;   // dollars this period
  5. Send one email per property, not one per meter A property with fourteen meters will produce fourteen alerts on the month the rate changes, and you will turn the whole thing off. Group by property, list only the meters over threshold, sort by dollars, and say plainly when nothing broke.

The thresholds, and why these ones

A starting table rather than a standard. Water is the one worth tuning hardest, because it is where the expensive failures are.

ConditionWhat it usually isWhat to do
Over 40% above expected, one periodCould be a leak, could be an estimated read, could be irrigation turning on for the season.Check whether the read was estimated before anything else. If actual, walk the property.
Over 25% above expected, two periods runningTreat as a leak until proven otherwise. Two consecutive periods rules out most billing artifacts.Meter the buildings separately if you can, and check irrigation zones and unit toilets in that order.
Over 15% and rising three periods runningSomething is degrading rather than broken. Often a slowly failing flapper population or a pressure regulator.Worth a plumber walking the units at turn.
Below 60% of expectedAlmost always an estimated read, and the true-up is coming.Flag it so the next period's spike is not read as a leak.

Three things that will break it

Estimated reads. The single largest source of false alarms. When the utility cannot access the meter it estimates, then trues up on the next actual read. That produces a fake low period followed by a fake spike, and your automation will call the true-up a leak. Most bills mark the read type. Parse it, and when a period is estimated, compare the pair of periods together rather than each one alone.

Occupancy moved and nobody told the baseline. A building that was 70% occupied last August and is 95% now should use more water, and the automation will report that as a problem every period until you account for it. If you have unit counts, normalize to consumption per occupied unit per day. If you do not, at least suppress alerts on any property whose occupancy moved more than ten points against the comparison period.

Meters get re-mapped and history follows the wrong one. A property adds a meter, or the utility replaces one and issues a new number, and six months of history now belongs to a meter that no longer exists while the new one has none. Key your history on your own internal meter ID with the utility's number as an attribute, and alert when a bill arrives carrying a meter number you have never seen.

If you would rather not build it

The kit is the finished version of everything above: the scenario blueprint, the consumption parser, the seasonal baseline, and the thresholds as a spreadsheet you can edit. Email [email protected] if you would rather have it built into what you already run.

Get the next build guide

One email when a new guide goes up. Nothing else.

No sequence, no upsell drip. Unsubscribe link on every send.