log in
consulting hosting industries tools the daily about contact

Better Stack: The Uptime + Logs + Status Page Trio I Keep Reaching For

Better Stack quietly bundles three tools I used to stitch together from three vendors. It's not perfect, but it's close enough that I've migrated most of my managed hosting clients to it.

I spent years paying three separate vendors to do three things that logically belong together: uptime monitoring, log aggregation, and a public status page. Better Stack bundles all three, the API is clean, and the pricing doesn't make me want to cry. It's the most underrated tool in my current stack.

The Problem It Actually Solves

Here's the situation I was living in before: Pingdom for uptime checks, Papertrail for logs, and a hand-rolled status page I was embarrassed to show clients. When something went wrong at 2 a.m., I'd get a Pingdom alert, log into Papertrail in a separate tab, correlate timestamps manually, then go update the status page by hand — if I remembered to update it at all.

That's not a monitoring stack. That's three dashboards and a prayer.

What Better Stack does is obvious in retrospect: uptime checks that link directly to log entries from the moment the check failed. A status page that can automatically reflect incidents triggered by those checks. One API, one webhook surface, one place to look when something's on fire. The integration isn't bolted on — it feels like it was designed that way from the start, which is rare.

I run managed hosting for clients in healthcare, e-commerce, and real estate. They care about two things: is the site up, and when it's not, can they point a customer to something that looks professional instead of a Twitter thread. Better Stack handles both.

A Working Integration

I integrate Better Stack into all my Laravel apps now. Here's the pattern I actually use in production — a heartbeat ping on scheduled jobs, plus structured log shipping.

First, the heartbeat. Better Stack has a dead man's switch style heartbeat monitor. You configure a URL in their dashboard, set an expected interval, and if they don't hear from you, they alert. I wire this into Laravel's scheduler:

// app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
    $schedule->command('reports:generate-daily')
             ->dailyAt('06:00')
             ->after(function () {
                 Http::get(config('services.betterstack.heartbeat_url'));
             });
}
// config/services.php
'betterstack' => [
    'heartbeat_url' => env('BETTERSTACK_HEARTBEAT_URL'),
    'source_token'  => env('BETTERSTACK_SOURCE_TOKEN'),
],

Simple. If the job runs and doesn't ping, I get an alert. No cron wrapper scripts, no external monitoring of the cron itself. This saved me once with a biotech client whose nightly data export job silently stopped running after a PHP version bump. The heartbeat caught it in six hours instead of three days.

For log shipping, Better Stack uses a Syslog-compatible endpoint or their own HTTP ingest. I use the HTTP ingest because it's easier to add structured context. I wrote a small Laravel log channel for it:

// config/logging.php
'channels' => [
    'betterstack' => [
        'driver' => 'monolog',
        'handler' => App\Logging\BetterStackHandler::class,
        'level'   => env('LOG_LEVEL', 'warning'),
    ],
    'stack' => [
        'driver'   => 'stack',
        'channels' => ['daily', 'betterstack'],
    ],
],
// app/Logging/BetterStackHandler.php
namespace App\Logging;

use Monolog\Handler\AbstractProcessingHandler;
use Monolog\LogRecord;
use Illuminate\Support\Facades\Http;

class BetterStackHandler extends AbstractProcessingHandler
{
    protected function write(LogRecord $record): void
    {
        Http::withToken(config('services.betterstack.source_token'))
            ->post('https://in.logs.betterstack.com', [
                'dt'      => $record->datetime->format(\DateTime::RFC3339_EXTENDED),
                'message' => $record->message,
                'level'   => $record->level->getName(),
                'context' => $record->context,
                'channel' => $record->channel,
                'env'     => app()->environment(),
            ]);
    }
}

This is synchronous and you will feel it if you log a lot. In high-throughput contexts I wrap this with a queued job or use their Fluent Bit integration instead. For most of my clients — a few thousand requests a day — the synchronous handler is fine and the simplicity is worth it.

