Better Status PageDocs

Customizing the status page

The public status page is built from three admin pages: Page Builder decides what is on the page and where, Branding decides how it looks, and Localization decides which languages visitors can read it in. This guide covers all three, plus dark mode and live updates.

Admin pageWhat it controls
Page BuilderMonitors, groups, charts, text, dividers and the incident feed, on a three-column grid
BrandingSite name, logo, layout switches, uptime bar thresholds, colours and custom CSS
LocalizationLanguages, the default language and every piece of text on the public page

All three are open to the admin, operator and branding roles. See Who can change this.


Page Builder

Admin → Page Builder

The left side is the Toolbox, the right side is the canvas. Drag an item from the toolbox onto the canvas, or press its + button to add it below everything else on the page.

The canvas is a grid three columns wide. Move a block by its handle (⠿) and resize it horizontally by its right edge, from one to three columns. Heights are fixed: monitors, charts, dividers and the incident feed always take one row, a group grows with the number of items in it, and a text block grows with its content.

Click a block to select it. Its settings appear under Properties in the left panel.

Blocks

Toolbox itemWhat it shows on the pageProperties
New groupA titled card that holds monitors and text blocksGroup name, Collapsible, Add monitor to group
Monitors (one entry per monitor)A status card for that monitorMonitor, Card type, Uptime bar, Uptime bar position, Show uptime %, Show monitor type
TextA Markdown blockName (only shown in the builder), Text (Markdown)
DividerA horizontal lineNone
IncidentsIncident cardsIncident limit (1–20, default 5), Filter: all, active only or resolved only
Charts (one entry per monitor)A response-time chart for that monitorSee below

Monitor cards. Card type is Full (default) or Compact. A full card has a 30-day uptime bar that you can switch off or place to the Right of the name (default) or Below it. With the bar below, Show uptime % adds the uptime percentage. A compact card is a single row without the uptime bar. Show monitor type adds the monitor type to either kind.

Charts are only offered for HTTPS, Ping, database (SQL Server, PostgreSQL, MySQL / MariaDB, MongoDB) and Docker monitors, because the other types have no response time. A chart has:

  • Title (optional): leave it empty to use the monitor name.
  • Time range: last 1, 3, 6, 12 or 24 hours, 2, 7, 30 or 90 days. Default: 24 hours.
  • Data points: 20, 30 (default) or 50.
  • Aggregation: AVG (default), P95 or MAX per data point.
  • Chart height: S, M (default) or L.
  • Fill area under line (on by default), Show uptime % and Show monitor type. The uptime percentage covers the chart’s time range in whole UTC days (at least 1 day).

Text blocks take Markdown: headings, paragraphs, lists, links. Raw HTML is not rendered.

Groups

A group holds monitors and text blocks only. To fill a group:

  • drag a monitor or a Text item from the toolbox onto the group,
  • drag a monitor or text block that is already on the canvas onto the group, or
  • select the group and pick monitors under Add monitor to group.

Inside a group, drag items by their handle to reorder them. Drag an item out of the group and drop it on the canvas to ungroup it. The × next to an item removes it from the group.

On the public page, a Collapsible group (the default) has a header visitors can click to fold it.

Deleting a group that still holds items asks for confirmation, because its items are deleted with it.

Which monitors appear

Only monitors you place on the page, as a card or a chart, are public. Every other monitor stays internal: the public API, the live event stream and the incident feed do not mention its name, status or history. An incident linked to both public and internal monitors shows only the public ones.

The overall status headline at the top of the page is calculated from the monitors on the page. Active incidents count towards it only when the page has an Incidents block.

A page with nothing on it tells visitors This page has not been configured yet.

When a monitor is deleted, it disappears from the public page at once. The next time you open Page Builder, its blocks are removed from the canvas and the layout is marked Unsaved so you can save the cleaned-up version.

Saving

There is no draft: Save publishes the layout immediately. The button is only active when there are unsaved changes, and the header shows Unsaved until you save. Every save is written to the audit log as Status Page Layout.

The builder shows the structure of the page, not the finished look. To see the real page, open it, or use the live preview in Branding, which renders the saved layout.

On phones (narrower than 768 px) the page drops the grid and stacks every block in a single column, in order from top to bottom and left to right.


