# SmartVisuals Last Refresh & Data Freshness for Power BI

> Free Power BI visual for last refresh time and status, data coverage and freshness, shown in each reader's own time zone. Business time, schedules, many sources.

- Page: https://www.smartvisuals.io/visuals/data-freshness
- Fields and settings: https://www.smartvisuals.io/visuals/data-freshness/settings
- Microsoft Marketplace: https://marketplace.microsoft.com/en-us/product/smartvisuals.smartvisuals-data-freshness?tab=overview
- Package: https://www.smartvisuals.io/downloads/smartvisuals-data-freshness-1.0.0.0.pbiviz
- Sample report (zipped .pbip): https://www.smartvisuals.io/samples/smartvisuals-data-freshness-sample-1.0.0.0.zip
- Price: Free, every feature, no licence.
- Certified by Microsoft: no
- Version: 1.0.0.0
- GUID (visualType and publicCustomVisuals): `dataFreshness4BAAAB2339CF41DABFC1E0BFB560FA50`

## What is free

- **Your time zone, not the server's**: Store the refresh time in UTC and each reader sees it in their own zone, daylight saving included, with the zone named in their language.
- **Three inputs, all tested**: Refreshed At, Data Through and Last Status: a refresh that loaded nothing is stale, and a failed run marks the source stale with the reason printed.
- **States you can read without colour**: Fresh, Ageing, Stale and Unknown, each with its own icon shape and word.
- **Business time and the refresh schedule**: Working days, working hours and holidays count by default; type your schedule and the visual knows when a run is late and when the next is due.
- **Many sources**: Bind a load log and every source gets its own state, reason, status and thresholds, from the format pane or from your data; click or press Enter on a source to cross-filter the report.
- **Five layouts**: Badge, header strip, corner chip, status card and source list, or Auto; one-line layouts shed parts instead of cutting text.
- **Guards against mistakes**: A time or data date in the future, or an unreadable value, is flagged and never shown as fresh; a zone abbreviation without daylight saving is refused with a hint.

## Fields

| Field | Internal name | Takes | Needed | What it is for |
| --- | --- | --- | --- | --- |
| Refreshed At | `refreshed` | Measure | Optional | When the data was last refreshed. Recipe: a one-row Power Query table with DateTimeZone.RemoveZone(DateTimeZone.UtcNow()), then MAX of it. Read as UTC by default (Time Zones card). |
| Data Through | `through` | Measure | Optional | The last date the data covers, e.g. CALCULATE(MAX(Sales[Order Date]), REMOVEFILTERS()). Tested against the expected lag. |
| Source | `source` | Column | Optional | Optional: one row per source or table (a load log, dataflows). Shows a list with a state per source. |
| Source Detail | `detail` | Column | Optional | Optional text under each source name: owner, system, schedule. |
| Last Status | `status` | Measure | Optional | Optional: the outcome of the last refresh run, as text (Succeeded, Failed, Cancelled) or a numeric code (Last Status card). Shown next to the refresh time; a failed run marks the source stale by default. |
| Next Refresh | `next` | Measure | Optional | Optional: the next scheduled refresh, when your data knows it. Wins over the Refresh Schedule card. |
| Ageing After (Hours) | `ageingAfter` | Measure | Optional | Optional per-source threshold from your data; wins over the format pane. |
| Stale After (Hours) | `staleAfter` | Measure | Optional | Optional per-source threshold from your data; wins over the format pane. |
| Tooltips | `tooltips` | Measure | Optional, up to 5 | Extra measures shown in the tooltip. |

## Format pane

Each card is a key under `visual.objects` in a PBIR visual.json; each setting is a property of it. Toggles take `true`/`false`, choices and text a value in single quotes (`'auto'`), numbers a `D` suffix (`12D`).

### Theme (`theme`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Theme | `selectedTheme` | `smartvisuals` (SmartVisuals), `dark` (Dark), `clean` (Clean), `slate` (Slate) |
| Transparent Background | `transparentBg` | On / off |

### Layout (`layout`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Layout | `layout` | `auto` (Auto (fit the space)), `badge` (Badge), `strip` (Header strip), `chip` (Corner chip), `card` (Status card), `list` (Source list) |
| Alignment | `align` | `auto` (Auto), `left` (Left), `center` (Center), `right` (Right) |
| Chip Position | `chipCorner` | `topRight` (Top right), `topLeft` (Top left), `bottomRight` (Bottom right), `bottomLeft` (Bottom left), `center` (Center) |
| Source Order | `order` | `worst` (Worst first), `data` (As in the data) |
| Shape | `shape` | `theme` (From the theme), `pill` (Pill), `rounded` (Rounded), `square` (Square) |
| Font | `font` | `theme` (From the theme (Inter / Segoe UI)), `segoe` (Segoe UI), `arial` (Arial), `georgia` (Georgia), `mono` (Monospace) |
| Text Size (px, 0 = Fit) | `textSize` | Number |
| Headline Size (%) | `headlineSize` | Number |
| Secondary Text Size (%) | `secondarySize` | Number |

