NoirWatch monitors specified websites for changes and sends notifications. It supports various notification methods including Pushover and native desktop notifications.
- Monitor multiple websites for changes
- Send notifications via Pushover and native desktop notifications (macOS, Linux, Windows)
- Configurable check intervals
- Verbose logging with different log levels
- Background execution support
- Customizable configuration and URL list files
- Monitor multiple websites for changes
- Send notifications via Pushover
- Send notifications via native desktop notifications (macOS, Linux, Windows)
- Run as a background service
- Run a custom script on change detection
- Run the check a specific number of times and then exit
- Robust configuration using JSON which includes per URL options
- Output change averages for all urls
- Add averages to notifications
- Full historical average change report
- Add more notification methods (email, slack, discord, teams, Telegram etc.)
- Bash 4.3+ (macOS ships Bash 3.2; install a newer one with
brew install bash) curlfor fetching website contentjqfor reading the configuration filexmllint(libxml2) for extracting the text of web pagesdiff,sed,shasumandtimeoutfor comparing content and running commands- GNU
realpathon Linux, orgrealpathfrombrew install coreutilson macOS powershellfor Windows desktop notificationsnotify-sendfor Linux desktop notifications
-
Tap the repository (if not already tapped):
brew tap binarynoir/noirwatch
-
Install NoirWatch:
brew install noirwatch
-
Clone the repository:
git clone https://github.com/binarynoir/noirwatch.git cd noirwatch -
Make the script executable:
chmod +x noirwatch
-
Install
notify-sendfor desktop notifications (if not already installed) on Linux:# On Debian/Ubuntu-based systems sudo apt install libnotify-bin # On Fedora-based systems sudo dnf install libnotify # On Arch-based systems sudo pacman -S libnotify
-
Install Git for Windows (includes Git Bash, if not installed).
-
Clone the repository:
git clone https://github.com/binarynoir/noirwatch.git cd noirwatch -
Make the script executable (in Git Bash or similar terminal):
chmod +x noirwatch
-
Ensure PowerShell is enabled in your Git Bash environment for notifications.
-
Move the man file to the appropriate directory:
sudo mv noirwatch.1 /usr/local/share/man/man1/
-
Update the man database:
sudo mandb
-
View the man page:
man noirwatch
-
Create a systemd service file:
sudo nano /etc/systemd/system/noirwatch.service
-
Add the following content to the service file:
[Unit] Description=NoirWatch Service After=network.target [Service] ExecStart=/path/to/noirwatch WorkingDirectory=/path/to Restart=always User=your-username [Install] WantedBy=multi-user.target
Replace
/path/to/noirwatchwith the actual path to thenoirwatchscript andyour-usernamewith your actual username.Do not add
--starthere. systemd runs NoirWatch in the foreground and restarts it if it stops;--startwould detach it from systemd. Logs go to the journal (journalctl -u noirwatch) as well as the NoirWatch log file. -
Reload systemd to apply the new service:
sudo systemctl daemon-reload
-
Enable the service to start on boot:
sudo systemctl enable noirwatch -
Start the service:
sudo systemctl start noirwatch
-
Check the status of the service:
sudo systemctl status noirwatch
Run NoirWatch as a LaunchAgent so it runs as you, reads your configuration file, and can show desktop notifications.
-
Create a launchd plist file:
nano ~/Library/LaunchAgents/com.noirwatch.plist -
Add the following content to the plist file:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.noirwatch</string> <key>ProgramArguments</key> <array> <string>/path/to/noirwatch</string> </array> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string> </dict> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardErrorPath</key> <string>/tmp/noirwatch.launchd.log</string> </dict> </plist>
Replace
/path/to/noirwatchwith the actual path to thenoirwatchscript. Do not add--start; launchd keeps NoirWatch running in the foreground. ThePATHentry lets launchd find Homebrew's Bash, because macOS's built-in Bash 3.2 cannot run NoirWatch. -
Load the plist file to start the service:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.noirwatch.plist
-
Check the status of the service:
launchctl print gui/$(id -u)/com.noirwatch | grep state
-
To unload the service:
launchctl bootout gui/$(id -u)/com.noirwatch
-
Create a Task in Task Scheduler:
- Open Task Scheduler and select "Create Task".
- In the "General" tab, name the task "NoirWatch" and select "Run whether user is logged on or not".
- In the "Triggers" tab, click "New" and set the trigger to "At startup".
- In the "Actions" tab, click "New" and set the action to "Start a program".
- In the "Program/script" field, enter the path to
bash.exe(usually located inC:\Program Files\Git\bin\bash.exeif using Git Bash). - In the "Add arguments (optional)" field, enter the path to the
noirwatchscript and the--startargument, e.g.,/path/to/noirwatch --start.
- In the "Program/script" field, enter the path to
- In the "Conditions" tab, uncheck "Start the task only if the computer is on AC power" to ensure it runs on battery power as well.
- In the "Settings" tab, ensure "Allow task to be run on demand" is checked.
-
Save and Test the Task:
- Click "OK" to save the task.
- To test the task, right-click on the "NoirWatch" task in Task Scheduler and select "Run".
-
Verify the Task:
- Check the status of the task in Task Scheduler to ensure it is running.
- Verify that NoirWatch is running by checking the log file or the expected notifications.
Run the script with the desired options. Below are some examples:
-
Monitor a single URL:
./noirwatch https://example.com
-
Monitor every URL listed under
urlsin the configuration file:./noirwatch
-
Override the change threshold for one URL (here, 15%):
./noirwatch '[15]https://example.com' -
Run the script in the background, check on it, and stop it:
./noirwatch --start ./noirwatch --status ./noirwatch --stop
-
Send Pushover notifications:
./noirwatch -p -a YOUR_API_TOKEN -u YOUR_USER_KEY https://example.com
NoirWatch uses a configuration file to store default settings. The default location is ~/.config/noirwatch.json on macOS and Linux, and %APPDATA%\noirwatch.json on Windows. You can initialize a configuration file with default settings using:
./noirwatch --init{
"configuration": {
"CACHE_DIR": "/tmp/noirwatch_cache",
"LOG_FILE": "/tmp/noirwatch_cache/noirwatch.log",
"CHECK_INTERVAL": "60s",
"TIMEOUT": "5s",
"SYSTEM_NAME": "Test System",
"PUSHOVER_NOTIFICATION": "false",
"PUSHOVER_USER_KEY": "",
"PUSHOVER_API_TOKEN": "",
"DESKTOP_NOTIFICATION": "false",
"VERBOSE": "true",
"LOG_LEVEL": "DEBUG",
"THRESHOLD": "0"
},
"urls": {
"default": [
{
"NAME": "Apple Newsroom",
"URL": "https://www.apple.com/newsroom/",
"TIMEOUT": "5s",
"THRESHOLD": "1",
"UPDATED_CMD": "./test/test_cmd.sh",
"CMD_TIMEOUT": "5s"
},
{
"NAME": "9to5mac Homepage",
"URL": "https://9to5mac.com",
"TIMEOUT": "10s",
"THRESHOLD": "5",
"UPDATED_CMD": "./test/test_cmd.sh",
"CMD_TIMEOUT": "5s"
}
]
}
}--initcreates the configuration file so only your user can read it, because it can hold your Pushover keys. Keep it out of version control.- Settings given on the command line override the configuration file.
- Unknown keys in the
configurationsection are ignored with a warning, so a typo cannot change unrelated settings. CHECK_INTERVALandTIMEOUTtake a whole number with an optionals,m,hordsuffix, such as30sor5m.- The cache directory must belong to your user. NoirWatch refuses to use system directories, your home directory, or a directory owned by someone else.
-h, --help: Display the help message.-V, --version: Display the script version.
-c, --config <config_file>: Specify a custom configuration file.-i, --init: Initialize the configuration file.-f, --force-init: Force initialize the configuration file if one exists.-S, --show-config: Show the configuration settings.-e, --show-config-file: Show the configuration file.-E, --edit-config: Edit the configuration file.
-x, --clean: Delete all cached files.-C, --cache-dir <path>: Specify a custom cache directory.
-n, --system-name <name>: Name of the system running the script.-p, --pushover: Send Pushover notifications.-u, --user-key <key>: Specify the user key for Pushover notifications.-a, --api-token <token>: Specify the API token for Pushover notifications.-d, --desktop: Send native desktop notifications (macOS, Linux and Windows).
-v, --verbose: Enable verbose output.-l, --log: Log the log file to the screen.-o, --output <file>: Specify a custom log file location.-L, --log-level <level>: Set the log level (FATAL, ERROR, WARN, INFO, DEBUG).
-I, --interval <s,m,h,d>: Set the interval between checks, such as90sor15m(default: 60 seconds).-T, --timeout <s,m,h,d>: Set the connection timeout for each request (default: 5 seconds).-N, --repeat <number>: Run the checks this many times, then exit (default: 0, which runs until stopped).-H, --threshold <percentage>: Set the percentage of a page that must change before you are notified. Higher values mean fewer notifications for minor changes (default: 0%).-U, --list-urls: List all watched URLs.
-s, --start: Start the NoirWatch service in the background.-k, --stop: Stop the NoirWatch service.-r, --restart: Restart the NoirWatch service.-t, --status: Check the current status of the NoirWatch service. Exits with code 0 when it is running and 3 when it is stopped.
This guide provides step-by-step instructions to deploy the NoirWatch service using Docker.
Ensure you have the following installed on your system:
- Docker
Clone the repository, then build the image from the repository root. The image contains the noirwatch script from your checkout and runs it as an unprivileged user.
git clone https://github.com/binarynoir/noirwatch.git
cd noirwatch
docker build -t noirwatch-image .
docker run -d --restart unless-stopped --name noirwatch noirwatch-imageThe image creates a default configuration at /app/noirwatch.json. To use your own, mount it over that file:
docker run -d --restart unless-stopped --name noirwatch \
-v "$PWD/noirwatch.json:/app/noirwatch.json:ro" noirwatch-imageNoirWatch runs in the foreground, so docker logs noirwatch shows its output and docker stop noirwatch shuts it down cleanly. Arguments after the image name are passed to NoirWatch, for example docker run --rm noirwatch-image --show-config.
The tests run offline against local test servers, so they do not depend on outside websites.
- Bash 4.3+ and the dependencies listed under Requirements
python3for the local test web servershellcheckto lint the scripts (optional)
From the repository root:
./test/test.shThe script prints ok or FAIL for each check and exits with a non-zero status if any check fails. It works in a temporary directory and removes everything it creates when it exits.
To lint the scripts:
shellcheck -s bash noirwatch test/*.sh scripts/*.shGitHub Actions runs the linter and the tests on Linux and macOS for every push and pull request.
-
Update
VERSIONandLAST_UPDATEDin thenoirwatchscript. -
Add an entry for the new version to
CHANGELOG.md. -
Commit the changes and merge them to
main. -
Run the release script from the repository root:
./scripts/publish-release.sh
The script checks that the working tree is clean, that you are on main, and that the changelog has an entry for the version. It then tags the version and pushes the tag. The tag starts the release workflow, which runs CI, checks that the tag matches VERSION, creates the GitHub release, and updates the Homebrew formula.
This project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
John Smith III
Thanks to all contributors and users for their support and feedback.