Branding

Admin → Branding

The left panel holds the settings, the right side is a Live preview of the public page: the saved Page Builder layout with your unsaved branding changes. Nothing reaches visitors until you click Save branding. Every change is written to the audit log.

Branding has two modes, switched by Custom branding:

Custom branding off (default)Custom branding on
ColoursBuilt-in paletteYour 14 colours
Dark modeVisitors can switch between light and darkOne universal theme in your colours, so no light/dark toggle
Image logoLight mode logo and Dark mode logoOne Universal logo
Custom CSSNot appliedApplied

Site name, logo text, layout switches and uptime bar thresholds apply in both modes.

Identity

  • Site name: used as the browser tab title, under the logo in the footer and as the logo’s alt text. Default: Status Page. It does not replace the logo.
  • Logo: choose Image or Text.
    • Image: upload JPEG, PNG, GIF or WebP, up to 5 MB. The file type is checked from the file’s contents, not its name. With custom branding off you upload a light and a dark variant, and the page shows the one that matches the visitor’s mode; with it on, one universal logo. The header shows it up to 40 px high and 200 px wide. Without an uploaded logo, the page shows the BetterStatusPage logo. The × next to a logo removes it.
    • Text: up to 40 characters, set in the heading font in the header and footer.

The uploaded logo is also used in subscriber emails: the universal logo with custom branding on, the light mode logo otherwise. Without one, emails show the site name as text.

Layout

SwitchWhat it hides when off
Page headerThe overall status headline and the monitor count at the top of the page. The top bar with the logo stays.
FooterThe logo and site name at the bottom of the page
BetterStatusPage linkThe small project link in the bottom-right corner

All three are on by default.

Uptime bar

The colour of each day of the 30-day uptime bar comes from the share of successful checks that day:

ColourDefault
Operational≥ 99.9 %
Degraded≥ 99 %
Partial outage≥ 95 %
Downbelow the partial outage value

The values apply to every monitor, with or without custom branding. They must be between 0 and 100 and strictly descending, otherwise Save branding stays disabled. Failures that have not reached a monitor’s failure threshold do not count; see Alert hygiene.

Colours

With Custom branding on, you can set 14 colours. Each takes a hex value such as #22c55e, or rgb() / rgba(); anything else is rejected.

SectionFieldDefaultCSS variable
BackgroundsPage background#faf8ff--bsp-bg
Cards and groups#f2f3ff--bsp-card-bg
Elevated elements and tooltips#e2e7ff--bsp-elevated-bg
Charts#f2f3ff--bsp-chart-bg
Borders and chartsBorders#c6c6cd--bsp-card-border
Chart grid lines#c6c6cd--bsp-chart-grid
TextPrimary text#131b2e--bsp-text
Secondary text#505f76--bsp-text-muted
Status colorsOperational#22c55e--bsp-up
Down#ba1a1a--bsp-down
Degraded#eab308--bsp-degraded
Partial outage (uptime bar)#f97316--bsp-partial
AccentPrimary color and chart line#000000--bsp-primary
Accent color#497cff--bsp-accent

Status text (as opposed to dots and bars) is mixed towards the primary text colour so it stays readable.

Custom CSS

With Custom branding on, Open CSS editor opens a full-screen editor. Changes show in the live preview as you type; Save branding applies them. The CSS is added to the public page and to the private page’s sign-in screen as written, with no sanitising, so only give the branding role to people you trust with the page’s appearance.

Use these classes to target parts of the page:

ClassElement
.bsp-pageEntire public status page
.bsp-headerSticky page header
.bsp-navigationHeader navigation content
.bsp-contentMain page content
.bsp-status-bannerOverall status badge
.bsp-maintenance-bannerMaintenance notice
.bsp-monitor-cardMonitor card
.bsp-monitor-nameMonitor name
.bsp-group-cardMonitor group
.bsp-group-labelGroup name
.bsp-chart-cardChart card and its background
.bsp-chartChart content
.bsp-chart-tooltipChart hover tooltip
.bsp-text-blockPage Builder markdown block
.bsp-dividerPage Builder divider
.bsp-incidents-sectionSystem events section
.bsp-incident-cardIncident card or history row
.bsp-footerPage footer
.bsp-project-linkBetterStatusPage link

