README
ΒΆ
π Upp

Uptime monitoring + change detection in a single binary. No Docker. No browser. Just your terminal.
Table of Contents
- Why Upp?
- Quick Start
- Features
- Check Types
- Target Configuration Fields
- Tutorial: Monitor Your First Website in 60 Seconds
- AI Agent Integration
- How Upp Is Different
- Installation
- All Commands
- Configuration
- Running as a Background Service
- Tech Stack
- Contributing
- License
Why Upp?
You just want to know if your website is up. Maybe get alerted when a pricing page changes. Simple, right?
There are plenty of great monitoring tools out there β dashboards, status pages, change trackers. They work well for what they're built for. But most share a common pattern:
- Docker or server required β spin up a container, expose a port, manage volumes
- Web UI only β need a browser to check on things
- Single purpose β want uptime monitoring and change detection? Run separate services
- Hard to script β integrating with cron jobs or AI agents means wrestling with REST APIs
For teams running production infrastructure with public status pages, these tools are the right choice. But if you just want to monitor a handful of sites from your terminal β or let an AI agent keep an eye on things β there should be a simpler way.
That's why Upp exists.
One 17MB binary. Works from your terminal. Works over SSH. Works in cron jobs. Works with AI agents out of the box. Install it, add a URL, done. No containers, no web UIs, no port forwarding.
Quick Start
# Install
go install github.com/naru-bot/upp@latest
# Add a site
upp add https://example.com --name "My Site"
# Check it
upp check
# See results
upp status
That's it. You're monitoring a website.
Features
π₯ Interactive TUI Dashboard
Full terminal UI with keyboard navigation. Browse targets, view stats, trigger checks β all without leaving your terminal. Works beautifully over SSH.
upp tui

Navigate with ββ/jk, Enter for details, c to check, p to pause, d to delete.
π Uptime Monitoring with Sparklines
Track HTTP status codes, response times, availability percentage, and SSL certificate expiry. Response time trends are visualized as sparkline charts right in your terminal.
upp status --period 7d
upp watch --refresh 10 # Live auto-refreshing dashboard

π Change Detection + Diff
Monitor pages for content changes. Target specific elements with CSS selectors. View colored unified diffs of what changed.
upp add https://example.com/pricing --name "Pricing" --selector "div.price"
upp check "Pricing"
upp diff "Pricing"
π― Conditional Triggers
Only get notified when specific conditions are met. Reduce alert noise by filtering on content.
# Alert only when "out of stock" appears
upp add https://store.example.com/product --trigger-if "contains:out of stock"
# Alert when "healthy" disappears from status page
upp add https://example.com/status --trigger-if "not_contains:healthy"
# Alert on regex pattern match
upp add https://example.com/pricing --trigger-if "regex:price.*\$[5-9][0-9]"
# Combine with CSS selectors or jq for precise monitoring
upp add https://example.com/api --jq '.status' --trigger-if "not_contains:ok"
Trigger types: contains, not_contains, regex, not_regex
π‘ JSON API Monitoring (jq)
Monitor JSON APIs with built-in jq filtering. Extract specific fields before change detection β only track what matters.
# Monitor a specific field in a JSON API
upp add https://api.example.com/v1/status --jq '.services.database.status' --name "DB Status"
# Track price changes from a JSON endpoint
upp add https://api.store.com/product/123 --jq '.price' --name "Product Price"
# Extract nested data
upp add https://api.example.com/data --jq '.items[] | {name, status}' --name "Items"
# Combine with triggers β alert only when price drops below threshold
upp add https://api.store.com/product/123 --jq '.price' --trigger-if "regex:^[0-9]\."
π Advanced HTTP Options
Full control over HTTP requests β method, body, auth, redirects, and status codes.
# POST request with JSON body (API health checks, GraphQL, webhooks)
upp add https://api.example.com/health --method POST --body '{"check":"deep"}'
# Bearer token authentication
upp add https://api.example.com/protected --auth-bearer "your-token-here"
# Basic auth
upp add https://staging.example.com --auth-basic "user:password"
# Monitor that a redirect exists (don't follow it)
upp add https://old.example.com --no-follow --accept-status "301"
# Accept specific status codes as "up" (e.g. 404 page monitoring)
upp add https://example.com/deleted-page --accept-status "200,404"
# Skip TLS verification (self-signed certs on internal services)
upp add https://internal.example.com:8443 --insecure
# Combine everything: POST + auth + jq + trigger
upp add https://api.example.com/graphql \
--method POST \
--body '{"query":"{ status { healthy } }"}' \
--auth-bearer "token" \
--jq '.data.status.healthy' \
--trigger-if "not_contains:true"
π· Tags & Organization
Organize targets with tags. Filter by tag in the CLI and TUI.
# Tag targets when adding
upp add https://example.com --tag production --tag web
# Tag existing targets
upp tag "My Site" production web
upp untag "My Site" staging
# Filter by tag
upp list --tag production
upp check --tag production
upp list --tags # show all tags with counts
# TUI: press 't' to cycle tag filter, '/' to search
β‘ Quick Ping Diagnostics
One-off checks without saving anything to the database. Perfect for quick debugging.
upp ping https://api.example.com/health

