Skip to main content

Overview

Pulses are lightweight event records that capture changes to your systems — deploys, config updates, feature-flag flips, database migrations, CI builds — without paging anyone, creating an incident, or generating a notification. They exist for a single reason: when an incident happens, responders need to answer “what changed?” as fast as possible. Pulses give you a searchable, filterable timeline of every change that landed in the recent past, so triage takes minutes instead of digging through Slack, git logs, and deploy dashboards to reconstruct the timeline.
Pulses are passive context, not alerts. They don’t trigger notifications, don’t page on-call, and don’t create incidents on their own. A Pulse Workflow is what turns a pulse into any of those things — but the pulse itself is inert.

How Pulses Are Used

Because pulses cost nothing to send and everything to have during triage, the right pattern is to send more pulses than you think you need. Pipe every deploy, every feature-flag flip, every config change — filter and narrow at read time via the pulse UI, not at write time.

Sending Pulses

Pulses can be created two ways: through the Rootly API and through the Rootly CLI. Pick whichever matches how your pipeline is already structured — most teams end up using both (API for programmatic sources, CLI for shell scripts and CI).

API

Every pulse is a POST /v1/pulses with a summary and optional metadata. Minimal request:
Linux
Richer request with metadata for filtering:
Linux
Best used from CI/CD hooks, feature-flag webhook receivers, and infrastructure-as-code apply hooks. Wire the pulse creation into your deploy pipeline once and every future deploy is captured automatically.

CLI

The Rootly CLI exposes two pulse commands — one that creates a pulse from a summary and one that wraps an arbitrary shell command: Simple pulse:
Linux
Wrap a shell command as a pulse:
Linux
pulse run executes the wrapped command and creates a pulse capturing the command, its exit status, and its runtime. Best for CI job wrappers where you want “this thing ran” as pulse metadata automatically. See the Rootly CLI docs for the full command reference.

Pulse Attributes

Every pulse supports the following fields. All are searchable and filterable in the pulses UI and in pulse variables for workflow templates.
summary
string
required
Human-readable one-line description. This is what appears in the triage timeline. Keep it short and specific — “Deploy website v2.14.1” beats “Deployment” or “Prod push”.
environments
array of strings
Which environments the change affects. Matches the Environments field on incidents, so pulses filter cleanly against incident context.
services
array of strings
Which Services the change touches. This is the single most important field for triage filtering — a pulse tagged with the affected service surfaces in the right place at the right time.
labels
key-value map
Free-form metadata attached to the pulse. Use for anything that helps at read time — commit hash, deploy author, version, ticket ID, feature-flag name.
In the JSON API, labels is a flat object: {"version": "2.14.1", "author": "alice"}.
external_url
string
Optional link back to the source of the change — Datadog dashboard, GitHub commit, CircleCI build. Renders as a clickable link in the pulses UI so responders can jump straight to the source.

Common Pulse Sources

The single most valuable pulse source. Post a pulse from every deploy job — success and failure both — with the version, commit, and environment as labels. When an incident hits, the responder immediately knows what shipped in the last hour.Common integrations: GitHub Actions, CircleCI, Jenkins, Buildkite, GitLab CI. Add a step to the deploy job that curls the pulses API.
Every feature-flag flip is a change. Wire your feature-flag service (LaunchDarkly, Statsig, Unleash, PostHog) to POST a pulse when a flag toggles in production. When a customer reports “it worked yesterday and doesn’t today,” the pulse timeline shows the exact flag that changed between then and now.
Post a pulse on every terraform apply, every kubectl rollout, every Pulumi update. Include the plan diff (or a link to it) in labels or external_url so responders can see what actually changed at the infra level.
Every schema migration is a landmine waiting to be stepped on during triage. Post a pulse from your migration runner with the migration name and target database. If an incident happens 3 hours after a migration, the pulse timeline surfaces the migration immediately.
Any manual change — restarting a service, applying a config patch, running a maintenance script — deserves a pulse. Use the CLI (rootly pulse create "Restarted elasticsearch-prod") as an operator habit. Future you will thank present you when the change becomes relevant during triage.

