> ## Documentation Index
> Fetch the complete documentation index at: https://checkly-422f444a-herve-close-confirmed-docs-gaps.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Multistep Check Construct

> Learn how to configure multistep checks with the Checkly CLI.

<Tip>
  Learn more about Multistep Checks in [the Multistep Checks overview](/detect/synthetic-monitoring/multistep-checks/overview).
</Tip>

Use Multistep Checks to run complex end-to-end workflows with Playwright that span multiple endpoints. The examples below show how to configure Multistep Checks for different testing scenarios.

<Accordion title="Prerequisites">
  Before creating Multistep Checks, ensure you have:

  * An initialized Checkly CLI project
  * Public endpoints you want to monitor
  * Runtime `2023.09` or later (Multistep Checks require [newer runtimes](/platform/runtimes/runtime-specification))

  For additional setup information, see [CLI overview](/cli/overview).
</Accordion>

<CodeGroup>
  ```ts Basic Example theme={null}
  import { MultiStepCheck } from "checkly/constructs"
  import * as path from "path"

  new MultiStepCheck("multistep-check-1", {
    name: "Multistep Check #1",
    description: "Validates user signup and login flow.",
    locations: ["us-east-1", "eu-west-1"],
    code: {
      entrypoint: path.join(__dirname, "multi-step.spec.ts"),
    },
  })
  ```

  ```ts Advanced Example theme={null}
  import { MultiStepCheck, Frequency } from "checkly/constructs"
  import { secret } from "checkly/util"
  import * as path from "path"

  new MultiStepCheck("complex-multistep-check", {
    name: "Complex User Journey",
    description: "Validates user signup and login flow.",
    activated: true,
    runtimeId: "2025.04",
    frequency: Frequency.EVERY_15M,
    locations: ["us-east-1", "eu-west-1"],
    tags: ["e2e", "user-journey", "critical"],
    environmentVariables: [
      { key: "BASE_URL", value: "https://app.example.com" },
      { key: "TEST_USER_EMAIL", value: "test@example.com" },
      { key: "TEST_USER_PASSWORD", value: secret("TEST_USER_PASSWORD"), secret: true },
    ],
    code: {
      entrypoint: path.join(__dirname, "user-journey.spec.ts"),
    },
  })
  ```
</CodeGroup>

## Configuration

