Skip to main content
Sabo includes a pre-built status badge widget that displays real-time system status from Better Stack directly in your application’s footer. This provides transparency to users about service availability and ongoing incidents.

Overview

A status page is a dedicated public page that shows the operational status of your services. It’s essential for:
  • Building trust - Show users you’re transparent about service health
  • Reducing support tickets - Users check status before contacting support
  • Professional image - Demonstrates operational maturity
  • Incident communication - Keep users informed during outages
Sabo’s implementation features:
  • Real-time status badge embedded in footer
  • Automatic theme matching (light/dark mode)
  • Hosted status page at your custom domain (e.g., status.yourdomain.com)
  • Historical uptime data with visual graphs
  • Powered by Better Stack - Industry-leading status page provider
Better Stack (formerly Checkly) provides enterprise-grade uptime monitoring and status pages. Their free tier includes everything you need to get started.
Need a deeper tour of Better Stack’s capabilities (monitors, incidents, alerting)? Keep their official Uptime documentation open while you work through this guide.

Quick Start

1

Create Better Stack account

Sign up for a free Better Stack account to get started.
  1. Visit Better Stack
  2. Create a free account (no credit card required)
  3. You’ll be redirected to the dashboard
Better Stack’s free tier includes 10 monitors and a branded status page - perfect for most projects.
2

Create your status page

Set up a public status page for your services.
  1. In Better Stack dashboard, go to Status Pages
  2. Click Create Status Page
  3. Configure:
    • Name: Your company/product name (e.g., “Acme”)
    • Subdomain: Choose a subdomain (e.g., acmeacme.betteruptime.com)
    • Custom domain (optional): status.yourdomain.com
  4. Click Create
Custom domains are available on all plans. Set up a CNAME record pointing to Better Stack to use your own domain.
3

Add monitors