Best Practices

  • Send more pulses than you think you need. Filtering out noisy pulses at read time is trivial (label filters, service filters, time-window filters). Reconstructing a change history from scratch during a live incident is not.
  • Wire pulses at the automation layer, not by hand. A pulse that requires an engineer to remember to send it doesn’t get sent when it matters most (during a rushed hotfix). Bake pulse creation into deploy jobs, CI hooks, and feature-flag webhooks so it happens automatically.
  • Use consistent labels across sources. If your GitHub deploys use version, your Terraform runs use terraform_version, and your feature flags use variant, filtering at read time gets awkward. Standardize on a small label vocabulary and apply it everywhere.
  • Tag environments and services on every pulse. Untagged pulses don’t surface in incident triage because triage filters by service and environment. A pulse without those tags is a pulse that responders won’t see.
  • Include an external_url when the pulse links to actionable detail. A pulse that says “Deploy v2.14.1” is useful; a pulse that says “Deploy v2.14.1” + a link to the CircleCI build page is a rollback candidate in one click.
  • Don’t use pulses for alerts. Pulses are inert by design. If you want an incident to open when a specific change happens, that’s a Pulse Workflow with an Incident Created action — not the pulse itself.

Troubleshooting

Two common causes: (1) the pulse’s services or environments don’t match the incident’s — triage filters by intersection, so a pulse tagged only with staging won’t appear on a Production incident; (2) the pulse landed outside the triage time window (default is the last few hours before the incident). Widen the window from the triage view’s date picker if the pulse is older.
The Authorization: Bearer <token> header is missing or the token is invalid. Generate a token in Account → Manage API keys → Generate New API Key and confirm it has API access enabled. If you’re using a Team API key, confirm the key’s team has permission to write pulses.
The CLI expects labels as comma-separated key=value pairs: --labels "version=2, attempt=1". Common mistakes: quoting individual pairs (--labels "version=2","attempt=1"), using colons instead of equals (--labels "version:2"), or wrapping values in inner quotes.
Check the workflow’s run conditions in Workflows. Pulse workflows fire on every matching pulse by default — narrow the conditions to filter by services, environments, or specific label values. The Workflow Conditions evaluator lets you test conditions against a sample pulse payload.
Some sources (e.g., a chatty CI system) generate too many pulses to be useful during triage. Two options: (1) filter noisy pulses out of the triage view via label filters — the pulse data stays available for post-incident review; (2) reduce the source’s pulse volume by only sending on meaningful events (e.g., successful deploys, not every retry).

Frequently Asked Questions

Pulses capture changes to your systems (deploys, config updates) and are passive — no notifications, no paging, no incident lifecycle. Incidents capture problems requiring response — they trigger workflows, page on-call, and follow the full incident lifecycle. Pulses inform incident triage; they don’t become incidents on their own unless a Pulse Workflow turns them into one.
Not directly. A pulse itself is inert. To page on-call when a specific pulse arrives, create a Pulse Workflow with matching conditions and an incident-creation or paging action.
Pulses are retained indefinitely by default. If your workspace has a data-retention policy, pulses fall under the same retention window as incidents. Contact support if you need a shorter retention window for pulses specifically.
Yes. The Pulses page in Rootly Web is a searchable, filterable timeline independent of any specific incident. Filter by service, environment, label, or time window.
Pulses use the standard Rootly API rate limits. High-volume pulse sources (e.g., a CI system pulsing on every commit) can hit limits — batch or throttle at the source, or use the CLI which handles retries.
Yes. See Pulse Variables for the reference — {{ pulse.id }}, {{ pulse.short_id }}, {{ pulse.source }}, {{ pulse.summary }}, and {{ pulse.data }} (the raw pulse payload). Reach into the payload with {{ pulse.data | get: 'field_name' }} for anything not exposed as its own top-level variable.
rootly pulse create creates a pulse from a summary and metadata you provide. rootly pulse run wraps an actual shell command — it executes the command, captures its exit status and runtime, and creates a pulse with that metadata attached automatically. Use pulse run when the pulse is the fact that a specific command ran (deploy scripts, migration jobs, backup jobs).

Pulse Workflows

Turn pulses into automation — post to Slack, create tickets, trigger incidents based on pulse content.

Pulse Variables

Liquid reference for pulse.id, pulse.short_id, pulse.source, pulse.summary, and pulse.data.

Rootly CLI

Full command reference for the Rootly CLI, including pulse create and pulse run.