### Show (`content`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| State Icon | `icon` | On / off |
| State Word | `stateWord` | On / off |
| Relative Age (2 hours ago) | `relative` | On / off |
| Refresh Time (today 06:04) | `absolute` | On / off |
| Last Status (Succeeded / Failed) | `status` | On / off |
| Time Zone Name (CEST) | `zoneName` | On / off |
| Data Through | `through` | On / off |
| Next Refresh | `next` | On / off |
| Reason When Not Fresh | `reason` | On / off |
| Summary Line (Source List) | `summary` | On / off |
| Column Headers (Source List) | `headers` | On / off |
| Age Bar (Status Card) | `ageBar` | On / off |
| UTC Time (Status Card) | `utcRow` | On / off |
| Business-Time Age (Status Card) | `businessAge` | On / off |
| As-Of Stamp | `asOf` | `auto` (In exports and snapshots), `always` (Always), `never` (Never) |

### Time Zones (`time`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Refresh Time Is Stored As | `storedAs` | `utc` (UTC (recommended recipe)), `viewer` (The viewer's time zone), `zone` (A time zone or offset (type below)) |
| Stored Time Zone | `storedZone` | Text |
| Show Times In | `displayZone` | `viewer` (The viewer's own time zone), `utc` (UTC), `business` (The business time zone) |
| Business Time Zone | `businessZone` | Text |
| Clock | `clock` | `auto` (From the report language), `24` (24-hour (18:30)), `12` (12-hour (6:30 PM)) |
| Relative Wording | `relStyle` | `long` (Long (2 hours ago)), `short` (Short (2 hr. ago)), `narrow` (Narrow (2h ago)) |
| Keep Ageing While Open | `live` | On / off |

### Refresh Age (`staleness`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Ageing After (Hours, 0 = Off) | `ageingHours` | Number |
| Stale After (Hours, 0 = Off) | `staleHours` | Number |
| Count Age In | `countIn` | `business` (Business time (working days and hours)), `calendar` (Calendar time) |

### Data Coverage (`coverage`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Expected Lag (Days) | `expectedLag` | Number |
| Ageing When Behind By (Days, 0 = Off) | `ageingDays` | Number |
| Stale When Behind By (Days, 0 = Off) | `staleDays` | Number |
| Count Missing Days In | `countIn` | `business` (Working days), `calendar` (Calendar days) |
| Date Format | `dateStyle` | `auto` (Auto (yesterday, Fri 26 Sep)), `short` (Short (26/09/2026)), `medium` (Medium (26 Sep 2026)), `long` (Long (26 September 2026)), `iso` (ISO (2026-09-26)) |
| Label | `label` | `words` (Data through), `field` (The measure's name (Sales through)) |

### Refresh Schedule (`schedule`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Scheduled Times (06:00, 12:30) | `times` | Text |
| Runs On | `days` | `workdays` (Working days), `every` (Every day) |
| Late After (Minutes) | `graceMinutes` | Number |
| Show Next Refresh As Approximate (~) | `approx` | On / off |

### Last Status (`lastStatus`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Numeric Status Codes | `codes` | `exit` (0 = succeeded, other = failed (exit codes)), `sqlAgent` (SQL Agent (1 succeeded, 0 failed, 4 running)), `http` (HTTP (2xx succeeded, 4xx/5xx failed)) |
| A Failed Last Run Makes the Source | `onFailure` | `stale` (Stale), `ageing` (Ageing), `none` (No change (show the status only)) |

### Business Calendar (`calendar`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Weekend | `weekend` | `satSun` (Saturday and Sunday), `friSat` (Friday and Saturday), `sun` (Sunday only), `none` (No weekend) |
| Working Hours (08:00-18:00, Empty = Whole Day) | `hours` | Text |
| Holidays (YYYY-MM-DD, Comma Separated) | `holidays` | Text |

### Text (`wording`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Refreshed Label | `refreshed` | Text |
| Data Through Label | `through` | Text |
| Next Refresh Label | `next` | Text |
| Last Status Label | `status` | Text |
| Source Column Label | `source` | Text |
| State Column Label | `stateCol` | Text |
| Your Time Label | `yourTime` | Text |
| Fresh Word | `fresh` | Text |
| Ageing Word | `ageing` | Text |
| Stale Word | `stale` | Text |
| Unknown Word | `unknown` | Text |

### Colors (`colors`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Background | `background` | Colour |
| Badge / Card Fill | `surface` | Colour |
| Border | `border` | Colour |
| Text | `text` | Colour |
| Secondary Text | `muted` | Colour |
| Accent and Rules | `accent` | Colour |
| Fresh | `fresh` | Colour |
| Ageing | `ageing` | Colour |
| Stale | `stale` | Colour |
| Unknown | `unknown` | Colour |

### Sources (`sources`)

| Setting | Internal name | Type or options |
| --- | --- | --- |
| Display Name | `label` | Text |
| Ageing After (Hours, 0 = Default) | `ageingHours` | Number |
| Stale After (Hours, 0 = Default) | `staleHours` | Number |
