Skip to main content

pagemon

Monitor web pages for changes from your terminal.

PyPI version Python versions License: MIT CI

Why pagemon?

  • CLI-first -- designed for developers who live in the terminal
  • Lightweight -- pure Python, no Docker, no browser engine, no background daemon
  • Smart diffing -- strips HTML noise (scripts, nav, timestamps) so you only see real content changes
  • CSS selectors -- watch a specific element instead of the whole page
  • Webhook notifications -- POST JSON to Slack, Discord, or any HTTP endpoint when something changes
  • Zero config -- works out of the box with sensible defaults and a local SQLite database

Features

  • Add, remove, and list monitored URLs
  • Check one or all targets for changes on demand
  • CSS selector support to monitor specific page elements
  • Colored unified diffs in the terminal (via Rich)
  • Snapshot history with content hashes
  • Smart noise filtering (whitespace, timestamps, dates)
  • Webhook notifications on change (Slack, Discord, custom)
  • JSON and CSV export
  • JSON output mode for scripting (--json)
  • Python API for programmatic use
  • SQLite storage -- single file, no server needed

Installation

pip install pagemon

Requires Python 3.10+.

Quick Start

Add a page to monitor:

$ pagemon add https://example.com/pricing --name "Pricing Page" --interval 60
Added: https://example.com/pricing
  Selector: -
  Interval: every 60m

Monitor a specific element with a CSS selector:

$ pagemon add https://example.com/status --name "Status" --selector "div.status-banner"
Added: https://example.com/status
  Selector: div.status-banner
  Interval: every 30m

Check all targets for changes:

$ pagemon check --all
  NEW      Pricing Page
  NEW      Status

After subsequent checks, changed pages show a diff:

$ pagemon check --all
  OK       Pricing Page
  CHANGED  Status
--- previous
+++ current
@@ -1,3 +1,3 @@
-All systems operational
+Degraded performance on API endpoints

List monitored pages:

$ pagemon ls
        Monitored Pages
┌────┬──────────────┬────────────────────┬──────────┐
│ ID │ Name / URL   │ Selector           │ Interval │
├────┼──────────────┼────────────────────┼──────────┤
│  1 │ Pricing Page │ -                  │      60m │
│  2 │ Status       │ div.status-banner  │      30m │
└────┴──────────────┴────────────────────┴──────────┘

View snapshot history:

$ pagemon history https://example.com/status --limit 5
           History: https://example.com/status
┌────┬─────────────────────┬──────────────┬────────┬───────┐
│ ID │ Timestamp           │ Hash         │ Status │  Size │
├────┼─────────────────────┼──────────────┼────────┼───────┤
│  3 │ 2026-03-29T14:30:00 │ a1b2c3d4e5f6 │    200 │   482 │
│  2 │ 2026-03-29T14:00:00 │ f6e5d4c3b2a1 │    200 │   471 │
│  1 │ 2026-03-29T13:30:00 │ 9e8d7c6b5a4f │    200 │   471 │
└────┴─────────────────────┴──────────────┴────────┴───────┘

CLI Reference

pagemon [OPTIONS] COMMAND [ARGS]

pagemon add URL

Add a URL to monitor.

Option Short Default Description
--name -n -- Friendly name for display
--selector -s -- CSS selector to watch a specific element
--interval -i 30 Check interval in minutes

pagemon rm URL

Remove a URL from monitoring.

pagemon ls

List all monitored URLs.

Option Description
--json Output as JSON

pagemon check [URL]

Check for changes. Checks a single URL, or all targets if no URL is given.

Option Short Description
--all -- Check all targets
--json -- Output as JSON
--webhook -w Webhook URL for notifications (or set PAGEMON_WEBHOOK)

pagemon diff URL

Show the latest diff between the two most recent snapshots for a URL.

pagemon history URL

Show snapshot history for a URL.

Option Short Default Description
--limit -l 10 Number of snapshots to show

pagemon export

Export all targets and their latest snapshots.

Option Default Description
--format json Output format: json or csv

pagemon --version

Print the installed version.

Python API

from pathlib import Path
from pagemon.core import PageMon

# Initialize with defaults (SQLite at ~/.pagemon/pagemon.db)
mon = PageMon()

# Or with custom settings
mon = PageMon(
    db_path=Path("/tmp/my-monitor.db"),
    webhook_url="https://hooks.slack.com/services/T.../B.../xxx",
    timeout=15.0,
)

# Add a target
target = mon.add(
    "https://example.com/pricing",
    name="Pricing",
    selector="div.pricing-table",
    interval=60,
)

# Check all targets
results = mon.check_all()
for result in results:
    print(f"{result.target.url}: {result.status.value}")
    if result.diff_text:
        print(result.diff_text)

# Check a single target
result = mon.check(target)

# Get snapshot history
snapshots = mon.get_history("https://example.com/pricing", limit=5)

# Get the latest diff
diff = mon.get_diff("https://example.com/pricing")

# List all targets
targets = mon.list_targets()

# Remove a target
mon.remove("https://example.com/pricing")

# Always close when done
mon.close()

Configuration

pagemon works with zero configuration. All settings can be overridden via environment variables or CLI options.

Variable CLI Option Default Description
PAGEMON_DB --db ~/.pagemon/pagemon.db Path to the SQLite database
PAGEMON_WEBHOOK --webhook / -w -- Webhook URL for POST notifications

The webhook sends a JSON payload on every detected change:

{
  "url": "https://example.com/status",
  "name": "Status",
  "status": "changed",
  "diff": "--- previous\n+++ current\n@@ ...",
  "timestamp": "2026-03-29T14:30:00.000000"
}

How It Works

pagemon follows a simple pipeline for each monitored URL:

Fetch --> Extract --> Diff --> Notify
  1. Fetch -- HTTP GET via httpx with configurable timeout and custom headers
  2. Extract -- HTML is parsed with BeautifulSoup; scripts, styles, nav, and footer elements are stripped. If a CSS selector is set, only matching elements are extracted
  3. Diff -- Content is hashed (SHA-256) for fast comparison. If the hash differs, a normalization pass filters out whitespace and timestamp noise. Only meaningful changes produce a unified diff
  4. Notify -- Changed results are sent to the configured webhook (or printed to the console)

All snapshots are stored in a local SQLite database for history and diffing.

Contributing

Contributions are welcome. To get started:

git clone https://github.com/Ltbltbltbltb/pagemon.git
cd pagemon
pip install -e ".[dev]"
pytest
ruff check src/ tests/

Please open an issue before submitting large changes.

License

MIT -- see LICENSE for details.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pagemon-0.1.0.tar.gz (20.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pagemon-0.1.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file pagemon-0.1.0.tar.gz.

File metadata

  • Download URL: pagemon-0.1.0.tar.gz
  • Upload date:
  • Size: 20.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pagemon-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ceeac846f447091b75f3d2420e12ed270cb6742fad165712681ed591781629f9
MD5 8a4ddbcb7352bc92a2b166c1dc30616b
BLAKE2b-256 ccb931b064194b148d777c8a8465c44f8fc9d51bf338089fda20fcfec8cf531b

See more details on using hashes here.

File details

Details for the file pagemon-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pagemon-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pagemon-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2182b01d80aafde305fe8647332c8218ec33b0e0ac8b2329f94cff18b23f2ede
MD5 89b3411a1dab4fb9e472f630e2b37552
BLAKE2b-256 9ef8cf7e9ef7475ce60226e80f4cc332b2c9c1708125418ab611de698a5e1fe1

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page