<Tabs>
  <Tab title="Multistep Check">
    | Parameter | Type | Required | Default | Description |
    | - | - | - | - | - |
    | `code` | `object` | ✅ | - | The Playwright test code |
  </Tab>

  <Tab title="General Check">
    | Property | Type | Required | Default | Description |
    | - | - | - | - | - |
    | `name` | `string` | ✅ | - | Friendly name for your check |
    | `description` | `string` | ❌ | `null` | A description of the check. Supports markdown. Max 500 characters |
    | `intent` | `CheckIntent` | ❌ | - | Structured guidance for root cause analysis and check repair. See [General Check Options](#general-check-options). |
    | `aiAutoRepairEnabled` | `boolean \| null` | ❌ | - | Enable or disable automatic repair, or inherit the account setting. Requires CLI 9.4.0 or later. See [General Check Options](#general-check-options). |
    | `activated` | `boolean` | ❌ | `true` | Whether the check is enabled |
    | `alertChannels` | `AlertChannel[]` | ❌ | `[]` | Array of AlertChannel objects for notifications |
    | `alertEscalationPolicy` | `AlertEscalationPolicy` | ❌ | - | Advanced alert settings |
    | `environmentVariables` | `object[]` | ❌ | `[]` | Check-level environment variables |
    | `frequency` | `Frequency` | ❌ | - | How often to run your check |
    | `group` | `CheckGroup` | ❌ | - | The CheckGroup this check belongs to |
    | `locations` | `string[]` | ❌ | `[]` | Array of public location codes |
    | `muted` | `boolean` | ❌ | `false` | Whether alert notifications are muted |
    | `runtimeId` | `string` | ❌ | - | The ID of the runtime to use (2023.09 or later required) |
    | `privateLocations` | `string[]` | ❌ | `[]` | Array of Private Location slugs |
    | `retryStrategy` | `RetryStrategy` | ❌ | - | Strategy for configuring retries |
    | `runParallel` | `boolean` | ❌ | `false` | Run checks in parallel or round-robin |
    | `tags` | `string[]` | ❌ | `[]` | Array of tags to organize checks |
    | `testOnly` | `boolean` | ❌ | `false` | Only run with test, not during deploy |
    | `triggerIncident` | `IncidentTrigger` | ❌ | - | Create and resolve an incident based on the check's alert configuration |
  </Tab>
</Tabs>

### Multistep Check Options

<ResponseField name="code" type="object" required>
  The Playwright test code that defines your Multistep Check monitor.

  **Usage:**

  ```ts theme={null}
  // Using file reference
  code: {
    entrypoint: path.join(__dirname, "user-journey.spec.ts")
  }

  // Using inline content
  code: {
    content: `
      import { test, expect } from "@playwright/test"

      test("complete workflow", async ({ request }) => {
        // Multistep logic here
      })
    `
  }
  ```

  **Parameters:**

  | Parameter | Type | Required | Description |
  | - | - | - | - |
  | `entrypoint` | `string` | ❌ | Path to a `.spec.js` or `.spec.ts` file containing the Playwright test |
  | `content` | `string` | ❌ | Inline JavaScript/TypeScript code as a string |

  <Info>
    You must provide either `entrypoint` or `content`, but not both.
  </Info>

  **Examples:**

  <Tabs>
    <Tab title="CRUD API">
      ```ts theme={null}
      new MultiStepCheck("onboarding-flow", {
        name: "Complete User Onboarding",
        runtimeId: "2025.04",
        code: {
          entrypoint: path.join(__dirname, "group.spec.ts")
        }
      })

      // group.spec.ts
      import { test, expect } from "@playwright/test"

      const baseUrl = "https://api.checklyhq.com/v1"

      const headers = {
        Authorization: `Bearer ${process.env.API_KEY}`,
        "x-checkly-account": process.env.ACCOUNT_ID,
      }

      test("Verify Group API", async ({ request }) => {
        /**
         * Create a group
         */
        const group = await test.step("POST /check-groups", async () => {
          const response = await request.post(`${baseUrl}/check-groups/`, {
            data: {
              locations: ["eu-west-1"],
              name: "createdViaApiCheck",
            },
            headers,
          })
          expect(response).toBeOK()

          return response.json()
        })

        /**
         * Get the newly created group
         */
        await test.step("GET /check-groups/{id}", async () => {
          const response = await request.get(`${baseUrl}/check-groups/${group.id}`, {
            headers,
          })
          expect(response).toBeOK()

          const receivedGroup = await response.json()
          expect(receivedGroup.id).toEqual(group.id)
        })

        /**
         * Update the new group
         */
        await test.step("PUT /check-groups/{id}", async () => {
          const response = await request.put(`${baseUrl}/check-groups/${group.id}`, {
            data: {
              tags: ["public-api", "added-by-check"],
            },
            headers,
          })
          expect(response).toBeOK()
        })

        /**
         * Delete the new group
         */
        await test.step("DELETE /check-group/{id}", async () => {
          const response = await request.delete(
            `${baseUrl}/check-groups/${group.id}`,
            { headers },
          )
          expect(response).toBeOK()
        })
      })
      ```
    </Tab>

    <Tab title="Degraded state">
      ```ts theme={null}
      new MultiStepCheck("degraded-example", {
        name: "Degraded Example",
        runtimeId: "2025.04",
        code: {
          entrypoint: path.join(__dirname, "degraded.spec.ts")
        },
      })

      // degraded.spec.ts
      import { test, expect } from "@playwright/test"
      import { getAPIResponseTime, markCheckAsDegraded } from "@checkly/playwright-helpers"

      const baseUrl = "https://api.spacexdata.com/v3"

      test("SpaceX-API Dragon Capsules & Next Launch", async ({ request }) => {
        await test.step("get all capsules", async () => {
          const response = await request.get(`${baseUrl}/dragons`)

          // Check 200 status code
          expect(response).toBeOK()

          // Check degraded status
          expect.soft(getAPIResponseTime(response), 'GET /dragons too slow').toBeLessThanOrEqual(200)

          return response.json()
        })

        // Trigger degraded state if check failed due to soft assertion
        if (test.info().errors.length) {
          markCheckAsDegraded('Check degraded due to soft assertion failure.')
        }
      })
      ```
    </Tab>
  </Tabs>

  **Use cases**: Complex API journeys, end-to-end API workflows, business process validation.
</ResponseField>

### General Check Options

<ResponseField name="name" type="string" required>
  Friendly name for your multistep check that will be displayed in the Checkly dashboard and used in notifications.

  **Usage:**

  ```ts highlight={2} theme={null}
  new MultiStepCheck("my-multistep", {
    name: "Complete User Journey Test"
  })
  ```
</ResponseField>

<ResponseField name="runtimeId" type="string">
  The Checkly runtime version used to execute the Multistep Check. Runtimes are managed execution environments for Browser and Multistep Checks. They include fixed Checkly-provided dependencies, such as Playwright, browser binaries, and runtime libraries.

  Multistep checks require runtime `2023.09` or later.

  Usage:

  ```ts highlight={3} theme={null}
  new MultiStepCheck("my-multistep", {
    name: 'My Multistep Check',
    runtimeId: "2025.04" // Use latest runtime for best performance
    /* More options... */
  })
  ```

  <Warning>
    Multistep checks require runtime `2023.09` or later. Earlier runtimes do not support multistep functionality.
  </Warning>
</ResponseField>

<ResponseField name="frequency" type="Frequency">
  How often the multistep check should run. Use the `Frequency` enum to set the check interval.

  Usage:

  ```ts highlight={5} theme={null}
  import { Frequency } from 'checkly/constructs'

  new MultiStepCheck("my-multistep", {
    name: "My Multistep Check",
    frequency: Frequency.EVERY_15M,
    /* More options... */
  })
  ```

  **Available frequencies**: `EVERY_1M`, `EVERY_2M`, `EVERY_5M`, `EVERY_10M`, `EVERY_15M`, `EVERY_30M`, `EVERY_1H`, `EVERY_2H`, `EVERY_3H`, `EVERY_6H`, `EVERY_12H`, `EVERY_24H`
</ResponseField>

<ResponseField name="locations" type="string[]" default="[]">
  Array of public location codes where the multistep check should run. Multiple locations provide geographic coverage and user experience insights.

  Usage:

  ```ts highlight={3} theme={null}
  new MultiStepCheck("global-check", {
    name: "Global Multistep Check",
    locations: ["us-east-1", "eu-west-1", "ap-southeast-1"]
    /* More options... */
  })
  ```

  Examples:

  <Tabs>
    <Tab title="Global User Experience">
      ```ts theme={null}
      // Worldwide API testing
      new MultiStepCheck("global-journey", {
        name: "Global API Journey",
        locations: [
          "us-east-1",      // N. Virginia
          "us-west-1",      // N. California
          "eu-west-1",      // Ireland
          "ap-southeast-1", // Singapore
          "ap-northeast-1"  // Tokyo
        ],
        /* More options... */
      })
      ```
    </Tab>

    <Tab title="Regional Focus">
      ```ts theme={null}
      // European user focus
      new MultiStepCheck("eu-workflow", {
        name: "European API Journey",
        locations: ["eu-west-1", "eu-central-1"],
        /* More options... */
      })
      ```
    </Tab>
  </Tabs>

  **Use cases**: Global API monitoring, regional API testing, geographic compliance validation.
</ResponseField>

<Warning>
  Multistep checks are only supported on runtime `2023.09` or later. Make sure to specify a compatible `runtimeId` in your check configuration.
</Warning>

<ResponseField name="intent" type="CheckIntent">
  Describe what your check is intended to verify and the behavior that should be preserved. Checkly uses intent for root cause analysis across all check types. It is separate from `description` and does not replace executable assertions.

  <Note>
    Intent is used for [automatic repair](/resolve/automatic-check-repair) only for Browser and Multistep Checks.
  </Note>

  The object accepts the following fields:

  | Field | Type | Required | Description |
  | - | - | - | - |
  | `goal` | `string` | Yes | The outcome your check should verify. Must contain 1–2,000 characters after trimming. |
  | `constraints` | `CheckIntentConstraint[]` | No | Outcomes and guardrails that refine the goal. Omitted constraints become an empty array. |

  Each constraint has a required `type` and `statement`:

  * `REQUIRED_OUTCOME`: an outcome the check must verify.
  * `MUST_PRESERVE`: behavior or an assertion that should be preserved when repairing the check.

  Each `statement` must contain 1–1,000 characters after trimming. You can specify at most 20 constraints of each type. The CLI trims leading and trailing whitespace from the goal and statements and rejects unknown fields.

  For example, configure intent on a Browser Check:

  ```ts theme={null}
  import { BrowserCheck } from "checkly/constructs"

  new BrowserCheck("dashboard-intent", {
    name: "Authenticated dashboard",
    code: {
      entrypoint: "./dashboard.spec.ts",
    },
    intent: {
      goal: "Verify that authenticated users can open the dashboard.",
      constraints: [
        {
          type: "REQUIRED_OUTCOME",
          statement: "Authentication succeeds for a valid user.",
        },
        {
          type: "MUST_PRESERVE",
          statement: "Do not remove or weaken the authentication assertion.",
        },
      ],
    },
  })
  ```
</ResponseField>

<ResponseField name="aiAutoRepairEnabled" type="boolean | null">
  Requires Checkly CLI 9.4.0 or later. Set `true` to enable automatic repair, `false` to disable it, or `null` to follow your account default. Omit the property to preserve an existing setting when you deploy.

  You also need a valid check intent. See [Configure automatic repair](../resolve/automatic-check-repair#define-intent-with-monitoring-as-code) for a complete example and repair prerequisites.
</ResponseField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.