Create monitors for the services you want to track.
  1. Go to MonitorsAdd Monitor
  2. Configure your first monitor:
    • Monitor Type: HTTP(S)
    • URL: Your main site (e.g., https://yourdomain.com)
    • Name: “Main Website”
    • Check Frequency: Every 1 minute (free tier)
  3. Click Create Monitor
Repeat for other services (e.g., demo site, docs, API):
  • https://demo.yourdomain.com → “Demo Site”
  • https://docs.yourdomain.com → “Documentation”
  • https://api.yourdomain.com → “API”
Each monitor will appear on your status page with real-time status and uptime history.
4

Get your status badge URL

Copy the embeddable badge URL for your status page.
  1. Go to Status Pages → Your status page
  2. Click SettingsBadge
  3. Copy the badge URL (format: https://your-subdomain.betteruptime.com/badge)
Example:
https://acme.betteruptime.com/badge
You’ll use this URL in the next step to configure Sabo’s status badge widget.
5

Update status badge URL in Sabo

Configure Sabo to display your status badge.Open src/components/shared/status-badge.tsx and update line 29 with your badge URL:
src/components/shared/status-badge.tsx
return (
  <iframe
    src={`https://your-subdomain.betteruptime.com/badge?theme=${badgeTheme}`}
    width="185"
    height="30"
    frameBorder="0"
    scrolling="no"
    style={{ colorScheme: "none" }}
    title="System Status"
  />
);
Replace your-subdomain with your actual Better Stack subdomain.
Keep the ?theme=${badgeTheme} parameter! This ensures the badge matches your site’s light/dark mode.
6

Verify integration

Check that the status badge appears in your footer.
  1. Restart your dev server: pnpm dev
  2. Visit http://localhost:3000
  3. Scroll to footer
  4. You should see the status badge next to the theme toggle
Expected appearance:
  • Light mode: Badge with light background
  • Dark mode: Badge with dark background
  • Status text: “All services operational” (or current status)
The badge updates automatically every 60 seconds to reflect current status.

How It Works

Status Badge Component

Sabo’s status badge is implemented in src/components/shared/status-badge.tsx:
src/components/shared/status-badge.tsx
"use client";
"use no memo";

import { useTheme } from "next-themes";
import { useEffect, useState, startTransition } from "react";

export function StatusBadge() {
  const { resolvedTheme } = useTheme();
  const [mounted, setMounted] = useState(false);

  // Only render after mounting to avoid hydration mismatch
  useEffect(() => {
    startTransition(() => {
      setMounted(true);
    });
  }, []);

  // Use resolvedTheme which handles system theme automatically
  const badgeTheme = resolvedTheme === "dark" ? "dark" : "light";

  // Return placeholder during SSR and initial render
  if (!mounted) {
    return <div className="h-[30px] w-[185px]" />;
  }

  return (
    <iframe
      src={`https://status.getsabo.com/badge?theme=${badgeTheme}`}
      width="185"
      height="30"
      frameBorder="0"
      scrolling="no"
      style={{ colorScheme: "none" }}
      title="System Status"
    />
  );
}

Key Features

The badge automatically matches your site’s theme using next-themes:
const badgeTheme = resolvedTheme === "dark" ? "dark" : "light";
How it works:
  1. useTheme() hook detects current theme
  2. resolvedTheme returns “dark” or “light” (handles system preference)
  3. Badge URL includes ?theme= parameter
  4. Better Stack serves appropriate badge design
Supported themes:
  • light - Light background, dark text
  • dark - Dark background, light text
The component uses careful client-side rendering to avoid React hydration errors:
const [mounted, setMounted] = useState(false);

useEffect(() => {
  startTransition(() => {
    setMounted(true);
  });
}, []);

if (!mounted) {
  return <div className="h-[30px] w-[185px]" />;
}
Why this matters:
  • Server renders a placeholder <div> (same dimensions as badge)
  • Client renders the actual iframe after hydration
  • Prevents “Expected server HTML to contain…” errors
  • Uses startTransition for smoother rendering
This pattern is recommended for all components that depend on next-themes. See Next.js hydration docs.
The badge uses an iframe for security and isolation:
<iframe
  src={`https://status.getsabo.com/badge?theme=${badgeTheme}`}
  width="185"
  height="30"
  frameBorder="0"
  scrolling="no"
  style={{ colorScheme: "none" }}
  title="System Status"
/>
Security benefits:
  • Sandboxed execution: Badge cannot access your site’s cookies or data
  • CSP friendly: Content Security Policy compatible
  • No JavaScript required: Pure iframe embed
  • Automatic updates: Better Stack updates badge without code changes
Accessibility:
  • title attribute provides screen reader context
  • Fixed dimensions prevent layout shift
  • No scrolling (compact design)

Better Stack Setup

Creating Monitors

Monitors check your services at regular intervals and update status automatically.
  • Website Monitor
  • API Monitor
  • Database Monitor
Monitor your main website’s availability.Configuration:
Monitor Type: HTTP(S)
URL: https://yourdomain.com
Name: Main Website
Check Frequency: Every 1 minute
Expected Status Code: 200
Timeout: 30 seconds
Regions: Multi-region (automatic)
What it checks:
  • HTTP response status code
  • Response time
  • SSL certificate validity
  • DNS resolution

Incident Management

When a monitor detects an issue, Better Stack creates an incident automatically. Incident workflow:
  1. Detection: Monitor fails X consecutive checks (configurable)
  2. Alert: Better Stack sends notifications (email, Slack, PagerDuty, etc.)
  3. Status page: Incident appears on your status page
  4. Resolution: Monitor recovers, incident auto-resolves
  5. Post-mortem: Incident history retained for analysis
Customize incident display:
  1. Go to Status Pages → Settings → Incidents
  2. Configure:
    • Which monitors trigger public incidents
    • Incident title format
    • Automatic status updates
    • Resolution messages
Not all monitor failures need to be public. Use “Private monitors” for internal services that shouldn’t appear on your status page.

Custom Domain Setup

Use your own domain for a professional status page.
1

Add CNAME record

In your DNS provider, add a CNAME record:
Type: CNAME
Name: status
Value: status.betteruptime.com
TTL: 3600 (or Auto)
Example for popular DNS providers:
  • Cloudflare
  • Vercel DNS
  • Namecheap
  1. Dashboard → DNS → Add record
  2. Type: CNAME
  3. Name: status
  4. Target: status.betteruptime.com
  5. Proxy status: DNS only (orange cloud OFF)
  6. Save
2

Configure in Better Stack

Add your custom domain to Better Stack.
  1. Go to Status Pages → Settings → Domain
  2. Enter: status.yourdomain.com
  3. Click Save
  4. Wait for DNS propagation (up to 24 hours, usually 15 minutes)
Better Stack automatically provisions SSL certificate via Let’s Encrypt.
3

Update badge URL

Update status-badge.tsx with your custom domain:
src={`https://status.yourdomain.com/badge?theme=${badgeTheme}`}

Customization

Badge Appearance

Better Stack provides several badge designs:
// Default badge (compact)
src={`https://status.yourdomain.com/badge?theme=${badgeTheme}`}

// Large badge (more info)
src={`https://status.yourdomain.com/badge/large?theme=${badgeTheme}`}

// Inline text (no border)
src={`https://status.yourdomain.com/badge/inline?theme=${badgeTheme}`}

Status Page Branding

Customize your status page’s appearance in Better Stack dashboard: Settings → Branding:
  • Logo: Upload your company logo (PNG, SVG, max 2MB)
  • Favicon: Custom favicon for status page
  • Primary color: Brand color (hex code)
  • Background: Light/dark mode backgrounds
  • Custom CSS: Advanced styling (paid plans)
Settings → Content:
  • Header text: Replace “System Status” with your text
  • Footer links: Add links to main site, support, etc.
  • About section: Company description
  • Contact info: Support email, Twitter handle
Match your status page’s branding to your main site for a cohesive experience.

Alternative Placements

The status badge can be placed anywhere in your app:
// In header
import { StatusBadge } from "@/components/shared/status-badge";

export function Header() {
  return (
    <header>
      <nav>...</nav>
      <StatusBadge /> {/* Top-right corner */}
    </header>
  );
}

// In dashboard sidebar
export function Sidebar() {
  return (
    <aside>
      <nav>...</nav>
      <div className="mt-auto">
        <StatusBadge />
      </div>
    </aside>
  );
}

// As a modal/popup
export function StatusModal() {
  return (
    <Dialog>
      <DialogTrigger>
        <StatusBadge />
      </DialogTrigger>
      <DialogContent>
        {/* Full status page iframe */}
        <iframe src="https://status.yourdomain.com" />
      </DialogContent>
    </Dialog>
  );
}
If you reposition the badge (header, footer variants, dashboard sidebar), follow the layout guidance in Footer customization so spacing and responsive behavior stay consistent across breakpoints.

Best Practices

Don’t just monitor your homepage - track the entire user journey.Essential monitors:
  • Landing page
  • Sign-up/login page
  • Dashboard/app
  • API endpoints
  • Payment processing
  • Database connectivity
Example monitor set:
✓ https://yourdomain.com (homepage)
✓ https://yourdomain.com/sign-in (auth)
✓ https://yourdomain.com/dashboard (app)
✓ https://api.yourdomain.com/health (API health)
✓ https://yourdomain.com/api/checkout (payments)
Balance between monitoring frequency and cost.Recommended intervals:
  • Critical services (auth, payments): 1 minute
  • Main website: 3 minutes
  • Documentation: 5 minutes
  • Internal tools: 10 minutes
Why not always 1 minute?
  • Free tier has limited checks per month
  • More frequent checks = higher costs on paid plans
  • Not all services need real-time monitoring
Better Stack’s free tier includes 10 monitors checking every 1 minute = 14,400 checks/day.
Bad:
  • Monitor 1
  • Test
  • Website
Good:
  • Main Website (getsabo.com)
  • API - Production
  • Stripe Webhook Endpoint
Why it matters:
  • Clear incident messages on status page
  • Easier alert triage
  • Better analytics and reporting
Avoid alert fatigue with smart thresholds.Default: Alert after 1 failed check Better: Alert after 3 consecutive failuresWhy?
  • Prevents false positives (network blips)
  • Confirms actual outages
  • Reduces notification noise
Configuration:
Alert Threshold: 3 consecutive failures
Recovery Threshold: 2 consecutive successes
Cooldown Period: 5 minutes
Transparency builds trust. Update your status page during outages.Incident update template:
[12:34] Investigating
We're aware of an issue affecting sign-in and investigating the cause.

[12:45] Identified
The issue is caused by a database connection timeout. We're working on a fix.

[13:15] Monitoring
A fix has been deployed. We're monitoring to ensure stability.

[13:30] Resolved
The issue has been fully resolved. All services are operational.
Best practices:
  • Update every 15-30 minutes during incidents
  • Be specific about what’s affected
  • Provide estimated resolution time (if known)
  • Apologize and explain after resolution

Troubleshooting

Symptoms: Footer shows blank space where badge should be.Causes:
  1. Incorrect badge URL in status-badge.tsx
  2. Better Stack status page not created
  3. Ad blocker blocking iframe
  4. CSP headers blocking iframe
Fix:
  1. Verify URL: Check line 29 in status-badge.tsx has correct subdomain
  2. Check Better Stack: Visit your status page URL directly in browser
  3. Test without ad blocker: Disable uBlock Origin, Privacy Badger, etc.
  4. Check CSP: If using Content Security Policy, allow Better Stack:
    next.config.ts
    headers: async () => [{
      key: 'Content-Security-Policy',
      value: "frame-src 'self' https://*.betteruptime.com"
    }]
    
  5. Check console: Browser DevTools → Console for iframe errors
Symptoms: Badge has light theme in dark mode (or vice versa).Causes:
  1. Missing ?theme=${badgeTheme} parameter
  2. Theme not resolving correctly
  3. Server-side render mismatch
Fix:
  1. Verify parameter: Ensure URL includes ?theme=${badgeTheme}
  2. Check theme hook: resolvedTheme should be “dark” or “light”
  3. Test mounting: Badge should show placeholder until mounted === true
  4. Check next-themes: Ensure ThemeProvider wraps your app in layout.tsx
Debug with console:
const badgeTheme = resolvedTheme === "dark" ? "dark" : "light";
console.log("Theme:", resolvedTheme, "Badge theme:", badgeTheme);
Symptoms: status.yourdomain.com shows DNS error.Causes:
  1. CNAME record not created
  2. DNS not propagated
  3. Wrong CNAME target
  4. Cloudflare proxy enabled (should be DNS only)
Fix:
  1. Verify CNAME: Use DNS Checker to verify:
    status.yourdomain.com → CNAME → status.betteruptime.com
    
  2. Wait for propagation: DNS can take up to 24 hours (usually 15 min)
  3. Check target: Must point to status.betteruptime.com exactly
  4. Disable Cloudflare proxy: Orange cloud should be OFF (gray cloud)
  5. Test with dig:
    dig status.yourdomain.com CNAME
    
    # Should return:
    # status.yourdomain.com. 3600 IN CNAME status.betteruptime.com.
    
Symptoms: Status badge shows old status after incident resolved.Causes:
  • Browser cache
  • iframe caching
  • CDN caching
Fix:
  1. Hard refresh: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
  2. Clear iframe cache: Better Stack badges have 60-second cache
  3. Wait 1-2 minutes: Badge auto-refreshes every 60 seconds
  4. Check Better Stack: Verify status page shows correct status
Badge updates are not instant. Better Stack caches badge images for 60 seconds to reduce load.
Symptoms: Monitor reports down but service is actually up.Causes:
  1. Too aggressive timeout (< 10 seconds)
  2. Checking from single region
  3. Rate limiting from monitoring checks
  4. SSL certificate issues
  5. Firewall blocking Better Stack IPs
Fix:
  1. Increase timeout: Set to 30 seconds minimum
  2. Multi-region checks: Enable in monitor settings
  3. Whitelist Better Stack: Allow IPs 35.186.224.0/24 and 35.197.128.0/24
  4. Check SSL: Ensure certificate is valid and not expired
  5. Alert threshold: Set to 3 consecutive failures instead of 1
  6. Test manually: Visit URL from different locations (VPN, mobile network)

Going Further

Integrations

Better Stack integrates with popular tools: Alerting:
  • Slack - Real-time incident notifications
  • Discord - Status updates in your server
  • PagerDuty - On-call management
  • Microsoft Teams - Enterprise communications
  • Webhooks - Custom integrations
Configuration:
  1. Better Stack → Integrations
  2. Select your tool
  3. Authorize connection
  4. Configure alert rules
Set up Slack notifications for your team to stay informed about incidents immediately.

Advanced Monitoring

Multi-step checks:
1. Visit login page
2. Submit credentials
3. Verify dashboard loads
4. Check API response
Synthetic monitoring:
  • Simulate real user interactions
  • Test complete user flows
  • Validate complex workflows
  • Paid plans only
Global checks:
  • Test from 10+ regions worldwide
  • Detect regional outages
  • Optimize CDN performance
  • Available on all plans

Alternative Solutions

If Better Stack doesn’t fit your needs:
SolutionProsConsPrice
Better StackEasy setup, generous free tierFewer regions on free planFree - $29/mo
Statuspage.ioAtlassian ecosystem, powerfulExpensive, complex2929 - 699/mo
StatusCastSimple, affordableLimited features1919 - 99/mo
InstatusBeautiful design, fastNewer, smaller team00 - 49/mo
Self-hostedFull control, no costMaintenance burden, setup timeFree
Sabo’s status badge implementation works with any Better Stack-compatible status page provider. Simply update the iframe URL in status-badge.tsx.