Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Uptime Monitor Laravel Package

spatie/laravel-uptime-monitor

Powerful, easy-to-configure uptime monitor for Laravel that notifies you when sites go down and recover, plus warns before SSL certificates expire. Uses Laravel native notifications to support Slack, Telegram, mail, and more.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal path from install to first alert:

composer require spatie/laravel-uptime-monitor
php artisan vendor:publish --provider="Spatie\UptimeMonitor\UptimeMonitorServiceProvider"
php artisan migrate

Then configure the package in config/uptime-monitor.php. The first file to read should be that config file: it is the real feature map for notifications, response checking, concurrency, timeouts, SSL thresholds, and model extension. The docs at https://spatie.be/docs/laravel-uptime-monitor fill in the command and model details.

For a first use case, monitor a production URL and its SSL certificate, then send failures and recoveries to Slack:

// config/uptime-monitor.php
'notifications' => [
    'notifications' => [
        \Spatie\UptimeMonitor\Notifications\Notifications\UptimeCheckFailed::class => ['slack'],
        \Spatie\UptimeMonitor\Notifications\Notifications\UptimeCheckRecovered::class => ['slack'],
        \Spatie\UptimeMonitor\Notifications\Notifications\CertificateExpiresSoon::class => ['slack'],
    ],
    'slack' => [
        'webhook_url' => env('UPTIME_MONITOR_SLACK_WEBHOOK_URL'),
    ],
],

Create the monitor interactively, then run a check immediately:

php artisan monitor:create
php artisan monitor:check-uptime

Schedule both checks. The uptime command is designed to run frequently; it decides internally whether each monitor is due based on uptime_check_interval_in_minutes.

// Laravel 10 and earlier: app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    $schedule->command('monitor:check-uptime')->everyMinute()->withoutOverlapping();
    $schedule->command('monitor:check-certificate')->daily();
}
// Laravel 11+: routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('monitor:check-uptime')->everyMinute()->withoutOverlapping();
Schedule::command('monitor:check-certificate')->daily();

Make sure the Laravel scheduler itself is running via cron or your platform’s scheduler.

Implementation Patterns

Manage monitors as application data, not just artisan commands. For a small set, monitor:create is fine. For a real fleet, seed or admin-manage the Monitor model so environments are reproducible:

use Spatie\UptimeMonitor\Models\Monitor;

Monitor::updateOrCreate(
    ['url' => 'https://example.com'],
    [
        'uptime_check_enabled' => true,
        'certificate_check_enabled' => true,
        'uptime_check_interval_in_minutes' => 5,
        'look_for_string' => 'Example Domain',
    ]
);

Treat url as the natural key in your own tooling, and keep monitor definitions in a seeder, deployment script, or internal admin CRUD. The package does not ship a UI or API. If you need an API, either build a thin CRUD over Monitor or evaluate the external LKDevelopment/laravel-uptime-monitor-api package.

Use the notification map as routing, not as business logic. The config maps each notification class to channels. Keep “where do alerts go?” there, and put “what should happen when a site fails?” in event listeners. Slack and mail are built in; other channels work through Laravel notifications.

use Spatie\UptimeMonitor\Events\MonitorFailed;

Event::listen(MonitorFailed::class, function (MonitorFailed $event) {
    // Create a ticket, update a status page, or notify a customer-specific channel.
});

This is also the escape hatch for per-customer or per-team routing. The default notifiable is config-wide, so if different monitors belong to different customers, listen to events and dispatch your own notifications rather than forcing everything through notifications.mail.to.

Choose response checks deliberately. The default LookForStringChecker is ideal for “200 and the page contains this marker.” For JSON health endpoints, APIs, or apps that return 200 with an error body, implement the UptimeResponseChecker contract and configure it globally or per monitor. For simple cases, use additional_status_codes when 201, 204, or redirect codes should count as healthy.

'uptime_check' => [
    'additional_status_codes' => [201, 204],
    'guzzle_options' => [
        // 'allow_redirects' => false,
    ],
],

Set notifications.location per environment. A blank location makes staging and production alerts indistinguishable. Use values like production-eu, staging, or the application name.

Tune noise with the two failure controls. resend_uptime_check_failed_notification_every_minutes controls repeat nagging, while fire_monitor_failed_event_after_consecutive_failures controls when the package fires the failed event. Use the event threshold for ticket creation and the notification resend interval for reminders.

For larger monitor sets, inspect the sync command. The package includes monitor:sync; check its signature with php artisan monitor:sync --help in your installed version before making it part of a declarative workflow. Do not mix manual edits and sync-owned definitions without understanding which side wins.

Gotchas and Tips

  • Schedule monitor:check-uptime every minute, not every five minutes. The command checks each monitor against its own uptime_check_interval_in_minutes. Scheduling it less often adds alert latency and makes recovery/failure timing less predictable.
  • Changing run_interval_in_minutes does not update existing monitors. The config comment is explicit: update uptime_check_interval_in_minutes on existing records too. Do that in a migration, seeder, or one-off command.
  • Failed checks bypass the normal interval. Once a monitor is down, the package checks it every time monitor:check-uptime runs. That is good for recovery detection, but it means scheduling frequency directly affects retry volume.
  • The event threshold and notification threshold are not the same thing. A first failed check may produce an uptime-failed notification while MonitorFailed waits for the configured number of consecutive failures. Avoid wiring both to the same pager without deduplication.
  • look_for_string is exact body matching. If the string moves, becomes localized, or is rendered client-side, checks will fail despite a healthy server. Prefer a stable health endpoint or a custom response checker.
  • Redirects and status codes bite. With Guzzle redirects disabled, a 301/302 is a failure unless you add it to additional_status_codes. Conversely, adding too many codes can hide real problems.
  • Lower concurrent_checks if you see strange network errors. The default of 10 is usually fine, but shared hosting, strict firewalls, or rate-limited targets may need a lower value.
  • Timeout and retry settings are per check, not per monitor schedule. timeout_per_site and retry_connection_after_milliseconds control a single check attempt sequence.
  • Custom headers and user agent matter behind WAFs. If Cloudflare, bot protection, or basic auth blocks the checker, use additional_headers and user_agent rather than assuming the site is down.
  • SSL checks need HTTPS and a valid certificate chain. Self-signed or internal certificates will fail unless you adjust Guzzle options—avoid disabling verification in production unless the target is genuinely internal.
  • Configure at least one real channel. The default config points failure notifications at Slack. If the webhook is missing, you may get notification errors instead of alerts.
  • Clear config cache after changes. Run php artisan config:clear locally or redeploy with fresh config caching; otherwise scheduler and notification changes may not take effect.
  • Custom models must extend the package model. Set monitor_model to your subclass and add any extra columns via your own migration. Clear config cache after changing the binding.
  • Testing is Guzzle-oriented. The package uses Guzzle under the hood, so Laravel’s Http::fake() may not intercept checks. For integration tests, point monitors at a local test server or mock the package’s HTTP layer.
  • There is no built-in API or dashboard. Day-to-day visibility comes from the monitors table, package events, notifications, and your own admin surface. Inspect the monitor record’s uptime/certificate status and failure reason columns when debugging.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core