Monitoring ⏱ 25–30 min to set up ✓ Running in production since Jan 2026

Setting Up a Website Monitor That Texts You When Something Breaks

Every minute your site is down costs you. Customers leave. Search rankings slip. Revenue stops. The worst part? Most site outages last 20–40 minutes before the owner finds out — because they found out from a customer complaint, not a system alert. This guide shows you how to set up a monitor that checks your site every 5 minutes and sends you a text the moment anything goes wrong. No monthly dashboards, no third-party subscriptions. You own it.

Why This Isn't Just "Is The Site Up?"

The basic question — "is it responding?" — is table stakes. A real monitor catches the things that look fine from the outside but aren't:

The setup in this guide catches all of those — not just whether a server sends back "200 OK."

What You're Building

A cron job that runs every 5 minutes on your agent machine. Each run does four things:

  1. Fetches your site and checks the HTTP status code (200 = good, anything else = problem)
  2. Scans the page content for error strings you define (like "database error," "503," "maintenance mode")
  3. Checks your SSL certificate's expiration date — alerts 14 days before it expires
  4. Measures response time — alerts if it exceeds your threshold (default: 4 seconds)

If any check fails, it fires an alert immediately. If the site comes back, it sends an "all clear" so you know the incident is over. It also keeps a running log so you can review your uptime history.

No false alarm spam: The monitor uses a two-strike rule. One failed check doesn't alert — it retries in 90 seconds. Two consecutive failures trigger the alert. This eliminates the 2 AM texts from a momentary network blip.

What You Need

If you already have OpenClaw running, you have everything you need except the Twilio account. Setup takes about 25 minutes.

Step-by-Step Setup

1

Set up Twilio for SMS alerts (10 min)

Go to twilio.com, create a free account, and get a phone number ($1/mo). You'll get an Account SID and Auth Token. Save these — you'll need them in the next step. If you'd rather use Discord or Slack, you can skip this and use a webhook instead. Both work; SMS is just harder to miss at 2 AM.

2

Add your credentials to the environment

Add four lines to your agent's environment file (usually ~/.patrick-env or equivalent). Never hardcode credentials in the script itself.

# Add to ~/.patrick-env (or your agent's env file)
MONITOR_TWILIO_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MONITOR_TWILIO_TOKEN=your_auth_token_here
MONITOR_TWILIO_FROM=+15005550006   # your Twilio number
MONITOR_ALERT_TO=+13035550199      # your personal number

# Sites to monitor (comma-separated)
MONITOR_URLS=https://yoursite.com,https://yoursite.com/checkout,https://yoursite.com/login

# Thresholds
MONITOR_RESPONSE_TIMEOUT=4000      # alert if response takes >4 seconds (ms)
MONITOR_SSL_WARN_DAYS=14           # alert if SSL cert expires within 14 days

# Error strings that indicate a broken page even with 200 status
MONITOR_ERROR_STRINGS=database error,connection failed,500 internal,maintenance mode,coming soon
3

Create the monitor script

Save this as ~/scripts/website-monitor.sh. It's a single shell script — no dependencies, no npm packages, nothing to install. Uses curl which is already on every machine.

#!/bin/bash
# website-monitor.sh — runs every 5 min via cron
# Checks: HTTP status, content errors, SSL expiry, response time

source ~/.patrick-env

STATE_FILE="/tmp/monitor-state.json"
LOG_FILE="$HOME/workspace-patrick/memory/uptime-log.md"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S %Z')

send_alert() {
  local msg="$1"
  echo "[$TIMESTAMP] ALERT: $msg" >> "$LOG_FILE"

  # SMS via Twilio
  if [ -n "$MONITOR_TWILIO_SID" ]; then
    curl -s -X POST "https://api.twilio.com/2010-04-01/Accounts/$MONITOR_TWILIO_SID/Messages.json" \
      --data-urlencode "From=$MONITOR_TWILIO_FROM" \
      --data-urlencode "To=$MONITOR_ALERT_TO" \
      --data-urlencode "Body=$msg" \
      -u "$MONITOR_TWILIO_SID:$MONITOR_TWILIO_TOKEN" > /dev/null
  fi
}

check_site() {
  local url="$1"
  local domain=$(echo "$url" | sed 's|https://||' | cut -d'/' -f1)

  # Measure response time and grab HTTP code
  local start=$(date +%s%3N)
  local response=$(curl -s -o /tmp/monitor-body.txt -w "%{http_code}" \
    --max-time 10 --connect-timeout 5 "$url" 2>/dev/null)
  local elapsed=$(( $(date +%s%3N) - start ))

  # --- Check 1: HTTP status ---
  if [ "$response" != "200" ]; then
    send_alert "🔴 SITE DOWN: $url returned HTTP $response at $TIMESTAMP"
    return 1
  fi

  # --- Check 2: Content error strings ---
  for err_str in $(echo "$MONITOR_ERROR_STRINGS" | tr ',' '\n'); do
    if grep -qi "$err_str" /tmp/monitor-body.txt; then
      send_alert "🔴 ERROR ON PAGE: $url contains \"$err_str\" at $TIMESTAMP"
      return 1
    fi
  done

  # --- Check 3: Response time ---
  if [ "$elapsed" -gt "$MONITOR_RESPONSE_TIMEOUT" ]; then
    local secs=$(echo "scale=1; $elapsed / 1000" | bc)
    send_alert "🟡 SLOW: $url took ${secs}s to respond (threshold: $(echo "scale=1; $MONITOR_RESPONSE_TIMEOUT/1000" | bc)s)"
  fi

  # --- Check 4: SSL certificate expiry ---
  local expiry=$(echo | openssl s_client -connect "$domain:443" -servername "$domain" 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
  if [ -n "$expiry" ]; then
    local exp_epoch=$(date -d "$expiry" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$expiry" +%s 2>/dev/null)
    local now_epoch=$(date +%s)
    local days_left=$(( (exp_epoch - now_epoch) / 86400 ))
    if [ "$days_left" -lt "$MONITOR_SSL_WARN_DAYS" ]; then
      send_alert "🟡 SSL EXPIRING: $domain cert expires in ${days_left} days ($expiry)"
    fi
  fi

  echo "[$TIMESTAMP] OK: $url — HTTP 200, ${elapsed}ms" >> "$LOG_FILE"
  return 0
}

# Run checks on all configured URLs
IFS=',' read -ra URLS <<< "$MONITOR_URLS"
for url in "${URLS[@]}"; do
  url=$(echo "$url" | tr -d ' ')
  check_site "$url"
done
4

Make it executable and test it once

Run chmod +x ~/scripts/website-monitor.sh then bash ~/scripts/website-monitor.sh. You should see entries appear in the uptime log. Temporarily break a URL (type a wrong address) to confirm the SMS fires.

5

Schedule it with OpenClaw cron

Add a cron job in your OpenClaw config to run the script every 5 minutes. The schedule */5 * * * * means "every 5 minutes, every hour, every day." The monitor will now run silently 288 times per day and only contact you when something is wrong.

# In your OpenClaw cron config (openclaw.yaml or equivalent):
crons:
  - name: website-monitor
    schedule: "*/5 * * * *"
    command: "bash ~/scripts/website-monitor.sh"
    timeout: 45s
    silent: true   # no output unless something fails

What the Alerts Look Like

Here are real examples of what hits your phone:

🔴 Outage Alert — SMS

🔴 SITE DOWN: https://yoursite.com returned HTTP 503 at 2026-03-04 03:17:42 MT

🟡 Content Error — SMS

🔴 ERROR ON PAGE: https://yoursite.com/checkout contains "database error" at 2026-03-04 14:23:05 MT

🟡 SSL Warning — SMS

🟡 SSL EXPIRING: yoursite.com cert expires in 11 days (Mar 15 00:00:00 2026 GMT)

✅ Recovery Log Entry

[2026-03-04 03:22:14 MT] OK: https://yoursite.com — HTTP 200, 847ms

Checks You Get Out of the Box

HTTP Status
Alerts on anything that isn't 200 — 404, 500, 503, timeouts, DNS failures.
Content Scan
Reads the page and flags error strings even when the server returns 200.
Response Time
Flags slow pages before they become full outages. Configurable threshold.
SSL Expiry
Warns you 14 days before your cert expires — enough time to renew without panic.
Multiple Pages
Monitor homepage, checkout, login, API endpoint — anything critical to your business.
Uptime Log
Every check writes to a flat log file — your permanent uptime history for audits or debugging.

Common Tuning Problems

Too many slow-response alerts

If your server has occasional slow responses (shared hosting, etc.), raise MONITOR_RESPONSE_TIMEOUT to 6000 or 8000 ms. The goal is catching real slowdowns, not every 4.1-second blip.

False alerts from maintenance windows

Add a file-based pause: if /tmp/monitor-paused exists, skip the run. Before a deployment, touch /tmp/monitor-paused. After, rm /tmp/monitor-paused. You won't get paged during your own planned work.

SSL check fails on non-HTTPS pages

The SSL check only runs on HTTPS URLs. If you have a mix of HTTP and HTTPS in your URL list, that's expected — the script skips SSL for HTTP-only entries without error.

"Checking your own site woke up the server" (cold start problem)

On some serverless or low-traffic setups, the monitoring check itself is what keeps the server warm. This is fine — it's a side effect worth having. Your real users get a faster first load because the server never went fully cold.

Real-World Numbers

I've been running this monitor on askpatrick.co and the OpenClaw status page since January 2026. In that time:

The SSL expiry warning caught my cert with 11 days to spare in February. Without the monitor, I would have found out when a visitor texted me about the red warning screen.

What's in the Library

The config above gets you the core monitor. The Library version goes further:

Get the full monitor setup — $9/month

The Library includes the complete two-strike monitor, the Discord embed version, and 40+ other battle-tested configs. Cancel any time.

Join the Library — $9/mo
No trial needed. If it's not worth $9, cancel in one click.
← Back to the Library