tutorial

Monitoring Kometa (Plex Meta Manager) with Vigilmon

Kometa automates Plex metadata and collection management — but long-running update cycles, Plex API timeouts, and silent scheduling failures can leave your library stale for days without anyone noticing. Here's how to monitor Kometa run health, Plex API connectivity, metadata update cycles, and scheduling execution with Vigilmon.

Kometa (formerly Plex Meta Manager) is a Python-based automation tool that connects to your Plex Media Server and applies metadata overlays, collection definitions, playlist rules, and library operations based on YAML configuration files. It runs on a schedule — typically once daily — and each run can take hours to complete against a large library. When a run silently fails halfway through (due to a Plex API timeout, a MDBList rate limit, or a YAML config error), your collections partially update and the next scheduled run may never trigger because the prior run process is still hanging. Without external monitoring, these failures are invisible until a user notices that "Top Rated" contains films from 2022 or a collection's poster never refreshed. Vigilmon lets you track Kometa run health and completion, Plex API reachability, metadata update cycle timing, and scheduler execution so your library metadata stays current and you know immediately when automation breaks.

What You'll Set Up

  • Kometa process health and run completion via cron heartbeats
  • Plex API connectivity monitoring
  • Metadata update cycle timing checks
  • Scheduler execution tracking
  • Web UI availability (port 9000, if enabled)

Prerequisites

  • Kometa 2.0+ running as a systemd service, Docker container, or scheduled cron job
  • Plex Media Server accessible from the Kometa host
  • Plex token available (X-Plex-Token)
  • A free Vigilmon account

Step 1: Monitor Kometa Run Completion

Kometa runs are not daemon-style — Kometa starts, processes all configured libraries, and exits. A failed run either exits with a non-zero code or hangs indefinitely waiting on a stalled API call. Monitor run completion rather than process presence:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to 26 hours (slightly longer than your daily run interval to account for variable run duration).
  3. Copy the heartbeat URL (e.g., https://vigilmon.online/heartbeat/abc123).

Wrap the Kometa invocation in a script that pings Vigilmon only on successful completion:

#!/bin/bash
# /usr/local/bin/kometa-run.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
KOMETA_DIR="/opt/kometa"
LOG_FILE="/var/log/kometa/run.log"
TIMEOUT_HOURS=6   # Kill run if it exceeds 6 hours

mkdir -p "$(dirname "$LOG_FILE")"

echo "[$(date)] Starting Kometa run" >> "$LOG_FILE"

# Run Kometa with a timeout guard
timeout "${TIMEOUT_HOURS}h" python3 "${KOMETA_DIR}/kometa.py" \
  --config "${KOMETA_DIR}/config/config.yml" \
  --run \
  >> "$LOG_FILE" 2>&1

EXIT_CODE=$?

if [ "$EXIT_CODE" -eq 0 ]; then
  echo "[$(date)] Kometa run completed successfully" >> "$LOG_FILE"
  curl -s "$HEARTBEAT_URL"
elif [ "$EXIT_CODE" -eq 124 ]; then
  echo "[$(date)] Kometa run timed out after ${TIMEOUT_HOURS}h" >> "$LOG_FILE"
  exit 1
else
  echo "[$(date)] Kometa run failed (exit $EXIT_CODE)" >> "$LOG_FILE"
  exit 1
fi

For Docker deployments:

#!/bin/bash
HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"

docker run --rm \
  -v /opt/kometa/config:/config \
  -e "KOMETA_CONFIG=/config/config.yml" \
  -e "KOMETA_RUN=true" \
  --name kometa-run \
  kometateam/kometa:latest

if [ $? -eq 0 ]; then
  curl -s "$HEARTBEAT_URL"
fi

Schedule this script from cron instead of calling Kometa directly:

# Run Kometa daily at 4am; heartbeat on success
0 4 * * * /usr/local/bin/kometa-run.sh

Step 2: Monitor Plex API Connectivity

Kometa's entire workflow depends on Plex API access. When Plex is restarted for an update, the database is being rebuilt after a library scan, or the Plex token expires, Kometa can't read or write any library metadata. Monitor Plex connectivity independently so you can distinguish "Kometa failed" from "Plex is unreachable":

#!/bin/bash
# /usr/local/bin/kometa-plex-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
PLEX_URL="http://localhost:32400"    # Adjust for your Plex host
PLEX_TOKEN="your-plex-token"
TIMEOUT=15

# Check Plex identity endpoint
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  -H "X-Plex-Token: ${PLEX_TOKEN}" \
  "${PLEX_URL}/identity")

