CameraWatch monitors webcam activity and sends webhook notifications when the camera starts or stops. It is designed for Home Assistant automations such as turning a home-office busy light on and off.
The repository includes:
- Windows support in
windows/through PowerShell and Task Scheduler - macOS support in
macos/through a Swift watcher and a per-user LaunchAgent - Optional macOS Shortcut triggers for camera activity
macos/contains the macOS watcher, installer, and uninstaller.windows/contains the Windows watcher, installer, uninstaller, and background launcher.
CameraWatch sends JSON payloads with the same shape on both platforms:
Camera active:
{
"user": "YourUsername",
"processes": "process1,process2"
}Camera inactive:
{
"user": "YourUsername",
"processes": ""
}On Windows, processes contains active webcam registry entries. On macOS, supported public APIs expose camera device usage, not owning app processes, so processes contains comma-separated active camera device names such as MacBook Pro Camera.
Expand
- macOS 12 or later
- Apple Command Line Tools
- Optional: Shortcuts configured for camera activity triggers
Install Command Line Tools if needed:
xcode-select --installThe macOS watcher uses CoreMediaIO to enumerate camera devices and checks whether each device is running anywhere on the system. It polls every 15 seconds by default. On state changes, it sends direct webhooks to Home Assistant.
Shortcut triggers are optional. When enabled, CameraWatch runs one Shortcut when the camera becomes active and another when the camera becomes inactive. Those Shortcuts can perform any automation, such as turning a macOS Focus mode on and off:
flowchart LR
A((Camera activity)) -->B[Swift watcher]
B -. optional.-> C(Shortcut triggers)
B --> D(Webhooks)
For guided setup, run:
./macos/Install-CameraWatch.shThe installer prompts for Home Assistant webhook URLs, poll interval, optional Shortcut triggers, and whether to start immediately. On reinstall, pressing Enter keeps existing settings; enter - at a webhook prompt to remove that URL. Guided setup requires an interactive terminal.
For scripted or non-interactive installation without Shortcut triggers:
./macos/Install-CameraWatch.sh \
--webhook-url "https://your-homeassistant-url/api/webhook/on-id" \
--webhook-url-sign-off "https://your-homeassistant-url/api/webhook/off-id" \
--non-interactiveFor scripted installation with existing Shortcuts, pass their names or identifiers:
./macos/Install-CameraWatch.sh \
--webhook-url "https://your-homeassistant-url/api/webhook/on-id" \
--webhook-url-sign-off "https://your-homeassistant-url/api/webhook/off-id" \
--camera-active-shortcut "CameraWatch Camera Active" \
--camera-inactive-shortcut "CameraWatch Camera Inactive" \
--non-interactiveThe installer compiles the Swift watcher, writes configuration, creates a LaunchAgent, and starts CameraWatch immediately by default.
Create two Shortcuts in the Shortcuts app. They can run any actions needed for camera activity. For example, to control macOS Focus:
CameraWatch Camera Active: use the "Set Focus" action to turn your chosen Focus on until turned off.CameraWatch Camera Inactive: use the "Set Focus" action to turn the same Focus off.
When Shortcut triggers are enabled, the installer validates that both Shortcuts exist. Use --skip-shortcut-check if you want to install first and create the Shortcuts later.
Passing either --camera-active-shortcut or --camera-inactive-shortcut also enables Shortcut triggers automatically. Existing installations using the earlier Focus-named config keys or installer flags remain supported.
Use --interactive together with selected options to prompt only for remaining settings, or --non-interactive to suppress prompts when running from automation.
Config is stored at:
~/Library/Application Support/CameraWatch/config.json
Example:
{
"WebhookUrl": "https://your-homeassistant-url/api/webhook/on-id",
"WebhookUrlSignOff": "https://your-homeassistant-url/api/webhook/off-id",
"PollIntervalSeconds": 15,
"ShortcutTriggersEnabled": false,
"CameraActiveShortcut": "CameraWatch Camera Active",
"CameraInactiveShortcut": "CameraWatch Camera Inactive",
"ShortcutTimeoutSeconds": 20
}Logs are stored at:
~/Library/Logs/CameraWatch/CameraWatch.log
Check status:
launchctl print gui/$UID/com.camerawatch.agentRestart:
launchctl kickstart -k gui/$UID/com.camerawatch.agentStop and unload:
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.camerawatch.agent.plistView logs:
tail -f ~/Library/Logs/CameraWatch/CameraWatch.logRun one dry check manually:
"$HOME/Library/Application Support/CameraWatch/camerawatch" --once --dry-runTest webhooks or Shortcut triggers:
"$HOME/Library/Application Support/CameraWatch/camerawatch" --test-notification on --dry-run
"$HOME/Library/Application Support/CameraWatch/camerawatch" --test-notification off --dry-run
"$HOME/Library/Application Support/CameraWatch/camerawatch" --test-shortcut on --dry-run
"$HOME/Library/Application Support/CameraWatch/camerawatch" --test-shortcut off --dry-runRemove the LaunchAgent and installed watcher binary:
./macos/Uninstall-CameraWatch.shAlso remove configuration and logs:
./macos/Uninstall-CameraWatch.sh --remove-configExpand
- Windows 10 or later
- PowerShell 5.1 or later
- Permissions to create scheduled tasks; Administrator is recommended but not required
The Windows script monitors the registry key that tracks webcam usage:
HKEY_USERS\{SID}\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam
It polls this registry location every 15 seconds. When a state change is detected, it sends a POST request to the configured webhook URL.
Open PowerShell, navigate to the repository, and run:
.\windows\Install-CameraWatch.ps1With webhook URLs:
.\windows\Install-CameraWatch.ps1 `
-WebhookUrl "https://your-homeassistant-url/api/webhook/on-id" `
-WebhookUrlSignOff "https://your-homeassistant-url/api/webhook/off-id"The script creates a scheduled task that runs automatically when you log in.
Config is stored at:
%LOCALAPPDATA%\CameraWatch\config.json
Example:
{
"WebhookUrl": "https://your-homeassistant-url/api/webhook/on-id",
"WebhookUrlSignOff": "https://your-homeassistant-url/api/webhook/off-id"
}Logs are stored at:
%LOCALAPPDATA%\CameraWatch\CameraWatch.log
Check status:
Get-ScheduledTask -TaskName "CameraWatch" -TaskPath "\CameraWatch\" | Get-ScheduledTaskInfoStart:
Start-ScheduledTask -TaskName "CameraWatch" -TaskPath "\CameraWatch\"Stop:
Stop-ScheduledTask -TaskName "CameraWatch" -TaskPath "\CameraWatch\"View logs:
Get-Content "$env:LOCALAPPDATA\CameraWatch\CameraWatch.log" -Tail 50.\windows\Uninstall-CameraWatch.ps1Also remove configuration and logs:
.\windows\Uninstall-CameraWatch.ps1 -RemoveConfig- Create one webhook trigger for camera active and one webhook trigger for camera inactive.
- Configure CameraWatch with both webhook URLs.
- Use the active webhook to turn on a busy indicator.
- Use the inactive webhook to turn it off.
- Check the LaunchAgent status with
launchctl print gui/$UID/com.camerawatch.agent. - Check
~/Library/Logs/CameraWatch/CameraWatch.log. - Re-run the installer after installing Command Line Tools.
- Confirm both Shortcuts exist with
shortcuts list --show-identifiers. - Run the test commands with
--test-shortcut onand--test-shortcut off. - macOS may ask for permission the first time a LaunchAgent runs Shortcuts.
- Verify the webhook URLs in the config file.
- Check logs for redacted webhook attempts and HTTP errors.
- Test the webhook URL manually with
curlor Postman.
- On Windows, confirm the webcam uses the standard Windows camera APIs.
- On macOS, confirm the camera is exposed through CoreMediaIO.