A plugin for UI Toolkit by Crosstalk Solutions that adds UniFi Access (physical door events) and UniFi Protect (camera/motion events) logging, correlated into a unified dashboard.
Not affiliated with Ubiquiti Inc. UniFi is a trademark of Ubiquiti Inc.
UI Toolkit already covers UniFi Network (Wi-Fi Stalker, Threat Watch, Network Pulse). This plugin fills the gap:
| Source | Events Captured |
|---|---|
| UniFi Access | Door open/close, badge granted/denied, door held open, remote unlock |
| UniFi Protect | Motion detection, person/vehicle/package smart detect, doorbell ring, recording events |
Plus a cross-source correlation engine β find Access + Protect events that occur within the same 60-second window (e.g. someone badges in and triggers a camera simultaneously).
- πͺ Access event logging β who badged in/out, where, and when
- πΉ Protect event logging β motion, smart detections, doorbell rings
- π Event correlation β cross-source events within configurable time windows
- π Outbound webhooks β Slack, Discord, or generic JSON alerts per event type
- π Live dashboard β dark-themed, auto-refreshing, filterable event table
- π€ OpenClaw skill β AI agent queries physical presence context
- π Webhook signature verification β HMAC-SHA256 validation of UniFi payloads
UniFi Access βββΊ POST /activity/webhooks/access βββ
UniFi Protect βββΊ POST /activity/webhooks/protect βββΌβββΊ SQLite βββΊ Dashboard + Query API
β
ββββΊ Slack / Discord alerts
ββββΊ OpenClaw AI agent context
Public access is handled by either:
- Cloudflare Tunnel β no VPS or firewall changes needed (recommended)
- VPS + Tailscale β Nginx reverse proxy over Tailscale mesh VPN
- UI Toolkit installed and running
- UniFi Access hub and/or UniFi Protect cameras on your network
- Docker + Docker Compose
# From your unifi-toolkit directory:
cp -r activity_log tools/
cp -r activity_log/templates/activity_log app/templates/
cp alembic_migration.py alembic/versions/xxxx_add_activity_log_tables.pyEdit alembic/versions/xxxx_add_activity_log_tables.py and set down_revision to your current Alembic head:
docker compose exec unifi-toolkit alembic currentfrom tools.activity_log.router import register as register_activity_log
from shared.database import get_db
register_activity_log(app, get_db, templates)from tools.activity_log import __version__ as activity_log_version
# ...
print(f" - Activity Log v{activity_log_version}")docker compose restart
docker compose exec unifi-toolkit alembic upgrade headDashboard at: http://localhost:8000/activity/
UniFi controllers need to POST events to your machine. Two options:
# Install cloudflared, then:
cloudflared tunnel login
cloudflared tunnel create unifi-toolkit
cloudflared tunnel route dns unifi-toolkit webhooks.yourdomain.com
# Copy cloudflare/cloudflared-config.yml and edit with your tunnel UUID
sudo cp cloudflare/cloudflared-config.yml /etc/cloudflared/config.yml
sudo cloudflared service install && sudo systemctl start cloudflared# On local machine AND VPS:
curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up
# On VPS β install Nginx, copy config, get SSL cert:
sudo apt install nginx certbot python3-certbot-nginx
sudo cp tailscale/nginx-vps.conf /etc/nginx/sites-available/unifi-toolkit
# Edit nginx-vps.conf: replace 100.x.x.x with your local machine's Tailscale IP
sudo ln -s /etc/nginx/sites-available/unifi-toolkit /etc/nginx/sites-enabled/
sudo certbot --nginx -d toolkit.yourdomain.comSee INTEGRATION.md and the Deployment Guide for full step-by-step instructions.
- Settings β Integrations β Webhooks β + Add
- URL:
https://webhooks.yourdomain.com/activity/webhooks/access - Enable: Access Granted, Access Denied, Door Unlock, Door Open, Door Held Open
- Copy signing secret β
.env:WEBHOOK_SECRET_ACCESS=your_secret
- Settings β Notifications β Webhooks β + Add
- URL:
https://webhooks.yourdomain.com/activity/webhooks/protect - Enable: Motion, Smart Detection, Doorbell Ring
- Copy signing secret β
.env:WEBHOOK_SECRET_PROTECT=your_secret
Restart after adding secrets: docker compose restart
Gives your OpenClaw AI agents real-world physical presence context.
# Install the skill
cp -r openclaw-skill ~/.openclaw/skills/unifi-activity-logConfigure in ~/.openclaw/openclaw.json:
{
"skills": {
"entries": {
"unifi-activity-log": {
"apiKey": "https://toolkit.yourdomain.com"
}
}
}
}Agent queries it understands:
- "Who has been in the building today?"
- "Were there any access denied events in the last hour?"
- "Give me a security briefing"
- "Did the front camera detect anyone after 6pm?"
Skill scripts:
uv run openclaw-skill/scripts/check_health.py
uv run openclaw-skill/scripts/query_events.py --source access --hours 24
uv run openclaw-skill/scripts/security_brief.py| Endpoint | Method | Description |
|---|---|---|
/activity/ |
GET | Live dashboard |
/activity/api/events |
GET | Query events (filters: source, action, user_id, location, since, until) |
/activity/api/events/summary |
GET | 24h stats + top users |
/activity/api/events/correlate |
GET | Cross-source events within time window |
/activity/api/settings |
GET/POST | Webhook notification config |
/activity/api/health |
GET | Health check |
/activity/webhooks/access |
POST | UniFi Access webhook receiver |
/activity/webhooks/protect |
POST | UniFi Protect webhook receiver |
βββ activity_log/ # The tool β copy to tools/ in UI Toolkit
β βββ __init__.py
β βββ models.py # SQLAlchemy models
β βββ normalizers.py # Access & Protect payload normalizers
β βββ notifications.py # Outbound Slack/Discord webhooks
β βββ router.py # FastAPI endpoints
β βββ templates/
β βββ activity_log/
β βββ index.html # Dashboard
βββ openclaw-skill/ # OpenClaw AI agent skill
β βββ SKILL.md
β βββ scripts/
β βββ query_events.py
β βββ security_brief.py
β βββ check_health.py
βββ cloudflare/
β βββ cloudflared-config.yml # Cloudflare Tunnel config
β βββ cloudflared.service # systemd service
βββ tailscale/
β βββ setup-tailscale.sh # Tailscale install script
β βββ nginx-vps.conf # Nginx reverse proxy config
β βββ nginx-rate-limits.conf
βββ alembic_migration.py # DB migration β copy to alembic/versions/
βββ INTEGRATION.md # Detailed integration instructions
βββ README.md
No events appearing after webhook test:
docker compose logs -f | grep activity
curl https://webhooks.yourdomain.com/activity/api/healthHTTP 401 on webhook POST: Webhook secret mismatch β verify WEBHOOK_SECRET_ACCESS in .env matches what UniFi shows.
Migration errors:
docker compose exec unifi-toolkit alembic current
docker compose exec unifi-toolkit alembic stamp head # if schema already existsCloudflare tunnel not connecting:
sudo journalctl -u cloudflared -n 50
cloudflared tunnel info unifi-toolkitMIT β see LICENSE
Built as a plugin for UI Toolkit by Crosstalk Solutions.