> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rootly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pulses

> Track deploys, config changes, and other operational events as pulses — silent context signals that surface in triage to correlate breaks with changes.

## 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.

<Note>
  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](/workflows/pulse-workflows) is what turns a pulse into any of those things — but the pulse itself is inert.
</Note>

***

## How Pulses Are Used

| Feature                                           | How pulses are used                                                                                                                                                                                                                                    |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Incident triage**                               | The most common use. When a responder opens an incident, Rootly shows pulses that landed in the recent past — filtered by the incident's services, environments, and time window — so "what changed right before this broke" is a one-glance question. |
| **[Pulse Workflows](/workflows/pulse-workflows)** | Trigger a workflow when a pulse arrives that matches specific criteria. Example: auto-post a Slack message when a Production deploy pulse arrives, so the team sees the deploy timeline in-context.                                                    |
| **API + CLI**                                     | Any system that knows about a change can send a pulse. CI/CD pipelines, feature-flag services, config-management tools, custom scripts — all common sources.                                                                                           |

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:

```bash Linux theme={null}
curl --header "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_ROOTLY_API_TOKEN>" \
  --data '{"data": {"attributes": {"summary": "Deployed website v2.14.1"}}}' \
  -X POST https://api.rootly.com/v1/pulses
```

Richer request with metadata for filtering:

```bash Linux theme={null}
curl --header "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_ROOTLY_API_TOKEN>" \
  --data '{
    "data": {
      "attributes": {
        "summary": "Deployed website v2.14.1",
        "environments": ["production"],
        "services": ["checkout-web", "payments-api"],
        "labels": {
          "version": "2.14.1",
          "author": "alice@example.com",
          "commit": "a1b2c3d"
        }
      }
    }
  }' \
  -X POST https://api.rootly.com/v1/pulses
```

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](https://github.com/rootlyhq/rootly-cli) exposes two pulse commands — one that creates a pulse from a summary and one that wraps an arbitrary shell command:

**Simple pulse:**

```bash Linux theme={null}
export ROOTLY_API_TOKEN="your-api-token"

rootly pulse create "Deployed website v2.14.1" \
  --services=checkout-web,payments-api \
  --labels="env=production,version=2.14.1"
```

**Wrap a shell command as a pulse:**

```bash Linux theme={null}
rootly pulse run \
  --summary="Deploy Website" \
  --services=checkout-web \
  --labels="env=production,version=2" \
  -- sh deploy.sh
```

`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](/integrations/cli) 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](/liquid/pulse-variables).

<ParamField path="summary" type="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".
</ParamField>

<ParamField path="environments" type="array of strings">
  Which environments the change affects. Matches the [Environments](/configuration/environments) field on incidents, so pulses filter cleanly against incident context.

  ```bash theme={null}
  --environments "production"
  --environments "staging, production"
  ```
</ParamField>

<ParamField path="services" type="array of strings">
  Which [Services](/configuration/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.
</ParamField>

<ParamField path="labels" type="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.

  ```bash theme={null}
  --labels "version=2.14.1, author=alice, commit=a1b2c3d"
  ```

  In the JSON API, labels is a flat object: `{"version": "2.14.1", "author": "alice"}`.
</ParamField>

<ParamField path="external_url" type="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.
</ParamField>

***

## Common Pulse Sources

<AccordionGroup>
  <Accordion title="CI/CD deploy pipelines" icon="rotate-right">
    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.
  </Accordion>

  <Accordion title="Feature flag services" icon="toggle-on">
    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.
  </Accordion>

  <Accordion title="Infrastructure changes (Terraform, Pulumi, Kubernetes)" icon="server">
    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.
  </Accordion>

  <Accordion title="Database migrations" icon="database">
    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.
  </Accordion>

  <Accordion title="Manual runbook actions" icon="wrench">
    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.
  </Accordion>
</AccordionGroup>

***

## 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](/workflows/pulse-workflows) with an Incident Created action — not the pulse itself.

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="A pulse I sent isn't appearing in the incident triage view" icon="circle-x">
    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.
  </Accordion>

  <Accordion title="API returns 401 when creating a pulse" icon="key">
    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.
  </Accordion>

  <Accordion title="CLI can't find labels in the correct format" icon="triangle-exclamation">
    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.
  </Accordion>

  <Accordion title="Pulses are firing pulse workflows I didn't expect" icon="bolt">
    Check the workflow's run conditions in [Workflows](/workflows/pulse-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](/workflows/conditions) evaluator lets you test conditions against a sample pulse payload.
  </Accordion>

  <Accordion title="High-volume pulse sources are cluttering the triage view" icon="filter">
    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).
  </Accordion>
</AccordionGroup>

***

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="How are pulses different from incidents?" icon="shapes">
    **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](/workflows/pulse-workflows) turns them into one.
  </Accordion>

  <Accordion title="Can pulses page on-call?" icon="bell">
    Not directly. A pulse itself is inert. To page on-call when a specific pulse arrives, create a [Pulse Workflow](/workflows/pulse-workflows) with matching conditions and an incident-creation or paging action.
  </Accordion>

  <Accordion title="How long are pulses retained?" icon="clock">
    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.
  </Accordion>

  <Accordion title="Can we search pulses across all incidents?" icon="magnifying-glass">
    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.
  </Accordion>

  <Accordion title="Do pulses count against API rate limits?" icon="gauge-high">
    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.
  </Accordion>

  <Accordion title="Can we use Liquid to reference pulse data in workflows?" icon="code">
    Yes. See [Pulse Variables](/liquid/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.
  </Accordion>

  <Accordion title="What's the difference between the CLI's pulse create and pulse run commands?" icon="wrench">
    `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).
  </Accordion>
</AccordionGroup>

***

## Related Pages

<CardGroup cols={3}>
  <Card title="Pulse Workflows" icon="bolt" href="/workflows/pulse-workflows">
    Turn pulses into automation — post to Slack, create tickets, trigger incidents based on pulse content.
  </Card>

  <Card title="Pulse Variables" icon="code" href="/liquid/pulse-variables">
    Liquid reference for `pulse.id`, `pulse.short_id`, `pulse.source`, `pulse.summary`, and `pulse.data`.
  </Card>

  <Card title="Rootly CLI" icon="wave-pulse" href="/integrations/cli">
    Full command reference for the Rootly CLI, including `pulse create` and `pulse run`.
  </Card>
</CardGroup>