π€ JSON Output for AI Agents
Every single command supports --json. Consistent, structured output that's trivial to parse. This is what makes Upp different from every GUI-based monitor.
upp check --json | jq '.[] | select(.status == "down")'
[
{
"target": "My Site",
"url": "https://example.com",
"status": "up",
"status_code": 200,
"response_time_ms": 142,
"changed": false,
"ssl_days_left": 85
}
]

π Notifications
Get alerted on Telegram, Discord, Slack, webhooks, or custom shell commands when things go wrong.
# Telegram
upp notify add --name tg --type telegram \
--config '{"bot_token":"123:ABC","chat_id":"-100123"}'
# Discord
upp notify add --name discord --type discord \
--config '{"webhook_url":"https://discord.com/api/webhooks/..."}'
# Webhook (Slack, etc.)
upp notify add --name alerts --type webhook \
--config '{"url":"https://hooks.slack.com/services/..."}'
# Custom shell command
upp notify add --name logger --type command \
--config '{"command":"echo \"{target} is {status}\" >> /var/log/upp.log"}'
# Manage
upp notify list
upp notify remove alerts

π» Daemon Mode
Run Upp as a background service. Checks run on schedule, notifications fire automatically.
upp daemon # Foreground
nohup upp daemon & # Background
See Systemd Service for production setup.
Check Types
Upp supports multiple monitoring approaches for different use cases:
HTTP (default)
- Monitors HTTP/HTTPS endpoints
- Tracks status codes, response times, SSL expiry
- Supports CSS selectors for targeted change detection
- Supports expected keyword matching
- Examples:
upp add https://example.com --name "My Site" upp add https://example.com/pricing --selector "div.price" --name "Pricing" upp add https://api.example.com/health --expect "ok" --name "API Health"
TCP
- Tests TCP port connectivity
- Example:
upp add example.com:3306 --type tcp --name "MySQL"
Ping
- ICMP-style connectivity check
- Example:
upp add example.com --type ping --name "Server Ping"
DNS
- DNS resolution check
- Example:
upp add example.com --type dns --name "DNS Check"
Visual (screenshot diff)
- Takes screenshots via headless browser and compares pixel-by-pixel
- Configurable threshold percentage (default 5%)
- Requires a headless browser (run
upp doctorto check) - Examples:
upp add https://example.com --type visual --name "Homepage Visual" upp add https://example.com --type visual --threshold 10.0 --name "Loose Visual"
WHOIS (domain monitoring)
- Monitors WHOIS data for changes (registrar, nameservers, status)
- Tracks domain expiry and warns when <30 days
- Domain is extracted from URL automatically
- Example:
upp add https://example.com --type whois --name "Domain WHOIS"
Target Configuration Fields
When using the TUI add/edit screen, these fields control how your targets are monitored:
| Field | Description | Applies to |
|---|---|---|
| Name | Display name for the target | All types |
| URL | Target URL or address | All types |
| Type | Check type (http, tcp, ping, dns, visual, whois) | All types |
| Interval | Seconds between checks (default: 300) | All types |
| Timeout | Request timeout in seconds (default: 30, visual: 60 recommended) | All types |
| Retries | Retry count before marking down (default: 1) | All types |
| Selector | CSS selector to monitor specific page element | http |
| Expect | Expected keyword in response body | http |
| Threshold (%) | Visual diff percentage to trigger change (default: 5.0) | visual |
| Trigger Rule | Conditional notification rule (e.g. contains:text, regex:pattern) |
All types |
| jq Filter | jq expression to filter JSON API responses before change detection | http |
| Method | HTTP method: GET, POST, PUT, PATCH, DELETE, HEAD (default: GET) | http |
| Body | Request body for POST/PUT/PATCH requests | http |
| Auth | --auth-basic user:pass or --auth-bearer token (stored in headers) |
http |
| No-Follow | Don't follow HTTP redirects | http |
| Accept Status | Accepted status codes, e.g. 200-299,301,404 (default: 200-399) |
http |
| Insecure | Skip TLS certificate verification | http |
Tutorial: Monitor Your First Website in 60 Seconds
Step 1 β Install Upp:
go install github.com/naru-bot/upp@latest
Step 2 β Add a website to monitor:
upp add https://yoursite.com --name "My App"
Step 3 β Run your first check:
upp check "My App"
You'll see status code, response time, SSL days remaining, and whether content changed.
Step 4 β Set up a notification so you know when it goes down:
upp notify add --name tg --type telegram \
--config '{"bot_token":"YOUR_BOT_TOKEN","chat_id":"YOUR_CHAT_ID"}'
Step 5 β Start the daemon for continuous monitoring:
upp daemon
Done. You're monitoring a website with notifications. No Docker, no browser, no account signups.
Bonus β Launch the TUI for a beautiful overview:
upp tui
AI Agent Integration
This is Upp's superpower. Every command speaks JSON natively. No API servers, no authentication tokens, no SDK. Just pipe and parse.
Use with AI coding agents
# "Are any of my sites down?"
upp check --json | jq '.[] | select(.status == "down")'
# "Which sites have low uptime?"
upp status --json | jq '.[] | select(.uptime_percent < 99)'
# "Did anything change?"
upp check --json | jq '.[] | select(.changed == true)'
# "Show me the diff"
upp diff "Pricing Page" --json
JSON conventions
- Lists β JSON arrays:
[{...}, {...}] - Single items β JSON objects:
{...} - Errors β
{"error": "message"} - Timestamps β RFC3339 format
Cron integration
# Check every 5 minutes, email on failures
*/5 * * * * upp check --json | jq -e '.[] | select(.status == "down")' && \
echo "ALERT" | mail -s "Site down" admin@example.com
How Upp Is Different
| Typical web-based monitors | Upp | |
|---|---|---|
| Install | Docker / server setup | Single binary, zero dependencies |
| Interface | Web browser required | Terminal / TUI / JSON |
| Check types | HTTP only | HTTP, TCP, Ping, DNS, Visual, WHOIS |
| Uptime + change detection | Usually separate tools | All-in-one |
| AI & automation friendly | REST API wrappers | Native CLI + JSON on every command |
| Interactive dashboard | Browser tab | TUI that works over SSH |
| Resource usage | 100-300MB+ RAM | ~10MB |
| Scriptable | Needs API tokens & HTTP calls | Pipe-friendly, works in cron/shell |
Installation
Go install (recommended)
go install github.com/naru-bot/upp@latest
Requires Go 1.24+.
Binary releases
macOS (Apple Silicon)
curl -LO https://github.com/naru-bot/watchdog/releases/latest/download/watchdog_darwin_arm64.tar.gz
tar xzf upp_darwin_arm64.tar.gz
sudo mv upp /usr/local/bin/
macOS (Intel)
curl -LO https://github.com/naru-bot/watchdog/releases/latest/download/watchdog_darwin_amd64.tar.gz
tar xzf upp_darwin_amd64.tar.gz
sudo mv upp /usr/local/bin/
Linux (x86_64)
curl -LO https://github.com/naru-bot/watchdog/releases/latest/download/watchdog_linux_amd64.tar.gz
tar xzf upp_linux_amd64.tar.gz
sudo mv upp /usr/local/bin/
Linux (ARM64)
curl -LO https://github.com/naru-bot/watchdog/releases/latest/download/watchdog_linux_arm64.tar.gz
tar xzf upp_linux_arm64.tar.gz
sudo mv upp /usr/local/bin/
Build from source
git clone https://github.com/naru-bot/watchdog.git
cd upp
make build
sudo mv upp /usr/local/bin/
Cross-compilation
make cross
# Produces: upp-darwin-arm64, upp-darwin-amd64, upp-linux-amd64, upp-linux-arm64
All Commands
| Command | Description |
|---|---|
init |
Initialize configuration file |
add <url> |
Add a URL to monitor |
remove <target> |
Remove a monitored target |
list / ls |
List all monitored targets |
check [target] |
Run checks (all or specific) |
status [target] |
Show uptime stats and summary |
view <target> |
Show full configuration for a target |
tui |
Interactive terminal dashboard |
watch |
Live auto-refreshing dashboard |
ping <url> |
Quick one-off check (no DB save) |
import <file> |
Bulk import targets from YAML |
diff <target> |
Show content changes between snapshots |
data <target> |
Show latest stored snapshot content |
extract <url> |
Fetch a URL and show extracted content |
history <target> |
Show check history |
pause <target> |
Pause monitoring |
unpause <target> |
Resume monitoring |
notify add|list|remove |
Manage notification channels |
export |
Export data as JSON or CSV |
daemon |
Run as background service |
doctor |
Check system dependencies (headless browser for visual checks) |
completion |
Generate shell completions (bash/zsh/fish/powershell) |
version |
Print version |
Global Flags
| Flag | Description |
|---|---|
--json |
Output in JSON format (all commands) |
--no-color |
Disable colored output |
-v, --verbose |
Verbose output |
-q, --quiet |
Suppress non-essential output |
Add command flags
upp add <url> [flags]
--name Target name (auto-generated from URL if omitted)
--type Check type: http, tcp, ping, dns, visual, whois (default: http)
--interval Check interval in seconds (default: 300)
--selector CSS selector for change detection (http type)
--expect Expected keyword in response body (http type)
--timeout Request timeout in seconds (default: 30)
--retries Retry count before marking as down (default: 1)
--threshold Visual diff threshold percentage (visual type, default: 5.0)
Configuration
upp init # Creates ~/.config/upp/config.yml
Config file location: ~/.config/upp/config.yml (or $XDG_CONFIG_HOME/upp/config.yml)
Full example
defaults:
interval: 300
type: http
timeout: 30
retry_count: 1
user_agent: upp/1.0
display:
color: true
format: table
verbose: false
thresholds:
ssl_warn_days: 30
headers:
Authorization: Bearer my-token
X-Custom: value
Reference
defaults β Default values for new targets
| Key | Type | Default | Description |
|---|---|---|---|
interval |
int | 300 |
Check interval in seconds. Applied to new targets when --interval is not specified. |
type |
string | http |
Default check type when --type is not specified. One of: http, tcp, ping, dns, visual, whois. |
timeout |
int | 30 |
HTTP/TCP request timeout in seconds. For visual checks, consider increasing to 60. |
retry_count |
int | 1 |
Number of retries before marking a target as down. Helps avoid false positives from transient failures. |
user_agent |
string | upp/1.0 |
User-Agent header sent with HTTP requests. Some sites block default Go user agents. |
display β Output formatting
| Key | Type | Default | Description |
|---|---|---|---|
color |
bool | true |
Enable colored output (status indicators, diffs, warnings). Disable for piping to files. Overridden by --no-color flag. |
format |
string | table |
Default output format: table, json, or compact. Overridden by --json flag. |
verbose |
bool | false |
Show additional detail in output (response headers, timing breakdown). Overridden by -v flag. |
thresholds β Warning thresholds
| Key | Type | Default | Description |
|---|---|---|---|
ssl_warn_days |
int | 30 |
Show SSL certificate expiry warning when days remaining is below this value. Certs with more days left are hidden from output. Red warning at half this value (e.g., <15 days at default). Set to 0 to always hide, or 365 to always show. |
headers β Custom HTTP headers
Key-value pairs added to every HTTP request. Useful for authentication tokens, custom identifiers, or bypassing certain WAF rules.
headers:
Authorization: Bearer my-api-token
Accept-Language: en-US
Data storage
All data lives in ~/.upp/upp.db (SQLite). Back up by copying the file, query with any SQLite client, or export via upp export.
Running as a Background Service
To run Upp in the background and survive reboots, set it up as a systemd service.
One-liner setup:
sudo tee /etc/systemd/system/upp-monitor.service << 'EOF'
[Unit]
Description=Upp Website Monitor
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/upp daemon
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now upp-monitor
Check status:
sudo systemctl status upp-monitor
View logs:
journalctl -u upp-monitor -f
Stop / restart:
sudo systemctl stop upp-monitor
sudo systemctl restart upp-monitor
Removing the Service
sudo systemctl stop upp-monitor
sudo systemctl disable upp-monitor
sudo rm /etc/systemd/system/upp-monitor.service
sudo systemctl daemon-reload
Uninstalling Upp
To completely remove Upp from your system:
# 1. Stop and remove the service (if running)
sudo systemctl stop upp-monitor
sudo systemctl disable upp-monitor
sudo rm /etc/systemd/system/upp-monitor.service
sudo systemctl daemon-reload
# 2. Remove the binary
sudo rm /usr/local/bin/upp
# Or if installed via go install:
rm $(go env GOPATH)/bin/upp
# 3. Remove data and config
rm -rf ~/.upp
rm -rf ~/.config/upp
Tech Stack
Built with some excellent Go libraries:
- Cobra β CLI framework
- Bubbletea + Bubbles + Lipgloss β TUI
- modernc.org/sqlite β Pure Go SQLite (zero CGO)
- goquery β HTML parsing
- Custom LCS-based line diff engine
Contributing
Contributions welcome! Open an issue or PR on GitHub.
git clone https://github.com/naru-bot/watchdog.git
cd upp
make build
# hack away
License
Documentation
ΒΆ
There is no documentation for this package.