The status page setup is entirely in the Better Stack dashboard — no code required. You create monitors, group them into components, attach the components to a status page. The page gets a subdomain like status.yourcompany.com via a CNAME. Took me about 20 minutes the first time.

The Gotchas That Bit Me

The HTTP log ingest has a rate limit and a payload size limit. I hit the payload limit when I made the mistake of logging full API response bodies in context. Better Stack will silently drop oversized payloads in some configurations. Log metadata and error summaries, not full response dumps. Sounds obvious. I still did it.

Uptime check locations matter and the defaults aren't always right. I had a client whose site was hosted in a Seattle data center. Better Stack's checks were hitting it from Frankfurt and Virginia by default. The site had a geographic firewall rule (long story — healthcare client, they were paranoid). It kept falsely alerting. You can configure check regions but it's not front-and-center in the UI. Dig into the monitor settings.

The on-call scheduling is functional but not PagerDuty. If you have a complex rotation with multiple people, escalation policies, and override calendars, Better Stack's on-call feature will frustrate you. It's good enough for a small shop like mine — I'm mostly the on-call — but I have one client with a real ops team who still uses PagerDuty for escalation and just pipes Better Stack alerts into it via webhook.

Status page incident updates require manual action by default. Incidents auto-open when a monitor fails, which is great. But the updates — "we're investigating," "fix deployed" — those are manual. I've gotten burned by a client checking their status page and seeing a stale incident with no updates because I was heads-down fixing the thing instead of narrating it. There's an API to post updates programmatically, which I now use from my deployment scripts:

// Post an incident update during deployment if there's an active incident
Http::withToken(env('BETTERSTACK_API_KEY'))
    ->post("https://uptime.betterstack.com/api/v2/incidents/{$incidentId}/updates", [
        'message' => 'Fix deployed. Monitoring for stability.',
        'type'    => 'update',
    ]);

But you have to know the incident ID, which means you need to query for open incidents first. It's a two-step process that I've scripted but wish was easier.

Log retention on lower tiers is short. The free and entry-level tiers give you 3 days of log retention. For serious log forensics after a weekend incident, that can be tight. Know your tier before you need it.

When I'd Reach for This

I reach for Better Stack when I'm setting up managed hosting for a client and I want one tool that covers the monitoring surface without a lot of glue code. It's my default for any new project now. The sweet spot is a small-to-medium Laravel or Node app, a client who needs a professional-looking status page, and a solo operator or small team running the infrastructure.

I'd reach for it specifically if:

  • You're currently juggling more than one monitoring vendor and hate context-switching during incidents
  • Your clients ask "is there somewhere I can check if the site is down?" and you don't have a good answer
  • You're running scheduled jobs and want dead man's switch monitoring without setting up something elaborate
  • You want logs and uptime correlated in one timeline during postmortems

I'd look elsewhere if:

  • You need serious APM — distributed tracing, flame graphs, the works. Better Stack isn't Datadog. Don't expect it to be.
  • You have a complex on-call rotation with multiple engineers. Route Better Stack alerts into PagerDuty or OpsGenie instead of trying to run scheduling in Better Stack itself.
  • You're shipping millions of log lines a day. Their ingest works, but you'll want to think carefully about cost and probably use a log shipper (Fluent Bit, Vector) instead of the HTTP API.
  • You need deep infrastructure metrics — CPU, memory, disk trends over time. This is application-layer monitoring, not infrastructure monitoring. Pair it with something like Grafana Cloud or Netdata if you need the system layer.

The Bottom Line

Better Stack isn't the most powerful tool in any individual category. But the sum is greater than the parts, and for the way I actually work — small team, lots of clients, incidents that happen at inconvenient hours — the integration between uptime, logs, and status page is worth more than marginal feature wins from specialized tools. I've migrated most of my hosting clients to it and I haven't looked back.

If you're still duct-taping three monitoring services together, spend an afternoon with Better Stack. The free tier is generous enough to evaluate it on a real project, and the API is the kind that doesn't make you feel like you need a shower after reading the docs.

Need help shipping something like this? Get in touch.