if [ "$HTTP_CODE" != "200" ]; then
  echo "Plex API unreachable (HTTP $HTTP_CODE)"
  exit 1
fi

# Verify library sections are accessible
SECTIONS_RESP=$(curl -s \
  --max-time "$TIMEOUT" \
  -H "X-Plex-Token: ${PLEX_TOKEN}" \
  -H "Accept: application/json" \
  "${PLEX_URL}/library/sections")

SECTION_COUNT=$(echo "$SECTIONS_RESP" | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(data.get('MediaContainer', {}).get('size', 0))
" 2>/dev/null || echo 0)

if [ "$SECTION_COUNT" -eq 0 ]; then
  echo "Plex returned 0 library sections — API may be degraded"
  exit 1
fi

echo "Plex API OK: $SECTION_COUNT library sections accessible"
curl -s "$HEARTBEAT_URL"

Install as a cron job:

chmod +x /usr/local/bin/kometa-plex-check.sh
(crontab -l 2>/dev/null; echo "*/10 * * * * /usr/local/bin/kometa-plex-check.sh >> /var/log/kometa-plex.log 2>&1") | crontab -

Set the Vigilmon heartbeat to 15 minutes. Plex API outages longer than 15 minutes will cause the next Kometa run to fail entirely.


Step 3: Monitor Metadata Update Cycle Timing

Kometa's runs take variable amounts of time — a library with 5,000 items and complex collection rules can take 3–4 hours. Track that runs are completing within an acceptable window and that cycles aren't drifting later and later (a sign of growing metadata debt or slowing Plex responses):

#!/bin/bash
# /usr/local/bin/kometa-cycle-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
LOG_FILE="/var/log/kometa/run.log"
MAX_HOURS_SINCE_COMPLETION=28   # Alert if no successful run in 28 hours
MAX_RUN_DURATION_HOURS=8        # Alert if last run took more than 8 hours

if [ ! -f "$LOG_FILE" ]; then
  echo "Kometa log file not found at $LOG_FILE"
  exit 1
fi

# Find last successful completion
LAST_SUCCESS_LINE=$(grep -E "Kometa run completed successfully|Run Finished" "$LOG_FILE" | tail -1)

if [ -z "$LAST_SUCCESS_LINE" ]; then
  echo "No successful Kometa run found in log"
  exit 1
fi

# Extract timestamp
LAST_SUCCESS_TIME=$(echo "$LAST_SUCCESS_LINE" | grep -oP '\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}' | head -1 || \
                    echo "$LAST_SUCCESS_LINE" | grep -oP '\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\]' | tr -d '[]' | head -1)

if [ -z "$LAST_SUCCESS_TIME" ]; then
  echo "Could not parse completion timestamp"
  exit 1
fi

SUCCESS_EPOCH=$(date -d "$LAST_SUCCESS_TIME" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
HOURS_AGO=$(( (NOW_EPOCH - SUCCESS_EPOCH) / 3600 ))

if [ "$HOURS_AGO" -gt "$MAX_HOURS_SINCE_COMPLETION" ]; then
  echo "Last successful Kometa run was ${HOURS_AGO}h ago (threshold: ${MAX_HOURS_SINCE_COMPLETION}h)"
  exit 1
fi

echo "Last successful run ${HOURS_AGO}h ago (OK)"
curl -s "$HEARTBEAT_URL"

Run this check every hour. A missed cycle (no heartbeat for 28 hours) triggers an alert before the second cycle would have been missed, giving you time to investigate before your library metadata is more than one day stale.


Step 4: Monitor the Kometa Web UI

When Kometa is running in schedule mode (not one-shot), it exposes a web interface on port 9000 that shows run history, collection status, and configuration validation. If the web UI goes down, the scheduler may have also stopped:

#!/bin/bash
# /usr/local/bin/kometa-webui-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/jkl012"
KOMETA_HOST="localhost"
KOMETA_PORT="9000"
TIMEOUT=10

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "http://${KOMETA_HOST}:${KOMETA_PORT}/")

if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then
  echo "Kometa web UI accessible (HTTP $HTTP_CODE)"
  curl -s "$HEARTBEAT_URL"
else
  echo "Kometa web UI unavailable (HTTP $HTTP_CODE)"
  exit 1
fi

Alternatively, add this as an HTTP monitor directly in Vigilmon:

  1. Click Add MonitorHTTP(S).
  2. Set URL to http://your-kometa-host:9000/.
  3. Set check interval to 5 minutes.
  4. Set expected response to HTTP 200.

The web UI is not critical for metadata updates, but its absence often indicates the scheduler process itself has crashed.


Step 5: Monitor External Metadata Sources

Kometa fetches metadata from external sources — MDBList, Trakt, IMDb, TMDb, TVDb — to populate collections and ratings. When these APIs are rate-limited, return errors, or change their schema, Kometa silently skips affected collections or falls back to incomplete data:

#!/bin/bash
# /usr/local/bin/kometa-sources-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/mno345"
TIMEOUT=15
FAILED=0

# TMDb API connectivity
TMDB_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "https://api.themoviedb.org/3/configuration?api_key=your-tmdb-key")
if [ "$TMDB_CODE" != "200" ]; then
  echo "TMDb API unreachable (HTTP $TMDB_CODE)"
  FAILED=1
