How to Monitor and Debug Self‑Hosted OpenSEO Instances

Self‑hosted OpenSEO deployments ship with a health endpoint, a telemetry heartbeat, and a startup pre‑flight script that collectively expose runtime status, validate configuration, and stream diagnostic logs to standard output.

OpenSEO is an open‑source SEO automation platform maintained in the every-app/open-seo repository. When you run the self‑hosted variant via Docker, the runtime exposes several first‑party mechanisms for observability. Below is a complete guide to leveraging the health API, telemetry worker, and container logs to keep your instance healthy.

Built‑in Health Endpoint

The application exposes an unauthenticated GET /api/health route that returns a JSON map of per‑feature setup checks. These checks cover database connectivity, DataForSEO API keys, Google Search Console authentication, and other critical dependencies.

In src/routes/api/health.ts, the handler re‑uses the same check map consumed by the Docker pre‑flight script, ensuring consistency between startup validation and runtime queries. You can poll this endpoint from any monitoring system or curl it locally for a quick pulse check.

curl -s http://localhost:8787/api/health | jq .

Typical output includes status keys for each subsystem:

{
  "dataforseo": "ok",
  "google-search-console": "ok",
  "database": "ok",
  "selfHostTelemetry": "ok"
}

Self‑Host Telemetry Heartbeat

A lightweight background worker in src/server/lib/self-host-telemetry.ts periodically pings the OpenSEO telemetry service. It reports the results of the health checks alongside counts of processed audits, rank checks, and MCP calls.

If the heartbeat fails, the module emits debug logs to standard error. This gives you immediate visibility into network partitions or authentication issues without exposing sensitive data in the heartbeat payload itself.

To inspect telemetry activity in real time, filter the Docker logs:

docker logs --follow open-seo-selfhost | grep "self-host telemetry"

A successful heartbeat appears as:


🟢 self-host telemetry heartbeat succeeded (runId=abc123)

Startup Validation with Pre‑flight Checks

Before the application accepts traffic, scripts/selfhost-preflight.ts executes inside the container (as defined in Dockerfile.selfhost). This TypeScript script validates required environment variables, tests connectivity to external APIs such as DataForSEO and Google Search Console, and runs the same health checks exposed by /api/health.

Any failure aborts the container start, giving you immediate feedback at deploy time rather than runtime. For example, a missing DataForSEO key produces:

node scripts/selfhost-preflight.ts

Output:


❌ Missing DATAFORSEO_API_KEY – aborting startup

Because the pre‑flight logic mirrors the health endpoint logic, passing the pre‑flight guarantees that the health endpoint will return "ok" for all critical dependencies.

Log Inspection and Debugging

OpenSEO runs as a Cloudflare Workers‑compatible container, so all console.error, console.warn, and console.debug calls—emitted from audit workers, rank‑check workflows, and MCP tools—are captured by Docker’s logging driver.

View the full log stream:

docker logs <container>

Enable verbose debug logging by setting LOG_LEVEL=debug before starting the container:

docker run -e LOG_LEVEL=debug -p 8787:8787 everyapp/open-seo:selfhost

At this level, src/server/lib/self-host-telemetry.ts and other modules emit granular traces useful for tracing failed audit jobs or MCP tool invocations.

For production‑grade observability, forward the container’s stdout to a log aggregation service such as Loki or Datadog. The telemetry heartbeat already ships aggregated metrics to the OpenSEO SaaS dashboard, where you can view instance‑level health charts separately from raw container logs.

Summary

  • Health endpoint (/api/health): Poll this JSON endpoint to verify database, API, and authentication status at runtime.
  • Telemetry worker (src/server/lib/self-host-telemetry.ts): Emits periodic heartbeats and debug logs on failure; grep container logs for "self-host telemetry" to verify connectivity.
  • Pre‑flight validation (scripts/selfhost-preflight.ts): Catches configuration errors at container start by replicating the health checks before the server boots.
  • Docker logs: Capture all console.* output from workers and workflows; enable LOG_LEVEL=debug for verbose tracing.

Frequently Asked Questions

How often does the self‑host telemetry heartbeat run?

The background worker in src/server/lib/self-host-telemetry.ts sends a heartbeat on an interval defined by the telemetry configuration, typically every few minutes. Each ping includes the current health check results and aggregate job counts, allowing the SaaS dashboard to plot instance health over time.

Can I disable telemetry while keeping the health endpoint?

The telemetry module respects environment variables. While the health endpoint (src/routes/api/health.ts) remains available for local monitoring, you can opt out of remote telemetry by omitting the telemetry token or setting the appropriate disable flag, though this will prevent the aggregated metrics from appearing in the OpenSEO dashboard.

What is the difference between the pre‑flight script and the health endpoint?

scripts/selfhost-preflight.ts runs once at container startup and exits non‑zero on failure, preventing the service from starting with invalid configuration. The health endpoint (src/routes/api/health.ts) exposes the same check logic via HTTP so you can query runtime state continuously. Both use the underlying check map, but the pre‑flight acts as a gate, while the endpoint acts as a gauge.

How do I debug a failing audit or rank‑check worker?

Set LOG_LEVEL=debug and inspect the Docker logs. Workers such as those in src/server/workflows/ emit console.debug statements at the start and end of each job, including error stack traces on failure. Filtering the logs by the workflow ID or error keyword will isolate the specific job trace.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →