From an empty folder to a scheduled check

Create your first Selfchecks project

Keep monitoring next to your application code, run the same checks in CI, and deploy them to your own Selfchecks server.

  1. 01CreateScaffold a Node.js project
  2. 02ConfigureSet project defaults
  3. 03TestAdd API and browser checks
  4. 04DeployUpload to your server

Step 1

Create the project

Selfchecks executes the project's .check.ts manifests and compiles supported constructs into a versioned deployment manifest. Imports, local helpers, loops, and computed definitions work like normal TypeScript.

Terminal
npx create-selfchecks my-checks
cd my-checks
npx playwright install chromium
npm test
Project structure
my-checks/
├── package.json
├── playwright.config.ts
├── checkly.config.ts
└── checks/
    ├── homepage.check.ts
    └── homepage.spec.ts

Step 2

Add configuration

Playwright controls test behavior. The Checkly-compatible config defines project discovery and scheduling defaults using the current construct API.

playwright.config.ts
import { defineConfig } from "@playwright/test";

export default defineConfig({
  timeout: 60_000,
  globalTimeout: 10 * 60_000,
  use: {
    baseURL: process.env.ENVIRONMENT_URL,
    screenshot: "only-on-failure",
  },
});
checkly.config.ts
import { defineConfig } from "@selfchecks/selfchecks";
import { Frequency } from "@selfchecks/selfchecks/constructs";

export default defineConfig({
  projectName: "My checks",
  logicalId: "my-checks",
  checks: {
    activated: true,
    frequency: Frequency.EVERY_10M,
    tags: ["production"],
  },
});

Step 3

Write a browser check

A browser check is a small manifest pointing to a normal Playwright Test spec. Selfchecks runs it in Chromium and records logs, screenshots, traces, videos, and performance data when available.

checks/homepage.check.ts
import { BrowserCheck, Frequency } from "@selfchecks/selfchecks/constructs";

new BrowserCheck("homepage", {
  name: "Homepage",
  activated: true,
  tags: ["smoke", "browser"],
  frequency: Frequency.EVERY_10M,
  code: {
    entrypoint: "homepage.spec.ts",
  },
});
checks/homepage.spec.ts
import { expect, test } from "@playwright/test";

test("homepage is available", async ({ page }) => {
  await page.goto("/");
  await expect(page).toHaveTitle(/My product/i);
  await expect(page.getByRole("main")).toBeVisible();
});
Selfchecks browser run report showing duration, error counts, the Playwright test report, traces, and logs.
A recorded browser run keeps the Playwright report, traces, logs, screenshots, videos, and error counts next to the result.

API checks

Choose the right API testing style

Use a native ApiCheck for a portable endpoint monitor with status, timing, header, text, and JSON assertions. Use the Playwright request fixture for multi-step flows.

Option Use it for Available API
ApiCheck Fast health and HTTP status checks Method, URL, query, headers, body, Basic Auth, redirects, assertions, and {{ENV}} placeholders
Playwright request JSON assertions and multi-step API flows test, expect, request fixture, hooks, and helpers
checks/health.check.ts
import {
  ApiCheck,
  AssertionBuilder,
  Frequency,
} from "@selfchecks/selfchecks/constructs";

new ApiCheck("api-health", {
  name: "API health",
  activated: true,
  tags: ["smoke", "api"],
  frequency: Frequency.EVERY_5M,
  maxResponseTime: 2_000,
  request: {
    method: "GET",
    url: "{{ENVIRONMENT_URL}}/api/health",
    headers: {
      accept: "application/json",
    },
    queryParameters: {
      probe: "selfchecks",
    },
    assertions: [
      AssertionBuilder.statusCode().equals(200),
      AssertionBuilder.jsonBody("$.data.ok").equals(true),
      AssertionBuilder.headers("content-type").contains("application/json"),
      AssertionBuilder.responseTime().lessThan(2_000),
    ],
  },
});

Dependencies

Modules you can use in tests

Remote runs install production dependencies from the uploaded package.json, keeping the runtime reproducible.

Playwright Test

test, expect, page, context, request, fixtures, and hooks.

Node.js built-ins

Modules such as node:crypto, node:fs, node:path, and node:url.

Your local modules

Relative TypeScript or JavaScript helpers included in the uploaded project.

npm packages

Packages in dependencies that support the server's Linux and Node.js runtime.

Migration

Keep existing Checkly imports

You do not have to rewrite every manifest. npm can install the Selfchecks constructs package under the local name checkly, so existing checkly and checkly/constructs imports remain valid.

package.json
{
  "devDependencies": {
    "@selfchecks/selfchecks-cli": "latest",
    "checkly": "npm:@selfchecks/selfchecks@latest"
  },
  "scripts": {
    "selfchecks": "selfchecks"
  }
}
Import Supported subset
checkly defineConfig
Checks ApiCheck, BrowserCheck
Groups CheckGroup, CheckGroupV2
Frequency EVERY_1M, EVERY_2M, EVERY_5M, EVERY_10M, EVERY_15M, EVERY_30M, EVERY_1H, EVERY_2H, EVERY_3H, EVERY_6H, EVERY_12H, EVERY_24H
Assertions Status, response-time, header, text-body, and JSON-body assertions with equality, ordering, containment, key/value, empty, and null comparisons
Retries noRetries, fixedStrategy, linearStrategy, exponentialStrategy, singleRetry
Source compatibility WebhookAlertChannel through a group, plus the related props and request types

Step 4

Deploy and run

Use deploy for the version scheduled checks should run, test for an isolated CI session, and trigger to run the latest deployment.

One-time CLI setup
export SELFCHECKS_URL="https://checks.example.com"
export SELFCHECKS_API_TOKEN="<api-token>"

npx selfchecks --help
Deploy and execute
# Upload the project and schedule its checks
selfchecks deploy --project my-project --root .

# Run the current source and keep the results
selfchecks test --project my-project --root . --record \
  -e ENVIRONMENT_URL=https://staging.example.com

# Run the latest deployed version
selfchecks trigger --project my-project --record
Selfchecks test sessions list showing CI release sessions with passed, failed, timed out, and cancelled results.
Recorded CI runs appear as test sessions with project, duration, and passed, failed, running, or queued counts.

Integration

Use the HTTP API directly

The CLI is a client for the authenticated Selfchecks HTTP API. Call it directly to trigger a deployment, inspect status, or build another integration.

Trigger a deployed project
curl --fail-with-body --request POST \
  "$SELFCHECKS_URL/api/cli/triggers" \
  --header "Authorization: Bearer $SELFCHECKS_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "projectSlug": "my-project",
    "reporter": "list",
    "testSessionName": "Manual API run",
    "env": [
      {
        "name": "ENVIRONMENT_URL",
        "value": "https://staging.example.com"
      }
    ]
  }'
202 Accepted
{
  "triggerId": "b472b7ce-…",
  "status": "queued",
  "statusUrl": "/api/cli/triggers/b472b7ce-…"
}
Method Endpoint Purpose
POST /api/cli/deployments Upload a multipart project bundle and queue a deployment
GET /api/cli/deployments/:deploymentId Read deployment status and import summary
POST /api/cli/test-sessions Upload source and start a recorded test session
GET · DELETE /api/cli/test-sessions/:sessionId Read results or cancel an active session
POST /api/cli/triggers Run the latest deployed source for a project
GET /api/cli/triggers/:triggerId Read trigger status and final run summary

CI/CD

Set up GitLab CI/CD

Run the current commit for merge requests and the default branch, then deploy the successful default-branch revision for scheduled monitoring.

.gitlab-ci.yml
stages:
  - test
  - deploy

default:
  image: node:20.19
  before_script:
    - npm ci

selfchecks:test:
  stage: test
  script:
    - >-
      npx selfchecks test
      --project "$CI_PROJECT_PATH_SLUG"
      --root .
      --record
      --reporter list
      --test-session-name "GitLab #$CI_PIPELINE_IID"
      --repository "$CI_PROJECT_PATH"
      --ref "$CI_COMMIT_REF_NAME"
      --commit-sha "$CI_COMMIT_SHA"
      --pipeline-url "$CI_PIPELINE_URL"
      --job-url "$CI_JOB_URL"
      -e "ENVIRONMENT_URL=$ENVIRONMENT_URL"
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

selfchecks:deploy:
  stage: deploy
  needs: ["selfchecks:test"]
  script:
    - npx selfchecks deploy --project "$CI_PROJECT_PATH_SLUG" --root .
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

CI/CD

Set up GitHub Actions

Run checks for pull requests and main, then deploy the main revision after the test job succeeds.

.github/workflows/selfchecks.yml
name: Selfchecks

on:
  pull_request:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      SELFCHECKS_URL: ${{ vars.SELFCHECKS_URL }}
      SELFCHECKS_API_TOKEN: ${{ secrets.SELFCHECKS_API_TOKEN }}
      ENVIRONMENT_URL: ${{ vars.ENVIRONMENT_URL }}
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - name: Run Selfchecks
        run: >-
          npx selfchecks test
          --project "$GITHUB_REPOSITORY"
          --root .
          --record
          --reporter github
          --test-session-name "GitHub #$GITHUB_RUN_NUMBER"
          --repository "$GITHUB_REPOSITORY"
          --ref "$GITHUB_REF_NAME"
          --commit-sha "$GITHUB_SHA"
          --pipeline-url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
          -e "ENVIRONMENT_URL=$ENVIRONMENT_URL"

  deploy:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: test
    runs-on: ubuntu-latest
    env:
      SELFCHECKS_URL: ${{ vars.SELFCHECKS_URL }}
      SELFCHECKS_API_TOKEN: ${{ secrets.SELFCHECKS_API_TOKEN }}
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npx selfchecks deploy --project "$GITHUB_REPOSITORY" --root .

Self-hosting

Deploy your own server

Selfchecks ships as a Docker Compose stack with the web app, worker, PostgreSQL, Redis, migrations, and Caddy for HTTPS.

Linux server
curl -fsSL https://github.com/selfchecks/selfchecks/releases/download/bootstrap/bootstrap.sh | sudo bash