Dashwall
All articles
5 min read

The dashboard that lies quietly

An empty tile is honest. It says “waiting for the first value” and everybody in the room understands it instantly. The dangerous tile is the one that was right on Friday afternoon and still says Friday's number on Monday morning, in numerals a foot tall, with a sparkline, looking exactly as authoritative as it did when it was true. Nobody distrusts it. That is the problem.

Every metrics wall eventually meets this failure. A cron job stops firing, a deploy takes an API key with it, a queue backs up, someone renames a column. The feed dies quietly and the wall keeps broadcasting the last thing it heard. Here is how Dashwall handles it, and why the honest version of a tile turned out to be smaller and quieter than you would expect.

A dead feed looks exactly like a quiet one

This is the whole difficulty. “Zero deploys since yesterday” and “the deploy webhook broke on Tuesday” produce identical pixels: a number that is not moving. No amount of design fixes that, because the wall genuinely cannot tell the difference. It has one reading and a timestamp, and it has no idea whether another one was due.

So we asked for the missing half. Every tile can carry an expected update interval. In the dashboard it is a plain question, how often is it updated?, answered with the intervals people actually run things on: every minute, every five minutes, hourly, daily, weekly. Once a tile knows what it expects, silence stops being ambiguous.

The default is no expectation, and that matters as much as the feature. A tile fed by hand, or by an event that may simply not happen this week, should never accuse itself of being broken. Staleness is opt-in per tile, because only you know which feeds have a heartbeat.

Set the expectation when you create the tile
# A tile fed by a five-minute cron says so when it is created
curl -X POST https://api.dashwall.io/api/boards/$BOARD_ID/tiles \
  -H "Authorization: Bearer $DASHWALL_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "label": "Signups today",
    "type": "number",
    "expectedInterval": 300
  }'

Late is not broken

The naïve rule flags almost every healthy tile: stale the moment the interval elapses. A job that runs “every five minutes” drifts by a few seconds each run. It takes a moment to start, the API call takes a moment more, and by mid-afternoon the reading lands at 5:03 instead of 5:00. Under a strict rule that tile spends a few seconds accusing itself, every single cycle, forever.

So a tile gets a quarter of its interval as grace, with a floor of thirty seconds for the short intervals where a proportion would be meaningless. Five minutes becomes six and a quarter before anyone says anything. The wall is not a monitoring system and should not behave like one. It is trying to answer “can I trust this number?”, not “did the job run on time?”

What the room actually sees

The temptation is a red banner. We did not do that, for two reasons. The first is that a wall is furniture: an alarm that nobody can dismiss stops being an alarm within a day. The second is structural. The display page is exactly one screen, with nothing to scroll, so every element in a tile eats from a fixed height budget. Honesty had to cost zero pixels.

It gets two things, both free:

  • An age, in the label row. Right-aligned next to the tile's name, in amber: 3h ago. The label row already exists on every tile type, so nothing below it moves.
  • The reading fades. Down to 40%. Still visible, because it is still the last thing we knew, but no longer competing for attention with the tiles that are current. From across the room you read the fresh numbers first, which is the correct order.

That is the entire treatment. A person glancing up sees a dimmed tile with a small “3h ago” on it and knows, without reading a word of documentation, that this number is old and the others are not.

A stale status tile drops its story

One tile type needed more than dimming. A status tile shows red, amber or green with a short message: Deploy #482 green. Fading a green tile still leaves a green tile, and green is a claim about right now.

So a stale status tile falls back to unknown, the grey state, and drops its message along with its colour. Keeping the headline while greying the dot would have been the same Friday claim in a different font.

Waiting is not stale

A tile that has never been fed is not stale. It is waiting, and the wall already says so. The distinction sounds pedantic until you are the one acting on it: a waiting tile needs a first value pushed, while a stale tile was working and stopped, and pushing a value by hand hides the problem instead of fixing it. Two silences, two different repairs.

Which is also why staleness is reported to whatever is reading the board, not just drawn on it. When an agent reads a board back, it sees the same verdict the room sees:

What a reader gets back
{
  "label": "Signups today",
  "value": 128,
  "recordedAt": "2026-08-29T09:14:02+00:00",
  "expectedInterval": 300,
  "stale": true,
  "staleAfter": "2026-08-29T09:20:17+00:00"
}

Both fields, on purpose. stale answers a client that reads once and acts on the answer. staleAfter is a deadline: the reading's timestamp plus the interval plus its grace. A wall that stays open for days needs that one, because it has to go stale while nobody is touching it. It compares that deadline against its own clock every thirty seconds, so a tile can go quiet at 2am in an empty office and be visibly quiet by the time the first person walks in.

Sending only stale would have frozen the verdict at render time, which is useless for a page that is never reloaded. Sending only the rule would have put a second copy of the grace calculation in the browser, ready to drift out of step with the one on the server. A deadline is the thing both sides can agree on.

Pick the interval when you make the tile

It takes one dropdown and it is the field that decides whether the wall can be believed at four o'clock on a Friday. A wall people trust gets glanced at; a wall that has lied once gets ignored, and a metrics display nobody looks at is just an expensive screensaver.

Every plan has it, on every tile type. Create a free account, put a board on a screen, and tell each tile what to expect. Or read how the whole thing fits together first.

Put your numbers on the wall

Create a free account, put your first KPI on a screen, and upgrade when the wall fills up. No credit card required.