@checkly/pulumiCheckly Pulumi Provider

Monitors in the same Pulumi program as the infrastructure they watch

Declare Checkly checks, groups, and alert channels as Pulumi resources in TypeScript, Python, Go, or .NET. They ship in the same pull request as the service, preview in the same plan, and land with the same pulumi up.

index.ts
1// index.ts
2import * as checkly from "@checkly/pulumi"
3
4new checkly.Check("products-api", {
5 name: "Products API",
6 type: "API",
7 activated: true,
8 frequency: 5,
9 locations: ["us-east-1", "eu-central-1"],
10 tags: ["pulumi", "storefront"],
11 degradedResponseTime: 3000,
12 maxResponseTime: 10000,
13 request: {
14 method: "GET",
15 url: "https://api.acme.dev/v1/products",
16 assertions: [
17 { source: "STATUS_CODE", comparison: "EQUALS", target: "200" },
18 { source: "JSON_BODY", property: "$.items", comparison: "NOT_EMPTY" },
19 ],
20 },
21 useGlobalAlertSettings: true,
22})

Trusted by teams that keep monitoring in version control

Vercel
Carhartt
CrowdStrike
Airbus
Fanatics
Mistral
ServiceNow
GoFundMe
Hopper
1Password
Fastly
Total Wine

Your infrastructure is declared. Your monitoring is the exception

Most teams that run Pulumi still click monitors together in a dashboard, so the checks drift from the services they watch and nobody reviews the change. The provider closes that gap: a check is a resource next to the load balancer it tests.

One program, one plan, one apply

Checks live in the same stack as the service. pulumi preview shows the monitor changes beside the infra changes, and one pulumi up lands both. Resource references resolve at deploy time, so a check can target the URL Pulumi just created.

pulumi previewpulumi upstack stateresource refs

The language you already write

The provider ships as an SDK for every major Pulumi language. Loop over services to generate checks, share a locations constant, wrap a check in a function your whole org calls. It is code, so it composes.

TypeScript / JavaScriptPythonGo.NET

Every Checkly resource

Not just checks. Groups, alert channels, status pages, private locations, maintenance windows, and environment variables are all resources, so the whole monitoring setup is reproducible from the repo.

CheckCheckGroupAlertChannelPlaywrightCheckSuiteUrlMonitorTcpMonitorDnsMonitorIcmpMonitorHeartbeatMonitorPrivateLocationStatusPageDashboardMaintenanceWindowEnvironmentVariableSnippet

From one check to a paged team in three resources

Define a check, group it with its neighbours, subscribe the group to an alert channel. Each step is a Pulumi resource that references the one before it.

01

Define a check

A checkly.Check is a Pulumi resource like any other. Point a BROWSER check at the Playwright spec in your repo, pick the regions and cadence, and Pulumi tracks it in state from here on.

checks.ts
1// checks.ts
2import { readFileSync } from "fs"
3import * as checkly from "@checkly/pulumi"
4
5// The Playwright spec lives next to the app code it exercises
6export const addToCart = new checkly.Check("add-to-cart", {
7 name: "Add to cart",
8 type: "BROWSER",
9 activated: true,
10 frequency: 5,
11 locations: ["us-east-1", "eu-central-1"],
12 tags: ["pulumi", "storefront"],
13 script: readFileSync("./__checks__/add-to-cart.spec.ts", "utf-8"),
14})
02

Group related checks

A checkly.CheckGroup carries shared locations, tags, and concurrency. Checks join it through groupId, which resolves from the group output at deploy time. No ID copied out of a dashboard.

checks.ts
1// checks.ts
2const storefront = new checkly.CheckGroup("storefront", {
3 name: "Storefront",
4 activated: true,
5 concurrency: 2,
6 apiCheckDefaults: {},
7 locations: ["us-east-1", "eu-central-1"],
8 tags: ["pulumi", "storefront"],
9 useGlobalAlertSettings: true,
10})
11
12new checkly.Check("add-to-cart", {
13 name: "Add to cart",
14 type: "BROWSER",
15 activated: true,
16 frequency: 5,
17 locations: ["us-east-1", "eu-central-1"],
18 script: readFileSync("./__checks__/add-to-cart.spec.ts", "utf-8"),
19 // Group membership is a resource reference, not a copied ID
20 groupId: storefront.id.apply((id) => parseInt(id)),
21})
03

