How to Configure the KPI Card Visualization

The KPI Card turns a report into a single, prominent number — with an optional trend, a comparison against another period, a target, and a status word that tells you at a glance whether the number is good news.

It is the least demanding visualization in DashboardFox. There is no schema to conform to, no required column names, no category values it expects to find. Point it at almost any report and it renders.

What your data does decide is how much of the card you get. This guide walks the whole sidebar, in the order it appears, and explains why some options are missing until your data can support them. It finishes with the part most people skip until a dashboard takes fifteen seconds to load: keeping a wall of KPI cards fast.


1. What your data lets the card do

Almost every question about KPI data comes down to one thing: does your report have a column that says when each row happened, and can DashboardFox read it?

That question puts you on one of three rungs.

Your period column

What the card can do

None

Show one number — a single cell, or a total across the report. Compare it against another column or another row. That's the whole card.

Period labels without a yearJanuary, Nov, Q3

A trend, and one comparison: the period immediately before. No year-over-year. No viewer period switching. No click-through to a date range.

Real dates, or labels with a year2026-03-15, Mar-26, Q3-2026

Everything. Eight comparison types, roll up from days to months to quarters to years, let viewers change the period on the fly, and click straight through to the exact date range behind the number.

The gap between rung two and rung three is one character: a year. Section 3 explains why.

Date formats the card understands

If your column holds real dates, you don't need to think about this. It's here for when dates arrive as text.

Format

Example

ISO date (recommended)

2026-03-15

ISO date with time

2026-03-15 14:22:00

ISO year and month

2026-03

Year alone

2026

Year and quarter

2026-Q1

Day-month-year, dotted

15.03.2026

Day-month-year, short month

15-Mar-2026

Month-day-year, written

Mar 15, 2026

Slashed dates

03/15/2026 (read according to your region's convention)

Use ISO (2026-03-15) whenever you have the choice. It is unambiguous everywhere in the world and never gets read as the wrong day.

Text period labels work too, as long as they carry a year: Mar-26, Mar-2026, March 2026, 3/2026, Q3-2026, Quarter 3-2026.

Two-digit years: 00 through 68 are read as the 2000s, 69 through 99 as the 1900s. Mar-26 is March 2026. If your data spans that boundary, write the full year.


2. Title, Display Type, and Value Column

The first three fields sit above everything else and apply to every card type.

KPI Title — the heading above the number. Leave it blank to show the value on its own. Type @ to insert a value from the report.

Select Display Type — choose Big Number / Trend. This guide covers that card.

Select Value Column — the column the card reads its number from. It must be typed as a number, or the card can't add it up. A column of 1200, 1450, 1600 stored as text will display but won't offer Sum or Average. If that happens, override the field's data type — see Formula fields.


3. Value Source

This is the most consequential choice on the card. It decides what the big number means, and it gates half the options below it.

Value Source

The number is

Needs a Period Column?

Single value (cell)

One cell of the report — pick a column and a row

No

Text, as-is

A cell shown exactly as written — a name, a status, a label

No

Latest period

The most recent period's figure

Yes

Total, all periods

Every row added up

Optional

Latest period is what most people want, and it's the only source that unlocks time-based comparisons, the runtime period switcher, and per-period goals.

When you pick a period-based source, four more fields appear.

Period Column

The column that says when each row happened. Only columns DashboardFox can read as dates or period labels appear here. If your date column isn't in the list, its values aren't consistently readable — see the pitfalls in section 13.

Group by

How rows are gathered into periods before the calculation runs. Daily rows grouped by Month give one figure per month.

Options: Day, Week, Month, Quarter, Year.

The rule only goes one way:

You can always roll up. You can never invent detail you don't have.

Daily rows can be grouped into months, quarters or years. Monthly rows can only go to quarters and years. Group by: Day on monthly data does nothing useful.

Weeks are a display choice, not a data grain. A column of 2026-W12 won't be recognized as a period column at all. You can display by week when the underlying data is daily.

Calculation

How the rows inside a period are combined into one number.

Options: Sum, Average, Min, Max, Count.

Week starts on

Only appears when Group by is Week. Monday (ISO-8601) or Sunday. Match whatever your business already uses; changing it later moves every bar in the trend.


4. Number Format and Value Color

Number Format decides how the value is written: None, Fixed point, Percent, Large number (1.2M), or Currency. Decimal places and currency symbol sit here.

Formatting is display only. It never changes the arithmetic.

Value Color is the color of the large number. Text values are colored too.


5. Comparison Options

A comparison adds a small change chip beside the value — ▲ +10.8% — and, in Detailed style, a labelled row of figures beneath it.

Source

What the value is being compared against. The options you see depend on your Value Source.

Source

Available when

Compares against

None

always

nothing

vs a period (time-based)

Value Source is Latest period, and there's a Period Column

an earlier period

vs another column

always

the same row, a different column

vs another row

Single value / Text

the same column, a different row

vs a delta column

Single value / Text

a column that already holds the change

Compare to

Only for the time-based source. This is the recipe — which earlier period.

Recipe

What it compares against

Needs

vs previous period

the period immediately before

any Period Column

Period-to-date vs prior

the same portion of the previous period

data finer than the displayed period

Same period last year

the same month/quarter last year

a year in the data

Year-over-year to-date

the same portion of last year

a year, and finer data

Week over week

the previous week

daily data

Same day last week

the same weekday last week

daily data

Same day last year

the same date last year

daily data and a year

Same week last month

the equivalent week last month

daily data

You will only be offered recipes your data can actually calculate. If Same period last year isn't there, your period labels have no year. If Period-to-date isn't there, your data isn't finer than what you're displaying.

If a recipe reaches past the end of your data, the card doesn't guess — the comparison simply doesn't render.

Measure from

The point in time the recipe counts back from.

  • Latest data point — the most recent period in the report. Use this when the report might lag.

  • Today's date — the real calendar date. Use this when a gap in the data should show as a gap.

Favorable

Higher is better or Lower is better. This colours the change chip green or red. Revenue is higher is better; churn, cost, and response time are lower is better. The card has no way to know which — set it.

Change as

How the change is expressed.

  • Auto — a percentage, unless the value is already a percentage, in which case percentage points.

  • Percent (%) · Percentage points (pp) · Multiple (x) · Absolute

Auto is right nearly always. The exception it exists for: a conversion rate that goes from 20% to 25% rose by 5 percentage points, not by 5%.

When prior is zero

Dividing by zero has no good answer, so you choose one.

Option

Shows

Show no value (—)

nothing — the honest default

Show ∞%

an infinity symbol

Show absolute change

the raw difference instead of a percentage

Use current value

the current number as the change

Style

  • Compact — a small change chip beside the value. The prior period goes in the caption.

  • Detailed — a labelled row beneath the value, with the prior figure and the change in columns.


6. Trend Options

Trend draws a small chart of the value over time: None, Line / area, or Bars.

It needs a Period Column. If Trend isn't offered, your Value Source isn't period-based, or the report has no readable date.

Dense data is grouped automatically. Two years of daily rows in a small tile is noise, so the card coarsens the drawn chart until the shape reads. Your figures are untouched.

  • Bar Color — only for Bars.

  • Show points on the line — a dot on each period.

  • Highlight high & low points — the best period turns green, the worst red.

The trend is never colored by whether the news is good. That's the change chip's job.


7. Status & Thresholds

This is where the card earns its place on a wall. A status label — a coloured word beside the change chip — tells you the number's condition without you having to read it.

Tick Show a status label based on value.

Measured as

What the thresholds are compared against.

Measured as

The thresholds mean

Needs a reference?

The value itself

literal numbers — Good at 100000

No

Percent of a reference

100 means the value equals the reference

Yes

Percent change from a reference

0 means no change

Yes

Standard deviations from average

how unusual this period is

No — uses the trend

Compare to

Only appears for the two percent options. What the value is measured against.

Compare to

Available when

A fixed number

always — type it into Reference

The goal

a goal is configured (section 8)

The prior period

a comparison is set up (section 5)

The average of all periods

there are at least three periods

If the reference cannot be worked out, no status word is shown. No goal set, a goal of zero, a missing prior period — the card shows nothing rather than a colour that means nothing. This is deliberate, and it's the behaviour that surprises people most.

Direction, Good at, Bad at

Direction — Higher is better, or Lower is better.

Good at and Bad at are the two cut points. Anything between them is Neutral. The units follow Measured as, and the labels change to remind you: Good at (%), Good at (σ).

Changing Measured as seeds sensible cut points into any field you've left blank — 100 / 90 for percent of, 0 / −10 for percent change, 2 / −2 for standard deviations. It never overwrites a number you've typed.

You can rename and recolour all three tiers.

Advanced: custom tiers

Three tiers not enough? Tick Advanced (custom tiers) and write your own as JSON.

[
{ "label": "Exceptional", "color": "#15803d", "match": { "op": "gte", "value": 120 } },
{ "label": "On Target", "color": "#22c55e", "match": { "op": "gte", "value": 100 } },
{ "label": "Near Target", "color": "#84cc16", "match": { "op": "gte", "value": 95 } },
{ "label": "Behind", "color": "#f59e0b", "match": { "op": "gte", "value": 80 } },
{ "label": "Critical", "color": "#991b1b", "match": { "op": "default" } }
]

The rules:

  • First match wins. Order matters. Put your highest band first.

  • Every tier needs a label and a match.

  • Operators: gt, gte, lt, lte, eq, between (with min and max, both inclusive), and default.

  • At most one default — it catches anything the others miss. Without one, a value matching nothing shows no status.

  • Colours are the text colour of the word.

The tiers are measured in whatever Measured as says. Paste the array above with Measured as: Percent of a reference and Compare to: The goal, and you have a five-band progress indicator against target.

The editor validates as you type and tells you what's wrong. If the JSON is invalid, no tiers are saved — the message under the box is your warning.

Flag unusual values

An independent alarm. Ticking it adds a ⚠ chip when the current value sits more than Sensitivity standard deviations from the average of the trend. Needs at least three periods.

This is separate from Standard deviations from average under Measured as. One flags an outlier; the other colours the status word. Use either, or both.


8. Goal Options

A target beneath the value, with an arrow showing which side of it you're on.

Pick a Goal Type:

Goal Type

The target is

Static value

a number you type — 3000000

Report value

a cell — pick a column and a row

Per period

a column, aggregated over the same period as the value

Per period is the one worth understanding. If your report has a budget column beside revenue, choose it as the Target Column and March's actuals will meet March's budget — not the year's. Switch the card to quarterly and the target follows. It only appears when the Value Source is period-based, because a per-period target against a single cell means nothing.

Heading is the word before the target. It defaults to Goal; type Target or Budget if you prefer. Prefix and suffix labels sit either side of the number.

DirectionHigher is good, Higher is bad, or None. This colours the arrow. The arrow character always points at where the value sits relative to the target; the colour says whether that's good news.

A goal of zero is a real goal, not a missing one — the card shows it and the arrow works. But "percent of target" against a target of zero has no meaning, so no status word appears.


9. Caption & Subtitle

Caption is a line of context under the value. It's the most under-used feature on the card.

Type @ and a picker appears. Choose a token; the card fills it in at run time.

Token

Becomes

{value}

the formatted value

{prior}

the comparison's prior figure

{delta}

the absolute change

{pct}

the percentage change

{currentPeriod}

the current period's label — Mar 2026

{priorPeriod}

the prior period's label

{periodRange}

the current period's date range

{count}

the number of rows behind the value

{goal}

the formatted target

{goalPct}

percent of target

{toGoal}

the distance to target

{col:Column Name}

any column's value from the first row

So vs {prior} in {priorPeriod} renders as vs $565,921 in Feb 2026, and {goalPct} of {goal} — {toGoal} to go renders as 82% of $3,000,000 — $540,000 to go.

Tokens that can't be resolved render as nothing. {goalPct} against a target of zero stays blank; {toGoal} still works, because subtraction survives a zero where division doesn't.

Subtitle is a plain line beneath, for context that never changes.


10. Interactivity

Drill-down

Set a Target Report and the card becomes clickable. Clicking the big number opens that report, filtered to the rows behind the number.

For a period-based card that means the exact date range of the period you clicked — click March, get March. Click a bar in the trend and you get that bar's period. Click the change chip and you get the prior period.

For a single-cell, text, or total card there's no date window to pass, so the target inherits the source report's own filters instead. That is still the right answer: the rows behind the number.

Map period to target date field tells the card which field in the target report to filter. The target must have the same underlying database date field for a date range to carry across.

If the trend is on, click-through on individual points can be enabled separately.

Viewer Controls

Let people who read the dashboard change what the card shows, without editing it. Nothing is saved — the card returns to your settings on refresh.

  • "Let viewers switch the period grain" — adds a small pill to the corner of the card. Use Periods offered to choose which options appear. Only periods at or coarser than your data are offered; the card can't invent daily detail from monthly rows.

  • "Let viewers switch comparison basis" — lets them flip between previous period and same period last year.

Neither appears for year-less period labels, because neither can be calculated.


11. Performance: keeping a dashboard of KPI cards fast

Everything above is about capability. This is about speed, and it's the part that decides whether your dashboard opens in one second or fifteen.

11.1 Why it matters

Every KPI tile runs its own report, and therefore its own database query.

The card does its arithmetic — the totals, the comparisons, the trend — on whatever rows the report hands back. So the cost of a card is the cost of its query and the size of its result.

Ten tiles, each pulling five years of transaction rows, is ten heavy queries every time anyone opens the dashboard. The card only displays one number. The database doesn't know that.

Three levers, cheapest first.

11.2 Constrain the dates

Most KPI cards answer a question about now. They rarely need every row ever recorded.

Add a criterion on your date field and use one of the predetermined ranges — Year to Date, Last 3 Months, Month to Date. Your data keeps growing; your query doesn't.

If you need year-over-year, you need this year and last year — nothing more. Two criteria on the same field:

order_date Is Year to Date
Or
order_date Is Last Year

Set the Logical Filter on the second criterion to Or. (The first criterion in a report is always AND; only later ones expose OR.) The report now returns two years instead of five, and Same period last year still works perfectly.

See Criteria and prompts.

11.3 Filter to the subset that matters

If the card is about open tickets, filter to open tickets.

status Is Open

Every row nobody is looking at is a row the database read, sent over the network, and the browser parsed, for nothing. This sounds obvious. It is routinely skipped, because the report was built for something else and then reused.

Anything that narrows the data to what the card is actually about is worth doing: a region, a product line, a status, an active flag.

Keep the filter column non-visible — see 11.6.

11.4 Aggregate when you don't need the fine detail

The biggest win, and the most under-used.

A card showing a monthly trend does not need 240,000 daily transaction rows. It needs 24 monthly totals. Do that aggregation once, in the report, instead of shipping every row to the browser.

  1. Add Formula on your date column to produce a period label. In the formula box type @, choose DateTime, and use Insert Report Field to drop in your date. Produce a value like 2026-03.

  2. Add Formula on your value column, choose Aggregate, and wrap it in Sum.

  3. Remove — or set non-visible — every other column that would split the rows apart.

Your report now returns one row per month. The card behaves identically and loads in a fraction of the time.

Keep the year in the period label. 2026-03 or Mar-2026, never March. A year-less label drops you to rung two of the ladder in section 1 and you lose year-over-year — the very comparison you were probably aggregating in order to afford.

See Report formulas and Data prep tools.

11.5 What aggregating costs you

You keep

You give up

Monthly, quarterly, yearly figures

Daily and weekly detail

Year-over-year and period-to-date

Viewer period switching below your chosen period

The trend chart

Click-through to an exact date range

Goals, thresholds, comparisons

That last one deserves a sentence. When you aggregate your dates into a text period column, click-through still works — it just carries the report's own filters rather than the exact period you clicked. If drilling into the rows behind a single month matters more than load time, keep the raw date column and constrain by date instead.

11.6 Don't let filter columns fragment your rows

The most common reason an aggregated report still comes back huge.

You aggregate to one row per month. Then you leave customer_name in the report because you want to filter on it. Now you have one row per month per customer, and you're back to thousands of rows.

A field can be used in criteria while being non-visible. Turn the column off. The filter still works. The rows stay collapsed.

Chart data shaping calls this the single biggest cause of messy data, and it's right. Dataset prep covers the Visible toggle.

11.7 When to stop fighting the report

If the shaping you need can't be expressed with criteria, formulas, and non-visible columns, stop.

That's the signal to move up a level: a database view or Direct SQL query, a stored procedure, surfaced through a Virtual App. Aggregating three million rows belongs in the database, which is built for it — not in a report that has to do it on every dashboard load.

The shaping belongs in the data.


12. Three worked examples

One number, no period

region

revenue

North

412000

South

388000

Value Source: Single value (cell) · Comparison Source: vs another row. A card showing North's revenue, with the change against South.

A trend and one comparison

month

revenue

January

310000

February

344000

March

366000

Value Source: Latest period · Comparison: vs previous period · Trend: Bars. "366,000 — up 6.4% on the period before." Add a year to month and everything in section 5 opens up.

The full card

order_date

revenue

budget

2026-01-14

12400

15000

2026-01-27

9800

15000

2026-02-03

15200

16000

Value Source: Latest period · Group by: Month · Calculation: Sum Comparison: vs a period → Same period last year Goal: Per period → budget Status: Measured as Percent of a reference, Compare to The goal, Good at 100, Bad at 90 Caption: {goalPct} of {goal} — {toGoal} to go Interactivity: Drill-down to a transaction report

March's revenue, against March last year, against March's budget, with a status word, a trend, and a click straight through to March's transactions.


13. Common pitfalls

Symptom

Cause

Fix

My date column isn't in the Period Column list

Its values aren't consistently readable as dates — mixed formats, too many blanks, or a date buried in free text

Clean the column, or build one consistent formula column

No Same period last year option

Your period labels have no year

MarchMar-2026

No Group by option

A year-less period column can't be rolled up

Add the year

No Trend option

Value Source isn't period-based, or the report has no readable date

Switch to Latest period

Dates read as the wrong day

03/04/2026 is ambiguous by region

Use ISO: 2026-03-04

My number column won't Sum

It's typed as text

Override the data type

Trend is a solid block of bars

Too many periods

Coarsen Group by, or aggregate the report

Status word never appears

The reference can't be resolved — no goal, a goal of zero, or no prior period

Check Compare to in Status & Thresholds

The status block vanished entirely

Invalid custom-tier JSON

Read the message under the box

Change chip is green when the news is bad

Favorable is wrong

Set Lower is better

A 20%→25% rise reads as +25%

Change as is Percent

Set Percentage points, or Auto

Click-through ignores the period I clicked

The period column is text, not a real date

Keep the raw date column and constrain by date

Dashboard takes forever to load

Every tile queries years of raw rows

Sections 11.2–11.4

I aggregated and the row count is still huge

A filter column is splitting the rows

Set it non-visible (11.6)


14. Checklist

Before you build a card

  • [ ] Does the report have a period column in one consistent format?

  • [ ] Do the period labels carry a year? (Mar-2026, not March)

  • [ ] Is the value column typed as a number?

  • [ ] For a per-period target, is the target column in the same report?

Before you configure it

  • [ ] Is Value Source right? Latest period unlocks comparisons, trends, and per-period goals.

  • [ ] Is Favorable set the right way round?

  • [ ] Does the status reference actually exist — a goal, a prior period, three periods of data?

Before you put six of them on a dashboard

  • [ ] Is every card constrained by date? (Year to Date, or Year to Date Or Last Year)

  • [ ] Is every card filtered to the subset it's about?

  • [ ] If you don't need daily detail, is the report aggregated to the period you display?

  • [ ] Are filter-only columns set non-visible?

The card will work without any of this. Your dashboard will be quicker with all of it.


Related