Config-as-Code

Define monitors, heartbeats, alert channels, status pages, and incidents in one `obs.json` file. Version-control your monitoring like application code.

ObserveOne supports an Infrastructure-as-Code (IaC) workflow. You can define all your monitors, API checks, heartbeats, alert channels, status pages, suites, and incidents in a single JSON file and synchronize them to your account.

Check obs.json into the same repo as your application code to version-control monitoring changes alongside it, or let an AI agent read and edit the file directly to manage your testing environment.

Generating a Config File#

If you already have resources created via the ObserveOne web dashboard, you don't need to write a configuration file from scratch. You can pull your existing remote state into a local JSON file.

# Fetches all remote resources and generates obs.json in the current directory
obs export
# Save to a custom file name
obs export -f my-stack.json
# Each suite's generated Playwright scripts are inlined under suites[].tests
# by default (useful for self-host migrations, offline backups, or portable
# archives). Pass --no-scripts for a lighter, config-only export.
obs export --no-scripts

obs export captures all 7 resource types: monitors, API checks, heartbeats, alert channels, status pages, suites, and incidents. DB-owned fields (id, created_at, updated_at) are automatically stripped so the output is safe to apply directly.

By default each suite's generated Playwright scripts are fetched and embedded inline under suites[].tests[] as { name, script }, so an export is lossless. Pass --no-scripts to export suites as metadata only (name, URL, cron, secret keys) for a lighter, config-only file. Suites with test_count: 0 are unaffected.

Synchronizing Changes#

Once you have your obs.json file, you can edit it locally. You can modify existing fields (like changing a timeout_ms) or copy-paste a block to define a brand new resource. If obs.json is missing but observeone.json exists, the CLI will automatically use observeone.json.

To synchronize your local file with the ObserveOne backend, run:

obs apply

How obs apply Works#

The apply command uses a stateless upsert strategy:

  1. It reads the local JSON array of resources.
  2. It fetches the current state from the backend API.
  3. It matches resources using a resource-specific identity key (see table below).
  4. Update: If a local resource matches a remote resource, the CLI fires an update API call to sync the properties.
  5. Create: If a local resource does not exist remotely, the CLI fires a create API call.
  6. Batched Execution: To prevent rate limiting (429 errors), the CLI automatically groups your configuration into batches of 5 and processes them with strict 1-second delays.
ResourceIdentity key
monitors, api_checks, heartbeatsname
alert_channelsname
status_pagesslug
suitessuite_name

Because matching is by name (or slug), renaming a resource in obs.json looks like a brand new resource: obs apply creates the renamed copy and leaves the original in place. To make this easy to catch, the create path prints a stderr warning listing existing names of that type before it creates, so an accidental rename stands out. Rename on the backend (or via update) when you want to keep the resource's history.

Apply limitations#

  • Incidents: obs apply warns and skips any incidents block. Incidents are runtime state and cannot be re-created from config. Use obs incident create directly.
  • Suites: obs apply updates metadata (name, target URL, schedule) for existing suites only. New suites require AI generation via obs suite generate and cannot be created via apply.
  • Browser checks: an ai_checks block is accepted but skipped with a warning while the feature is disabled.
  • Status-page monitors: attached monitors are exported but not applied. Manage them via obs status-page add-monitor / remove-monitor.

Single-Resource Files#

Starting in CLI v1.13.0, obs apply accepts files holding a single resource in addition to the standard plural config. Useful for one-off scripts that manage a resource without maintaining a full obs.json.

Three accepted shapes:

// 1. Wrapped: explicit resource key
{
"monitor": {
"name": "Landing",
"url": "https://example.com",
"interval": "*/5 * * * *"
}
}
// 2. Bare: type inferred from fields
// url → monitor; url + method → api_check; period/grace_period/ping_key → heartbeat
{ "name": "Daily Backup", "period": 86400, "grace_period": 60 }
// 3. Explicit type: disambiguates the bare form
{ "type": "heartbeat", "name": "Daily Backup", "period": 86400 }

The standard obs.json (plural config) still works exactly as before. Single-resource files use the same diff/upsert logic.

Schema Reference#

To see the exact fields allowed in the JSON configuration, check out the JSON Schema Reference.

Was this page helpful?