else
  echo "TMDb OK"
fi

# Trakt API connectivity
TRAKT_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "https://api.trakt.tv/movies/trending" \
  -H "Content-Type: application/json" \
  -H "trakt-api-version: 2" \
  -H "trakt-api-key: your-trakt-client-id")
if [ "$TRAKT_CODE" != "200" ]; then
  echo "Trakt API unreachable (HTTP $TRAKT_CODE)"
  FAILED=1
else
  echo "Trakt OK"
fi

# MDBList connectivity
MDBLIST_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  --max-time "$TIMEOUT" \
  "https://mdblist.com/api/?apikey=your-mdblist-key&i=tt0816692")
if [ "$MDBLIST_CODE" != "200" ]; then
  echo "MDBList API unreachable (HTTP $MDBLIST_CODE)"
  FAILED=1
else
  echo "MDBList OK"
fi

if [ "$FAILED" -eq 0 ]; then
  curl -s "$HEARTBEAT_URL"
else
  exit 1
fi

Run this check every 30 minutes. External API failures don't break Kometa's process, but they cause incomplete collection data — knowing about them before a Kometa run lets you skip affected sources in the run config or postpone the run.


Step 6: Set Up Alert Channels

Configure Vigilmon alert routing for Kometa:

  1. Go to Alert Channels in Vigilmon.
  2. Add email notification for the run completion heartbeat — a missed daily run is important but not pager-worthy.
  3. Add a Slack webhook to #media-ops for Plex API failures — these block all metadata updates.
  4. Set Consecutive failures before alert to 1 for the Plex connectivity monitor (a single failure is actionable).
  5. Set Consecutive failures before alert to 2 for external metadata source monitors (brief API blips are common).

Add a maintenance window before Plex updates:

curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "monitor_id": "KOMETA_PLEX_MONITOR_ID",
    "duration_minutes": 30,
    "reason": "Plex Media Server update and database rebuild"
  }'

Summary

| Monitor | Target | What It Catches | |---|---|---| | Cron heartbeat (run) | Script exit code on Kometa completion | Failed run, timeout, config error, partial completion | | Cron heartbeat (Plex API) | GET /identity + /library/sections | Plex down, token expired, database rebuilding | | Cron heartbeat (cycle) | Log timestamp of last successful run | Drifting run times, missed daily cycles | | HTTP monitor (web UI) | Port 9000 | Scheduler crash, process exit | | Cron heartbeat (sources) | TMDb / Trakt / MDBList | API rate limits, outages, schema changes |

Kometa's failure mode is silent staleness — collections stop updating, overlays stop refreshing, and new library items never get their metadata applied. The only indication is a Plex library that gradually diverges from what your YAML configuration describes. Vigilmon's run completion heartbeats make this failure visible the same day it happens rather than after weeks of stale data accumulate.

Start monitoring for free at vigilmon.online.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →