Address
Your page's canonical address is <your-slug>.realuptime.io, served at the root of that hostname. A new page starts on a random address; the first time you open its settings you are asked for a company or product name and offered a matching one instead. Change it any time from your status page's own settings, and the old address keeps working with a redirect to the new one.
For a shorter link to share during an incident, rlup.io/<your-slug> redirects straight to the same page.
What it shows
Top to bottom: your logo (or your page title when you have not set one) with Subscribe beside it, one banner with the overall status, your components, a legend, any scheduled maintenance, and the past fifteen days of incidents. The banner reads All Systems Operational, or names each open incident, colored by its impact: red for a major outage, orange for a partial outage, yellow for degraded performance, blue for maintenance. An open incident always outranks a green reading: the page never claims everything is fine while an unresolved incident is open.
Components and their bars
Each component shows its current status, then one bar per day for the history window (90 days on paid plans, 30 on Free), with that window's uptime under the bars. A day's bar takes the color of the worst incident on that component that day, blue when a maintenance window covered it, green when nothing happened, and grey for a day with no checks at all, such as before the component was added. Hover a bar for its date and level. Click a component to see the reading from each region it is checked from. Components you have grouped render under a group heading that collapses.
History archive
The bars on the page cover the most recent window, but the record behind them is kept indefinitely. The Uptime history link under past incidents opens the archive: a calendar of every year and month with data. Click a month to see each component's day-by-day status for that month, with every region's own row. The archive lives at /history on your status page's own address.
Components and incidents
Add components to your page from the dashboard to group related checks under one name a visitor recognizes, like "API" or "Website", rather than a list of raw check names. When something breaks, open an incident and post updates as you learn more: investigating, then identified, then monitoring, then resolved. Past incidents list every update in that order under the day the incident opened, with a link to its postmortem once you publish one. A scheduled maintenance window is not an incident and gets its own section, so planned work never reads as something going wrong.
One outage is one incident. A check probed from several regions that fails in more than one of them does not file an incident per region: the first region to confirm the failure opens the incident, every later region is added to it and posted on its timeline ("Also failing from Europe"), and your subscribers are emailed once. The card names every region affected and marks each one as it comes back, and the incident resolves only once every affected region has recovered.
Not every blip belongs in your public history. An automatically detected incident that recovers in under 5 minutes, with no update from a person and no postmortem, is treated as a blip: it does not appear in the incident history, and it does not color a bar or count toward uptime. Nothing is deleted. The blip still exists in your dashboard and in your team's Uplink view, and any incident someone opens by hand, edits, or writes a postmortem for is always shown, however short it was. An incident that is still open is always shown too.
Each incident also carries an impact level, matching the same three levels the Atlassian Statuspage convention uses: major outage, partial outage, and degraded performance. A major outage means every region your check is probed from failed at some point during the incident. A partial outage means only some of them did, so part of your service kept working for part of your audience. Degraded performance means the failures are explained by an upstream provider, described below. The card shows this as a labeled pill, and a fresh incident's title reflects it too, for example "Checkout API: partial outage in Australia" instead of a blanket "is down" when only one of several regions failed. A heartbeat monitor has no regions to compare, so it is always reported as a major outage.
Each component's uptime percentage follows the same convention: it is the share of the time window not spent in an incident, weighting a major outage as full downtime and a partial outage as 30% downtime, since part of your service was still reachable. Only days the component was actually checked count, so a component added last week is judged on last week. Degraded performance costs nothing toward uptime, because uptime measures whether the service answered, not how fast. When two incidents overlap on the same component, the overlap counts once, at whichever impact was worse during that overlap, never twice. Blips (see above) never reach this figure either, the same way they never reach the incident history.
Upstream provider incidents
When your service sits behind Cloudflare or Vercel, a problem at that provider's edge in one city looks, from our probe in that city, exactly like your service failing there. RealUptime tells the two apart only when both of these are true:
- Your check's own responses from that same region came through that provider (for example a
cf-rayorx-vercel-idheader), in the day before the failure or during it. Responses from other regions do not count, since a service can be fronted in one region and reach its origin directly in another. - The provider's own status page reported the edge location serving that region as under maintenance, re-routed, degraded, or under an open incident, for a period that overlaps the failure. The location is the one in the same city as our probe, or the one your responses named.
When both hold, the incident reads degraded performance and names the provider, for example "Upstream: Cloudflare São Paulo (GRU) maintenance", with a link to the provider's status page. It costs nothing toward your uptime figure. If only some of the failing regions are explained this way, the rest are judged exactly as before, so a failure elsewhere still reads as a partial or major outage. When either fact is missing, nothing changes. Alerts still go out for every one of these incidents, and the alert names the provider too.
Vendor components
A component can also mirror a third party your product depends on, picked from the Outages catalog (Stripe, GitHub, AWS and the rest). Its status is RealUptime's own probe reading of that vendor, the same one shown at /outages/<vendor>, mapped to operational, degraded, partial outage, major outage or "unknown (third-party)" when our probes hold no usable reading. The vendor's own status-page claim is shown beside it when we ingest that feed. On your page the row is labelled "Third-party, measured by RealUptime Outages" with a link to the vendor's outage page: it is never a measurement of your service. A vendor component never opens an incident on your page and stays out of your page-wide status by default; both the page-wide vote and the optional "email my subscribers when this vendor goes down" toggle are off until you turn them on. The REST API lists them as vendor_components on GET /status.
Provider components
A provider component shows one specific piece of Cloudflare or Vercel your service runs on, for example Cloudflare's São Paulo (GRU) edge or Cloudflare DNS, picked from the provider's own component list under Status page settings. Its state is the provider's own claim for that component, read from the provider's status page every five minutes: operational, degraded performance, partial outage, major outage, or under maintenance. On your page the row is labelled "Reported by Cloudflare, not measured", linked to the provider's status page. If we have not read the provider's status page in the last 20 minutes, or the provider stops listing the component, the row reads Unknown rather than keeping an old state.
Unlike a vendor component, which is RealUptime's probe of a vendor's public website, a provider component tracks exactly the piece you picked, so a problem at one Cloudflare city shows even while cloudflare.com loads fine. Provider components count toward your page-wide status: a provider outage, partial outage or degraded performance makes the page read degraded, never down, since it is the provider's claim about its own component and not a measurement of your service. Maintenance and Unknown do not change the page-wide status.
Custom domains
On Growth or Scale, serve your status page at your own hostname, like status.yourcompany.com, instead of a realuptime.io subdomain. From your status page's settings, enter the hostname, then add a CNAME record for it pointing to realuptime-web.fly.dev. RealUptime checks for the record and issues a certificate automatically once it finds it, which can take a few minutes to propagate. If your plan changes back to Free, the domain is disabled rather than removed: your certificate and DNS setup stay in place, so upgrading again restores it right away with nothing to reconfigure. See pricing for what each plan includes.
Subscribers
A visitor can subscribe to your status page with their email address, directly from the page. They receive an email when you open or resolve an incident, or post an update, and can unsubscribe at any time from a link in every email you never have to build yourself.
Scheduled maintenance sends its own three-email lifecycle: a "Scheduled maintenance" notice when you create the window, "Maintenance starting" the moment its start time arrives, and "Maintenance complete" once it ends, whether that is its scheduled end time or you ending it early. If you cancel a window before it happens, subscribers who were told about it get a "Maintenance cancelled" notice instead of the completion email.
Webhook and Slack subscriber channels
On Growth and above, a status page can also notify subscribers on a webhook endpoint or a Slack channel instead of, or alongside, email. Register a webhook from the status page's settings; we verify it with a signed GET challenge, a request to your URL with?challenge=<token>&signature=<hmac>, where the endpoint must echo the token back as the response body. Once verified, every incident open/update/resolve and maintenance scheduled/start/end event is delivered as an HMAC-SHA256-signed JSON POST (the same X-Realuptime-Signature header as an operator webhook). A Slack channel is added with an incoming-webhook URL and verified immediately with a test message; events arrive as Slack block messages. Both count against the account's subscriber allowance, and an endpoint that fails delivery repeatedly is disabled automatically.
Branding
Add your own logo from your status page's settings; it renders at the top of the public page. Every page carries a small "Powered by RealUptime" footer link unless your plan removes it.
Languages
Set a default language for a page's own chrome (status words, section headings, the subscribe form) from its settings: English, Spanish, German, French, Portuguese (Brazil), or Japanese. Content you write yourself (incident updates, component names, the page title, your description) is never translated; it always renders exactly as you typed it, in every language.
A visitor can also open /l/<code> on the page's own address (for example acme.realuptime.io/l/es) to read the page in a specific language regardless of its default, useful for a support link to a non-English-speaking customer.
RSS and Atom feeds
Every public status page publishes a feed of its incidents and scheduled maintenance at /feed.atom and /feed.xml (RSS 2.0) on the page's own address, so most feed readers pick it up automatically the moment you visit the page. A password-protected page has no feed, the same as it has no badge: both are read anonymously by software that cannot enter a password.
Calendar feed for scheduled maintenance
Every public status page also publishes an iCalendar feed of its scheduled maintenance at /maintenance.ics, on the page's own address, including a verified custom domain. Subscribing (rather than downloading) keeps a calendar app in sync as windows are added or moved: use the "Subscribe in your calendar" link on the public page, or copy the feed address from the dashboard's Maintenance tab. A password-protected page has no calendar feed, for the same reason it has no RSS/Atom feed or badge.
Incident banner for your own app
A one-tag script that shows a slim strip across your own app only while something is wrong on your status page: a component degraded or down, or an incident open. The rest of the time it renders nothing at all. The strip names the page and the incident, links to the status page, and can be dismissed per incident (the dismissal is remembered in the visitor's browser until a different incident opens). Copy the exact tag from your status page's settings under "Badge and embed"; it has this shape:
<script src="https://<your-slug>.realuptime.io/banner.js" async></script>The script has no dependencies, weighs about 9 KB, uses no eval, no inline event handlers and no external fonts or images, and reads exactly one thing: the page's public snapshot at /status.json on the same host it was loaded from. It polls that once a minute (never sooner than the JSON's own cache lifetime), backs off to ten minutes after failures, and stops polling while the tab is hidden. A password-protected page has no snapshot, so its banner never shows anything, for the same reason it has no badge and no feed. If you serve your status page on a custom domain, the same two paths work there too, so the tag can point at your own hostname instead.
Options
All optional, as attributes on the script tag:
data-position="top"(default) or"bottom".data-theme="auto"(default, follows the visitor's system setting),"light"or"dark".data-components="API, Website": a comma-separated list of component names. The banner then reacts only to those components (and to open incidents), ignoring the rest of the page.data-styles="none": do not inject a stylesheet; you ship the one below yourself.
Content Security Policy
If your app sends a CSP, allow the host the tag points at in both script-src (the script) and connect-src (the JSON it polls). Nothing else is needed, and no other host is ever contacted:
Content-Security-Policy: script-src 'self' https://<your-slug>.realuptime.io; connect-src 'self' https://<your-slug>.realuptime.ioThe script injects its styles as one <style> element. If your policy's style-src forbids that, either give the script tag a nonce (the script passes it on to the style element) or set data-styles="none" and include this stylesheet in your own CSS:
.ru-status-banner{position:fixed;left:0;right:0;z-index:2147483000;box-sizing:border-box;display:flex;align-items:center;flex-wrap:wrap;gap:8px 12px;margin:0;padding:10px 16px;font:14px/1.45 system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;color:#1a1523;background:#fff5e7;border:0;border-bottom:1px solid #a75c05;text-align:left}
.ru-status-banner[data-position='bottom']{bottom:0;border-bottom:0;border-top:1px solid #a75c05}
.ru-status-banner[data-position='top']{top:0}
.ru-status-banner[data-severity='down']{background:#fef2f2;border-color:#da2323}
.ru-status-banner *{box-sizing:border-box}
.ru-status-banner-dot{flex:none;width:10px;height:10px;border-radius:50%;background:#a75c05}
.ru-status-banner[data-severity='down'] .ru-status-banner-dot{background:#da2323}
.ru-status-banner-text{flex:1 1 200px;min-width:0;margin:0}
.ru-status-banner-name{font-weight:600}
.ru-status-banner-state{color:#a75c05;font-weight:600}
.ru-status-banner[data-severity='down'] .ru-status-banner-state{color:#da2323}
.ru-status-banner-link{color:inherit;text-decoration:underline;text-underline-offset:2px;margin-left:4px;white-space:nowrap}
.ru-status-banner-dismiss{flex:none;min-width:38px;min-height:38px;margin:-6px -8px -6px 0;padding:0;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;font-size:20px;line-height:1;cursor:pointer}
.ru-status-banner-dismiss:hover{background:rgba(0,0,0,.06)}
.ru-status-banner a:focus-visible,.ru-status-banner button:focus-visible{outline:2px solid #6d28d9;outline-offset:2px}
.ru-status-banner[data-theme='dark']{color:#f3f4f6;background:#302416;border-color:#fbbf24}
.ru-status-banner[data-theme='dark'][data-severity='down']{background:#2a1416;border-color:#f87171}
.ru-status-banner[data-theme='dark'] .ru-status-banner-dot{background-color:#fbbf24}
.ru-status-banner[data-theme='dark'] .ru-status-banner-state{color:#fbbf24}
.ru-status-banner[data-theme='dark'][data-severity='down'] .ru-status-banner-dot{background-color:#f87171}
.ru-status-banner[data-theme='dark'][data-severity='down'] .ru-status-banner-state{color:#f87171}
.ru-status-banner[data-theme='dark'] .ru-status-banner-dismiss:hover{background:rgba(255,255,255,.1)}
.ru-status-banner[data-theme='dark'] a:focus-visible,.ru-status-banner[data-theme='dark'] button:focus-visible{outline-color:#b298f7}
@media (prefers-color-scheme:dark){
.ru-status-banner[data-theme='auto']{color:#f3f4f6;background:#302416;border-color:#fbbf24}
.ru-status-banner[data-theme='auto'][data-severity='down']{background:#2a1416;border-color:#f87171}
.ru-status-banner[data-theme='auto'] .ru-status-banner-dot{background-color:#fbbf24}
.ru-status-banner[data-theme='auto'] .ru-status-banner-state{color:#fbbf24}
.ru-status-banner[data-theme='auto'][data-severity='down'] .ru-status-banner-dot{background-color:#f87171}
.ru-status-banner[data-theme='auto'][data-severity='down'] .ru-status-banner-state{color:#f87171}
.ru-status-banner[data-theme='auto'] .ru-status-banner-dismiss:hover{background:rgba(255,255,255,.1)}
.ru-status-banner[data-theme='auto'] a:focus-visible,.ru-status-banner[data-theme='auto'] button:focus-visible{outline-color:#b298f7}
}
@media (max-width:480px){.ru-status-banner{padding:8px 12px;gap:6px 10px}.ru-status-banner-link{margin-left:0}}The JSON
/status.json is the same snapshot the page's static mirror publishes: overallStatus, a components array with a status per component, activeIncidents, the stamps and a version field. It is public, cacheable for 30 seconds and readable cross-origin, so you can build on it directly if the banner's look is not yours.