Add an alert channel

A checkly.AlertChannel for Slack, email, Opsgenie, PagerDuty, or a webhook. Subscribe the group once and every check inside it pages the same place. The webhook URL stays in your environment, not in the file.

alerts.ts
1// alerts.ts
2const oncallSlack = new checkly.AlertChannel("oncall-slack", {
3 slack: {
4 url: process.env.SLACK_WEBHOOK_URL!,
5 channel: "#oncall-storefront",
6 },
7})
8
9const storefront = new checkly.CheckGroup("storefront", {
10 name: "Storefront",
11 activated: true,
12 concurrency: 2,
13 apiCheckDefaults: {},
14 locations: ["us-east-1", "eu-central-1"],
15 tags: ["pulumi", "storefront"],
16 useGlobalAlertSettings: true,
17 // Every check in the group inherits this subscription
18 alertChannelSubscriptions: [
19 { activated: true, channelId: oncallSlack.id.apply((id) => parseInt(id)) },
20 ],
21})

Three ways to write monitoring as code. Pick one.

The Checkly CLI is the primary path and gets new features first. The Pulumi and Terraform providers are for teams whose infrastructure already lives in one of those tools and who want monitoring in the same place. All three manage the same account.

primary path

Checkly CLI

TypeScript constructs, npx checkly test to run checks locally and in CI before deploying, and the fastest access to new check types. Start here unless you have a reason not to.

Monitoring as code with the CLI
this page

Pulumi provider

Your infra is a Pulumi program. Monitors become resources in it, in the same language, previewed and applied with the same command. Manage each resource in Pulumi or in the UI, never both.

Provider reference on the Pulumi registry
sibling

Terraform provider

The same resources in HCL for teams standardised on Terraform. Same account, same checks, different state file.

Checkly Terraform provider

Get started in four steps

From an empty directory to a check running in production. The full walkthrough, including the Playwright example, is in the Pulumi provider docs.

01

Create a Pulumi project

Install the Pulumi CLI, then scaffold a project in the language your infra already uses.

zsh
$ mkdir acme-monitoring && cd acme-monitoring
$ pulumi new typescript
project name: (acme-monitoring)
stack name: (dev) prod
Created stack 'prod'
Your new project is ready to go!
02

Install the provider

One package. Python, Go, and .NET teams install pulumi-checkly, the Go module, or Pulumi.Checkly instead.

zsh
$ npm install @checkly/pulumi
added 1 package in 2s
03

Provide your credentials

Your account ID and an API key from app.checklyhq.com. Set them as environment variables, or store them on the stack with pulumi config set so the whole team shares them.

zsh
$ export CHECKLY_ACCOUNT_ID=<your-account-id>
$ export CHECKLY_API_KEY=cu_<your-api-key>
# or, scoped to the stack and encrypted at rest:
$ pulumi config set checkly:accountId <your-account-id>
$ pulumi config set checkly:apiKey cu_<your-api-key> --secret
04

Preview, then apply

pulumi up shows the diff first. Confirm it and the checks exist in Checkly seconds later, tracked in state.

zsh
$ pulumi up
Previewing update (prod)
+ checkly:index:Check products-api create
Do you want to perform this update? yes
+ checkly:index:Check products-api created (2s)

One owner per resource

Resources created by Pulumi should be changed through Pulumi. Editing them in the Checkly web app creates drift the next pulumi up will overwrite or fail on. If you want to explore in the UI first, do it on checks Pulumi does not manage.

@checkly/pulumi 2.xpulumi-checklyPulumi.Checklyopen source on GitHub

Put monitoring in the same pull request

Install @checkly/pulumi, declare a check next to the service it watches, and run pulumi up. The next review of your infra includes the monitoring too.

No credit card required.