---
title: "Check-Ins"
description: "Cron monitoring protocol for reporting job start, success, and failure via check-in envelopes."
url: https://develop.sentry.dev/sdk/telemetry/check-ins/
---

# Check-Ins

This document uses key words such as "MUST", "SHOULD", and "MAY" as defined in

<!-- -->

[RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) to indicate requirement levels.

Statusstable

Version`1.6.0`[(changelog)](https://develop.sentry.dev/sdk/telemetry/check-ins.md#changelog)

## [Overview](https://develop.sentry.dev/sdk/telemetry/check-ins.md#overview)

Cron check-ins allow Sentry to monitor the health of recurring jobs (cron jobs, scheduled tasks, periodic workers). An SDK sends check-in envelopes to report when a job starts, succeeds, or fails. Sentry uses this data to detect missed, late, and failing executions.

Related specs:

* [Envelopes](https://develop.sentry.dev/sdk/foundations/transport/envelopes.md) — transport format

***

## [Concepts](https://develop.sentry.dev/sdk/telemetry/check-ins.md#concepts)

### [Monitors and Check-Ins](https://develop.sentry.dev/sdk/telemetry/check-ins.md#monitors-and-check-ins)

A **monitor** is a named entity in Sentry that tracks a recurring job. Each monitor is identified by a unique `monitor_slug`. Monitors can be created manually in Sentry or upserted by the SDK alongside check-in data.

A **check-in** is a single status report for one execution of a monitored job, sent as a `check_in` envelope item.

### [Check-In Lifecycle](https://develop.sentry.dev/sdk/telemetry/check-ins.md#check-in-lifecycle)

Each job execution produces two check-ins that share the same `check_in_id`:

```bash
[job starts] → in_progress → [job ends] → ok / error
```

* `in_progress` — the job has started
* `ok` — the job completed successfully
* `error` — the job failed

Sentry uses the time between the `in_progress` and terminal (`ok`/`error`) check-ins to compute duration, and the absence of a terminal check-in within `max_runtime` to detect timeouts.

### [Monitor Upsert](https://develop.sentry.dev/sdk/telemetry/check-ins.md#monitor-upsert)

SDKs can send monitor configuration (schedule, thresholds, timezone) alongside a check-in. Sentry creates the monitor if it doesn't exist or updates it if it does. This eliminates the need for manual monitor setup.

***

## [Behavior](https://develop.sentry.dev/sdk/telemetry/check-ins.md#behavior)

### [Check-In Lifecycle](https://develop.sentry.dev/sdk/telemetry/check-ins.md#check-in-lifecycle-1)

Stablespecified since

<!-- -->

1.0.0

SDKs **MUST** generate a unique `check_in_id` (UUID v4) when a job execution starts and send a check-in with status `in_progress`.

When the job completes, SDKs **MUST** send a second check-in with the same `check_in_id` and status `ok` (success) or `error` (failure).

SDKs **SHOULD** compute the `duration` field for terminal check-ins (`ok` or `error`) by measuring the elapsed time since the `in_progress` check-in was sent.

### [Trace Context Linking](https://develop.sentry.dev/sdk/telemetry/check-ins.md#trace-context-linking)

Stablespecified since

<!-- -->

1.3.0

SDKs **SHOULD** include a `contexts.trace` object with a `trace_id` field to link the check-in to associated errors and traces.

If the job execution is part of an active trace, the SDK **SHOULD** use that trace's `trace_id`. Otherwise, the SDK **MAY** generate a new `trace_id` for correlation purposes.

### [Updating in\_progress Check-Ins](https://develop.sentry.dev/sdk/telemetry/check-ins.md#updating-in_progress-check-ins)

Stablespecified since

<!-- -->

1.2.0

SDKs **MAY** send a check-in with `check_in_id` set to an empty UUID (128-bit zero value, `00000000000000000000000000000000`) to indicate that Sentry **SHOULD** update the most recent `in_progress` check-in for the given monitor.

If no `in_progress` check-in exists, Sentry creates a new one.

This is useful for fire-and-forget patterns where the SDK does not retain the original `check_in_id`.

### [Monitor Upsert](https://develop.sentry.dev/sdk/telemetry/check-ins.md#monitor-upsert-1)

Stablespecified since

<!-- -->

1.1.0

SDKs **MAY** include a `monitor_config` object in the check-in payload. When present, Sentry creates the monitor if it does not exist, or updates its configuration if it does.

SDKs **SHOULD** only send `monitor_config` on the first check-in of a job execution (the `in_progress` check-in), not on every check-in.

### [Auto-Instrumentation](https://develop.sentry.dev/sdk/telemetry/check-ins.md#auto-instrumentation)

Stablespecified since

<!-- -->

1.1.0

SDKs **MAY** provide integrations that automatically instrument popular scheduling libraries. When available, these integrations **SHOULD**:

1. Automatically discover scheduled jobs and derive `monitor_slug` values.
2. Send `in_progress` and terminal check-ins for each job execution.
3. Upsert monitor configuration based on the library's schedule definition.

Known integrations include Celery Beat (Python), node-cron / cron / node-schedule (JavaScript), Sidekiq-Cron (Ruby), and Oban/Quantum (Elixir).

***

## [Wire Format](https://develop.sentry.dev/sdk/telemetry/check-ins.md#wire-format)

### [Check-In Payload](https://develop.sentry.dev/sdk/telemetry/check-ins.md#check-in-payload)

Stablespecified since

<!-- -->

1.0.0

A check-in is sent as a `check_in` envelope item containing a JSON object.

```json
{
  "check_in_id": "83a7c03ed0a04e1b97e2e3b18d38f244",
  "monitor_slug": "my-monitor",
  "status": "in_progress",
  "duration": 10.0,
  "release": "1.0.0",
  "environment": "production",
  "contexts": {
    "trace": {
      "trace_id": "8f431b7aa08441bbbd5a0100fd91f9fe"
    }
  }
}
```

| Field            | Type   | Required     | Since | Description                                                                                                                                                                                                |
| ---------------- | ------ | ------------ | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `check_in_id`    | String | **REQUIRED** | 1.0.0 | Client-generated UUID identifying this job execution. **MAY** be an empty UUID (all zeros) to update the most recent `in_progress` check-in (since 1.2.0).                                                 |
| `monitor_slug`   | String | **REQUIRED** | 1.0.0 | The distinct slug identifying the monitor.                                                                                                                                                                 |
| `status`         | String | **REQUIRED** | 1.0.0 | One of `in_progress`, `ok`, or `error`.                                                                                                                                                                    |
| `duration`       | Number | **OPTIONAL** | 1.0.0 | Duration of the job execution in seconds. Only takes effect for `ok` or `error` status.                                                                                                                    |
| `release`        | String | **OPTIONAL** | 1.0.0 | The release version.                                                                                                                                                                                       |
| `environment`    | String | **OPTIONAL** | 1.0.0 | The environment name.                                                                                                                                                                                      |
| `monitor_config` | Object | **OPTIONAL** | 1.1.0 | Monitor configuration for upsert. See [Monitor Configuration Payload](https://develop.sentry.dev/sdk/telemetry/check-ins.md#monitor-configuration-payload).                                                |
| `contexts`       | Object | **OPTIONAL** | 1.3.0 | Contextual information. Currently supports [trace context](https://develop.sentry.dev/sdk/foundations/transport/event-payloads/contexts.md#trace-context) with `trace_id` for linking check-ins to errors. |

**Envelope constraints:**

* A `check_in` item **MUST** occur at most once per envelope.
* This item can either be included in an Envelope with other items, or it **MAY** be sent by itself.
* Maximum item size: 100 KiB.

**Envelope Headers:** *None*

**Additional Item Headers:** *None*

### [Monitor Configuration Payload](https://develop.sentry.dev/sdk/telemetry/check-ins.md#monitor-configuration-payload)

Stablespecified since

<!-- -->

1.1.0

When included, the `monitor_config` object supports the following fields:

```json
{
  "monitor_config": {
    "schedule": {
      "type": "crontab",
      "value": "0 * * * *"
    },
    "checkin_margin": 5,
    "max_runtime": 30,
    "failure_issue_threshold": 2,
    "recovery_threshold": 2,
    "timezone": "America/Los_Angeles",
    "owner": "user:john@example.com"
  }
}
```

| Field                     | Type   | Required     | Since | Description                                                                                                                         |
| ------------------------- | ------ | ------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `schedule`                | Object | **REQUIRED** | 1.1.0 | Schedule configuration. See [Schedule Configuration](https://develop.sentry.dev/sdk/telemetry/check-ins.md#schedule-configuration). |
| `checkin_margin`          | Number | **OPTIONAL** | 1.1.0 | Allowed margin in minutes after the expected check-in time before the monitor is considered missed.                                 |
| `max_runtime`             | Number | **OPTIONAL** | 1.1.0 | Allowed duration in minutes that a monitor may be `in_progress` before being considered failed due to timeout.                      |
| `failure_issue_threshold` | Number | **OPTIONAL** | 1.4.0 | Number of consecutive failed check-ins before an issue is created.                                                                  |
| `recovery_threshold`      | Number | **OPTIONAL** | 1.4.0 | Number of consecutive OK check-ins before an issue is resolved.                                                                     |
| `timezone`                | String | **OPTIONAL** | 1.1.0 | A [tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) string for the monitor's execution schedule timezone. |
| `owner`                   | String | **OPTIONAL** | 1.5.0 | An actor identifier string, e.g. `user:john@example.com` or `team:a-sentry-team`.                                                   |

### [Schedule Configuration](https://develop.sentry.dev/sdk/telemetry/check-ins.md#schedule-configuration)

Stablespecified since

<!-- -->

1.1.0

This configuration format differs slightly from what is accepted in the monitors frontend APIs.

The `schedule` object **MUST** contain a `type` field set to either `crontab` or `interval`.

**Crontab schedule:**

| Field   | Type   | Required     | Description                               |
| ------- | ------ | ------------ | ----------------------------------------- |
| `type`  | String | **REQUIRED** | `"crontab"`                               |
| `value` | String | **REQUIRED** | A crontab expression, e.g. `"0 * * * *"`. |

**Interval schedule:**

| Field   | Type   | Required     | Description                                              |
| ------- | ------ | ------------ | -------------------------------------------------------- |
| `type`  | String | **REQUIRED** | `"interval"`                                             |
| `value` | Number | **REQUIRED** | The interval value.                                      |
| `unit`  | String | **REQUIRED** | One of `year`, `month`, `week`, `day`, `hour`, `minute`. |

***

## [Public API](https://develop.sentry.dev/sdk/telemetry/check-ins.md#public-api)

### [Capture Check-In](https://develop.sentry.dev/sdk/telemetry/check-ins.md#capture-check-in)

Stablespecified since

<!-- -->

1.0.0

SDKs **MUST** expose a top-level function to send a check-in:

```bash
captureCheckIn(checkIn, monitorConfig?) -> checkInId
```

**Parameters:**

* `checkIn` — Object containing at minimum `monitorSlug` and `status`. For terminal check-ins, also includes `checkInId` (from the initial `in_progress` call) and optionally `duration`.
* `monitorConfig` — **OPTIONAL**. Monitor configuration for upsert (schedule, margins, thresholds).

**Returns:** The `checkInId` (string), so callers can correlate the `in_progress` and terminal check-ins.

Naming **SHOULD** follow the SDK's language conventions:

* `captureCheckIn` (JavaScript, Java)
* `capture_check_in` (Python, Ruby, Elixir)
* `CaptureCheckIn` (Go, .NET)

### [Monitor Wrapper](https://develop.sentry.dev/sdk/telemetry/check-ins.md#monitor-wrapper)

Stablespecified since

<!-- -->

1.1.0

SDKs **SHOULD** expose a higher-level wrapper that automatically sends `in_progress` and `ok`/`error` check-ins around a callback:

```bash
withMonitor(monitorSlug, callback, monitorConfig?) -> callbackResult
```

The wrapper **MUST**:

1. Send an `in_progress` check-in before invoking the callback.
2. Send an `ok` check-in if the callback completes without error.
3. Send an `error` check-in if the callback throws or returns a failure.
4. Compute and include `duration` in the terminal check-in.

SDKs **MAY** additionally provide language-idiomatic alternatives:

* **Decorators** (Python): `@monitor(monitor_slug='slug')`
* **Context managers** (Python): `with monitor(monitor_slug='slug'):`
* **Mixins** (Ruby): `include Sentry::Cron::MonitorCheckIns`
* **Annotations** (Java/Kotlin): framework-specific annotations

### [Hooks](https://develop.sentry.dev/sdk/telemetry/check-ins.md#hooks)

Stablespecified since

<!-- -->

1.6.0

Check-in events **MUST NOT** go through the `beforeSend` hook. The `beforeSend` hook is reserved for error events.

SDKs **MAY** implement a dedicated `beforeSendCheckIn` hook that applies only to check-in events.

***

## [Examples](https://develop.sentry.dev/sdk/telemetry/check-ins.md#examples)

### [Basic manual check-in (two-step)](https://develop.sentry.dev/sdk/telemetry/check-ins.md#basic-manual-check-in-two-step)

```bash
// Start
checkInId = captureCheckIn({
  monitorSlug: "data-sync",
  status: "in_progress"
})

// ... execute job ...

// Complete
captureCheckIn({
  monitorSlug: "data-sync",
  checkInId: checkInId,
  status: "ok",
  duration: 12.5
})
```

Envelope payload for the first check-in:

```json
{
  "check_in_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "monitor_slug": "data-sync",
  "status": "in_progress"
}
```

Envelope payload for the terminal check-in:

```json
{
  "check_in_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "monitor_slug": "data-sync",
  "status": "ok",
  "duration": 12.5
}
```

### [Wrapper with monitor upsert](https://develop.sentry.dev/sdk/telemetry/check-ins.md#wrapper-with-monitor-upsert)

```bash
result = withMonitor("daily-report", () => {
  return generateReport()
}, {
  schedule: { type: "crontab", value: "0 2 * * *" },
  checkinMargin: 10,
  maxRuntime: 60,
  timezone: "America/New_York"
})
```

The `in_progress` envelope payload includes the monitor config:

```json
{
  "check_in_id": "f7e8d9c0b1a2f7e8d9c0b1a2f7e8d9c0",
  "monitor_slug": "daily-report",
  "status": "in_progress",
  "monitor_config": {
    "schedule": { "type": "crontab", "value": "0 2 * * *" },
    "checkin_margin": 10,
    "max_runtime": 60,
    "timezone": "America/New_York"
  }
}
```

The terminal envelope payload omits the config:

```json
{
  "check_in_id": "f7e8d9c0b1a2f7e8d9c0b1a2f7e8d9c0",
  "monitor_slug": "daily-report",
  "status": "ok",
  "duration": 45.3
}
```

***

## [Changelog](https://develop.sentry.dev/sdk/telemetry/check-ins.md#changelog)

| Version | Date       | Summary                                                                                 |
| ------- | ---------- | --------------------------------------------------------------------------------------- |
| `1.6.0` | 2025-09-18 | Added hook requirements (beforeSend exclusion, optional beforeSendCheckIn)              |
| `1.5.0` | 2024-04-24 | Added owner field to monitor\_config                                                    |
| `1.4.1` | 2023-12-18 | Added failure\_issue\_threshold and recovery\_threshold to monitor\_config JSON example |
| `1.4.0` | 2023-12-13 | Added failure\_issue\_threshold and recovery\_threshold to monitor\_config              |
| `1.3.1` | 2023-07-10 | Fixed typo in checkin\_margin and max\_runtime descriptions                             |
| `1.3.0` | 2023-06-26 | Added trace context support for linking check-ins to errors                             |
| `1.2.1` | 2023-06-06 | Clarified zero UUID wording to specify "most recent in\_progress" check-in              |
| `1.2.0` | 2023-06-05 | Added zero UUID support for updating most recent in\_progress check-in                  |
| `1.1.0` | 2023-04-18 | Added monitor upsert support with schedule configuration                                |
| `1.0.1` | 2023-04-17 | Improved monitor\_slug example (UUID replaced with human-readable slug)                 |
| `1.0.0` | 2023-03-21 | Initial spec — basic check-in payload                                                   |