The colour variables in the table above hold the current palette, for example:

.bsp-monitor-card {
  border-radius: 8px;
  border-color: var(--bsp-accent);
}

The page’s Content Security Policy limits what CSS can load: images only from the page’s own origin or data: URLs, and fonts only from the page itself or Google Fonts.


Dark mode

With Custom branding off, the public page has a light and a dark appearance. On the first visit it follows the visitor’s operating system setting. The sun/moon button in the header switches it, and the choice is remembered in that browser.

With Custom branding on, the page uses one universal theme built from your colours, so there is nothing to switch and the toggle is not shown.


Localization

Admin → Localization

Translations cover the public status page, including the subscribe dialog and the private page’s sign-in screen. The admin console is English only.

Languages

A new instance has one language, English (en), which is the default. Built-in copy ships for two languages:

CodeBuilt-in copy
enEnglish, complete
plPolish, complete

To add a language, click Add Language, enter a Code and a Name, then Create Language. The code is lowercase letters with an optional region, for example de, fr or pt-br. The name is what visitors see in the language menu, so write it in that language (Deutsch, Polski).

Adding pl (or pl-pl) gives you the full Polish page straight away. Any other new language starts out showing English until you translate it.

Translating

Select a language to see every text key on the public page, grouped as Status Labels, Overall Page Status, Page Copy, Empty States, Uptime Bars & Tooltips, Incidents, Response Time Chart, Subscriptions and Private Page Sign-in. Each field shows the text it falls back to as a placeholder. Type a translation and click Save Changes.

Some strings contain placeholders such as {n} or {date}. Keep them in your translation; they are replaced with numbers and dates on the page.

A key without a translation (or with a cleared field) falls back, in this order, to:

  1. the language’s built-in copy, if it has one (pl, pl-pl, … use the Polish copy),
  2. English,
  3. the key name itself.

Default language and the visitor’s choice

Set as Default makes a language the one new visitors see. Only one language is the default, and the default cannot be deleted.

When there is more than one language, the header shows a language menu. A visitor’s choice is remembered in their browser and wins over the default. If the chosen language is later deleted, they get the default again. The page does not read the browser’s language setting.

Deleting a language removes its translations. Adding, renaming, translating, deleting and changing the default are written to the audit log.


Live updates

The public page keeps a Server-Sent Events connection to /api/v1/public/events. When a monitor on the page changes status, its card updates without a reload. When an incident is created or updated, the page reloads its status and incident data. Status changes of monitors that are not on the page are not sent.

If the connection drops, the page reconnects after two seconds. The server sends a keep-alive message every 30 seconds. As a fallback, the page also reloads its status every five minutes.

Layout and branding changes are not pushed. Visitors with the page open get them when the page next loads its data, for example on reload.

A reverse proxy must not buffer the event stream. The server sends X-Accel-Buffering: no; set the proxy options in Nginx reverse proxy as well, so updates arrive at once and long-lived connections are not cut.


Who can change this

RolePage BuilderBrandingLocalization
adminYesYesYes
operatorYesYesYes
brandingYesYesYes
viewerNoNoNo

The branding role is meant for people who look after the page’s appearance without touching monitoring. In the builder they see each monitor’s name and type, enough to place it, but not its configuration; the Monitors, Incidents and Notifications pages are not available to them. See Users and roles.


API

All endpoints are under /api/v1/admin and need one of the roles above.

EndpointPurpose
GET / PUT /layoutRead or replace the layout tree ({ "tree": … })
GET /layout/monitorsMonitor id, name and type, for placing monitors
GET / PATCH /brandingRead or update branding; omitted fields are left unchanged
POST /branding/logo, /logo/light, /logo/darkUpload the universal, light or dark logo (multipart, field file)
GET / POST /localesList languages, or add one ({ "code": "de", "name": "Deutsch" })
GET / PATCH / DELETE /locales/:codeRead, update (name, translations) or delete a language
POST /locales/:code/set-defaultMake a language the default

PATCH /branding takes the layout switches (showHero, showFooter, showProjectLink) and enabled (custom branding) as 0 or 1.