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

# Checkly Quickstart

> Add synthetic monitoring to your existing project in minutes. Let your AI agent set up Checkly, or follow the steps yourself.

export const SetupFlow = () => {
  const steps = [{
    label: "Setup",
    icon: "terminal",
    detail: <span>
          Execute <code className="cklyflow-code">npx checkly init</code> to
          automatically install the <code className="cklyflow-code">checkly</code>{" "}
          CLI and the Checkly agent skills, and scaffold a{" "}
          <code className="cklyflow-code">checkly.config.ts</code>.
        </span>
  }, {
    label: "Generate",
    icon: "agent",
    detail: <span>
          Paste the provided prompt into your AI agent. It scans and parses your
          project, then creates monitoring resources using Checkly constructs.
        </span>
  }, {
    label: "Test",
    icon: "testing",
    detail: <span>
          Run <code className="cklyflow-code">npx checkly test</code> to validate
          your monitoring setup before it goes live.
        </span>
  }, {
    label: "Deploy",
    icon: "deploy",
    detail: <span>
          Deploy your code-defined monitoring with a single command:{" "}
          <code className="cklyflow-code">npx checkly deploy</code>.
        </span>
  }, {
    label: "Monitor",
    icon: "globe",
    detail: <span>
          Monitor your application from global locations and get alerted the
          moment something breaks.
        </span>
  }];
  const stepGap = 0.5;
  const columns = steps.map((step, i) => i < steps.length - 1 ? "3.5rem 1fr" : "3.5rem").join(" ");
  const renderIcon = name => {
    const common = {
      width: 24,
      height: 24,
      viewBox: "0 0 24 24",
      fill: "none",
      stroke: "currentColor",
      strokeWidth: 1.7,
      strokeLinecap: "round",
      strokeLinejoin: "round",
      "aria-hidden": true
    };
    if (name === "terminal") {
      return <svg {...common}>
          <rect x="3.5" y="5" width="17" height="14" rx="1.5" />
          <path d="M7 9.5l3 2.5-3 2.5M12.5 15h4" />
        </svg>;
    }
    if (name === "agent") {
      return <svg {...common} stroke="none" fill="currentColor">
          <path d="M12 3l1.6 4.4L18 9l-4.4 1.6L12 15l-1.6-4.4L6 9l4.4-1.6L12 3Z" />
          <path d="M18.5 14l.7 1.9 1.9.7-1.9.7-.7 1.9-.7-1.9-1.9-.7 1.9-.7.7-1.9Z" />
        </svg>;
    }
    if (name === "testing") {
      return <svg {...common}>
          <path d="M20 6L9 17l-5-5" />
        </svg>;
    }
    if (name === "deploy") {
      return <svg {...common}>
          <path d="M12 3v12M7 8l5-5 5 5M5 21h14" />
        </svg>;
    }
    return <svg {...common}>
        <circle cx="12" cy="12" r="8.5" />
        <path d="M3.5 12h17M12 3.5c2.5 2.4 2.5 14.6 0 17M12 3.5c-2.5 2.4-2.5 14.6 0 17" />
      </svg>;
  };
  const [played, setPlayed] = useState(false);
  const [selected, setSelected] = useState(0);
  useEffect(() => {
    const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const node = document.getElementById("cklyflow-root");
    if (reduce || !node || typeof IntersectionObserver === "undefined") {
      setPlayed(true);
      return;
    }
    const observer = new IntersectionObserver(function (entries) {
      const entry = entries[0];
      if (entry && entry.isIntersecting) {
        setPlayed(true);
        observer.disconnect();
      }
    }, {
      threshold: 0.35
    });
    observer.observe(node);
    return function () {
      observer.disconnect();
    };
  }, []);
  return <div id="cklyflow-root" className={`cklyflow my-6 ${played ? "cklyflow-played" : ""}`}>
      <style>{`
        .cklyflow {
          --ckly-rest-border:#e5e7eb; --ckly-rest-icon:#9ca3af; --ckly-rest-bg:#ffffff;
          --ckly-blue:#0075ff; --ckly-blue-bg:rgba(0,117,255,0.08); --ckly-blue-icon:#0075ff;
          --ckly-line:#e5e7eb;
        }
        .dark .cklyflow {
          --ckly-rest-border:#374151; --ckly-rest-icon:#6b7280; --ckly-rest-bg:rgba(255,255,255,0.02);
          --ckly-blue:#3b9bff; --ckly-blue-bg:rgba(0,117,255,0.16); --ckly-blue-icon:#5aa9ff;
          --ckly-line:#374151;
        }
        .cklyflow-rail { display:none; }
        @media (min-width:640px) {
          .cklyflow-rail {
            display:grid;
            grid-template-columns:var(--ckly-cols);
            align-items:center;
            column-gap:.5rem;
            row-gap:.85rem;
          }
        }
        .cklyflow-list { display:flex; flex-direction:column; }
        .cklyflow-list-row { display:flex; gap:.9rem; align-items:stretch; }
        .cklyflow-list-rail { display:flex; flex-direction:column; align-items:center; flex:0 0 auto; }
        .cklyflow-list-line { flex:1 0 auto; width:2px; min-height:.85rem; margin:.4rem 0; border-radius:9999px; }
        .cklyflow-list-text { padding-bottom:1.4rem; }
        .cklyflow-list-row:last-child .cklyflow-list-text { padding-bottom:0; }
        .cklyflow-detail-box { display:none; }
        @media (min-width:640px) {
          .cklyflow-list { display:none; }
          .cklyflow-detail-box { display:block; }
        }
        .cklyflow-tile {
          border:1px solid var(--ckly-rest-border);
          background:var(--ckly-rest-bg);
          color:var(--ckly-rest-icon);
          padding:0;
          cursor:pointer;
          transition:
            border-color .4s ease var(--ckly-d,0s),
            background-color .4s ease var(--ckly-d,0s),
            color .4s ease var(--ckly-d,0s),
            transform .2s ease,
            box-shadow .2s ease;
        }
        @media (min-width:640px) { .cklyflow-tile { justify-self:center; } }
        .cklyflow-played .cklyflow-tile {
          border-color:var(--ckly-blue);
          background:var(--ckly-blue-bg);
          color:var(--ckly-blue-icon);
        }
        .cklyflow-tile.is-active {
          transform:scale(1.08);
          box-shadow:0 0 0 4px rgba(0,117,255,.18), 0 8px 20px -6px rgba(0,117,255,.5);
        }
        .cklyflow-tile:focus-visible { outline:2px solid var(--ckly-blue); outline-offset:2px; }
        .cklyflow-code {
          font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
          font-size:.85em;
          background:rgba(0,0,0,.05);
          padding:.1em .35em;
          border-radius:.35em;
        }
        .dark .cklyflow-code { background:rgba(255,255,255,.1); }
        .cklyflow-line {
          position:relative; overflow:hidden; border-radius:9999px;
          width:100%; height:2px; background:var(--ckly-line);
        }
        .cklyflow-conn-v { position:relative; overflow:hidden; background:var(--ckly-line); }
        .cklyflow-fill-h, .cklyflow-fill-v { position:absolute; inset:0; background:var(--ckly-blue); }
        .cklyflow-fill-h {
          transform:scaleX(0); transform-origin:left center;
          transition:transform .4s ease var(--ckly-d,0s);
        }
        .cklyflow-fill-v {
          transform:scaleY(0); transform-origin:top center;
          transition:transform .4s ease var(--ckly-d,0s);
        }
        .cklyflow-played .cklyflow-fill-h { transform:scaleX(1); }
        .cklyflow-played .cklyflow-fill-v { transform:scaleY(1); }
        @media (prefers-reduced-motion: reduce) {
          .cklyflow-tile, .cklyflow-fill-h, .cklyflow-fill-v { transition:none !important; }
        }
      `}</style>

      <div className="rounded-2xl border border-gray-200 dark:border-gray-800 bg-gray-50/60 dark:bg-white/[0.02] p-6 sm:p-7">
        <div className="cklyflow-rail" style={{
    "--ckly-cols": columns
  }} aria-label="The Checkly workflow: setup, generate, test, deploy, monitor">
          {steps.flatMap((step, i) => {
    const isActive = selected === i;
    const tileCol = String(2 * i + 1);
    const items = [<button key={`${step.label}-tile`} type="button" aria-label={step.label} aria-pressed={isActive} aria-controls="cklyflow-detail" onFocus={() => setSelected(i)} onClick={() => setSelected(i)} className={`cklyflow-tile ${isActive ? "is-active" : ""} rounded-2xl w-14 h-14 flex items-center justify-center`} style={{
      "--ckly-d": `${i * stepGap}s`,
      gridColumn: tileCol,
      gridRow: "1"
    }}>
                {renderIcon(step.icon)}
              </button>, <div key={`${step.label}-label`} className={`text-sm font-semibold text-center transition-colors ${isActive ? "text-gray-900 dark:text-white" : "text-gray-700 dark:text-gray-200"}`} style={{
      gridColumn: tileCol,
      gridRow: "2",
      justifySelf: "center",
      whiteSpace: "nowrap"
    }}>
                {step.label}
              </div>];
    if (i < steps.length - 1) {
      items.push(<div key={`${step.label}-line`} aria-hidden="true" className="cklyflow-line" style={{
        "--ckly-d": `${i * stepGap + 0.2}s`,
        gridColumn: String(2 * i + 2),
        gridRow: "1"
      }}>
                  <span className="cklyflow-fill-h" />
                </div>);
    }
    return items;
  })}
        </div>

        <div className="cklyflow-list" aria-label="The Checkly workflow: setup, generate, test, deploy, monitor">
          {steps.map((step, i) => <div key={`${step.label}-row`} className="cklyflow-list-row">
              <div className="cklyflow-list-rail">
                <div className="cklyflow-tile rounded-2xl w-12 h-12 flex items-center justify-center" style={{
    "--ckly-d": `${i * stepGap}s`,
    cursor: "default"
  }}>
                  {renderIcon(step.icon)}
                </div>
                {i < steps.length - 1 && <div aria-hidden="true" className="cklyflow-conn-v cklyflow-list-line" style={{
    "--ckly-d": `${i * stepGap + 0.2}s`
  }}>
                    <span className="cklyflow-fill-v" />
                  </div>}
              </div>
              <div className="cklyflow-list-text">
                <div className="text-sm font-semibold text-gray-900 dark:text-white">
                  {step.label}
                </div>
                <p className="text-sm text-gray-600 dark:text-gray-300 leading-relaxed mt-1 mb-0">
                  {step.detail}
                </p>
              </div>
            </div>)}
        </div>

        <div id="cklyflow-detail" className="cklyflow-detail-box mt-5 sm:mt-6 pt-5 border-t border-gray-200/80 dark:border-gray-800 min-h-[64px]">
          <p className="text-sm text-gray-600 dark:text-gray-300 leading-relaxed m-0">
            <span className="font-semibold text-gray-900 dark:text-white">
              {steps[selected].label}.
            </span>{" "}
            {steps[selected].detail}
          </p>
        </div>
      </div>
    </div>;
};

Add synthetic monitoring to a project you already have, in any language or framework, in minutes. You'll end up with checks running around the clock from global locations, alerting you the moment your site or API breaks. The fastest path is to let your AI coding agent set it up: `npx checkly init` installs the [Checkly CLI](/cli/overview) and [agent skills](/ai/skills), and from there your agent can generate, test, and deploy your monitoring as [Monitoring as Code](/concepts/monitoring-as-code) that lives alongside your application code.

The steps below explain each phase so you understand what the agent does, and you can run them yourself if you prefer.

<SetupFlow />

*The recommended flow, end to end. Each phase is explained below.*

## Get started with Monitoring as Code

<Accordion title="Prerequisites">
  * [Node.js](https://nodejs.org) `20.19+` or `22.12+`, and npm
  * A terminal
  * (Optional) the URL of an app or API you want to monitor
</Accordion>

### Let your AI agent set it up (recommended)

Run `npx checkly init` and answer a few prompts to let your agent take over:

```text Terminal theme={null}
npx checkly init

✔ Do you want your AI agent to set up Checkly? … yes
✔ Install the Checkly skill for your AI coding agent? … yes
✔ Which AI coding agent do you use? › Claude
✔ Run npm install to install them now? … yes

...

✔ Copy prompt to clipboard? … yes

You're ready to go!
```

`checkly init` installs the [Checkly CLI](/cli/overview) and [agent skills](/ai/skills), creates a `checkly.config.ts`, installs dependencies, and **copies a starter prompt tailored to your project to your clipboard**. Paste it into your AI agent and follow the instructions.

From here, what the agent does depends on your project. It might:

* Scan your project and discover monitoring targets
* Create Checkly monitors in code
* Test them with `npx checkly test`
* Set up alert channels
* Reuse your existing Playwright tests
* Deploy your monitoring with `npx checkly deploy` after your confirmation

It asks for input along the way. Open [your Checkly dashboard](https://app.checklyhq.com) to see your monitoring live.

To see what each command does, or to run them yourself, follow the [steps below](#set-it-up-yourself).

### Set it up yourself

The steps below use the Checkly CLI directly so you can build and deploy your monitoring by hand.

<Steps>
  <Step title="Bootstrap a Checkly project">
    Run the init command in your project directory and decline the agent setup. It scaffolds a working example you can edit.

    ```text Terminal theme={null}
    npx checkly init

    ✔ Do you want your AI agent to set up Checkly? … no
    ✔ Run npm install to install them now? … yes
    ✔ Add some demo checks to get started? … yes
    ✔ Created __checks__/ with example checks

    ...

    All done!
    ```

    This scaffolds a `checkly.config.ts` file and a `__checks__` folder containing a few starter checks:

    ```bash Project structure theme={null}
    |- checkly.config.ts
    |__checks__
        |- api.check.ts
        |- heartbeat.check.ts
        |- homepage.spec.ts
        |- url.check.ts
    ```

    The `checkly.config.ts` file holds your project-wide settings, such as the default run frequency, locations, and which files contain your checks.
  </Step>

  <Step title="Log in to Checkly">
    Log in to your Checkly account, or create a free one, right from the terminal.

    ```bash Terminal theme={null}
    npx checkly login
    ```

    This opens your browser to authenticate. Once you're logged in, you can run and deploy checks from your machine. Run `npx checkly whoami` at any time to confirm which account you're connected to.
  </Step>

  <Step title="Write your first check">
    Checks are code. The scaffolded `__checks__/homepage.spec.ts` is a [Browser Check](/detect/synthetic-monitoring/browser-checks/quickstart): a standard `@playwright/test` file that Checkly runs as a monitor. Edit it to load a page and assert on what matters:

    <CodeGroup dropdown>
      ```ts homepage.spec.ts theme={null}
      import { test, expect } from '@playwright/test'

      test('homepage loads', async ({ page }) => {
        const response = await page.goto('https://www.checklyhq.com')
        expect(response?.status()).toBeLessThan(400)
        await expect(page).toHaveTitle(/Checkly/)
        await page.screenshot({ path: 'homepage.jpg' })
      })
      ```

      ```js homepage.spec.js theme={null}
      const { test, expect } = require('@playwright/test')

      test('homepage loads', async ({ page }) => {
        const response = await page.goto('https://www.checklyhq.com')
        expect(response?.status()).toBeLessThan(400)
        await expect(page).toHaveTitle(/Checkly/)
        await page.screenshot({ path: 'homepage.jpg' })
      })
      ```
    </CodeGroup>

    Checkly turns every `*.spec.ts` file into a Browser Check through the `browserChecks.testMatch` pattern in your `checkly.config.ts`. To monitor an endpoint instead, edit `__checks__/api.check.ts`, which defines an [API Check](/detect/synthetic-monitoring/api-checks/quickstart). For every construct and option, see the [Constructs reference](/constructs/overview).
  </Step>

  <Step title="Run your checks locally">
    Dry-run all your checks against Checkly's global infrastructure before you deploy anything:

    ```bash Terminal theme={null}
    npx checkly test
    ```

    You'll see the results in your terminal:

    ```
    Running 2 checks in eu-west-1.

    __checks__/homepage.spec.ts
      ✔ homepage loads (24s)
    __checks__/api.check.ts
      ✔ Hello API (222ms)

    2 passed, 2 total
    ```

    Runs are recorded as [test sessions](/detect/testing/overview) by default, with full logs, traces, and videos you can review in the [Checkly web app](https://app.checklyhq.com).
  </Step>

  <Step title="Deploy to production">
    Deploy your checks and related resources to Checkly. From now on, they run around the clock from Checkly's global locations:

    ```bash Terminal theme={null}
    npx checkly deploy
    ```

    Open [your Checkly dashboard](https://app.checklyhq.com) and you'll see your checks, ready to start monitoring.
  </Step>

  <Step title="Set up alerts">
    Add an [alert channel](/communicate/alerts/overview) so you're notified when a check fails. Define the channels you want in a new `__checks__/alert-channels.ts` file, then attach them to your checks through the `alertChannels` defaults in your config.

    <Tabs>
      <Tab title="Email">
        ```ts alert-channels.ts theme={null}
        import { EmailAlertChannel } from 'checkly/constructs'

        export const emailChannel = new EmailAlertChannel('email-alert-channel', {
          address: 'alerts@example.com',
        })
        ```
      </Tab>

      <Tab title="Phone">
        ```ts alert-channels.ts theme={null}
        import { PhoneCallAlertChannel } from 'checkly/constructs'

        export const phoneChannel = new PhoneCallAlertChannel('phone-alert-channel', {
          name: 'On-call engineer',
          phoneNumber: '+1234567890',
        })
        ```
      </Tab>
    </Tabs>

    Import the channels you defined and set them as defaults in your `checkly.config.ts` so every check, including your Browser Check, uses them. This example assumes you defined both, so import only the channels you created:

    ```ts checkly.config.ts theme={null}
    import { defineConfig } from 'checkly'
    import { emailChannel, phoneChannel } from './__checks__/alert-channels'

    export default defineConfig({
      projectName: 'My Project',
      logicalId: 'my-project',
      checks: {
        // ...your existing check defaults
        alertChannels: [emailChannel, phoneChannel],
      },
    })
    ```

    You can also attach `alertChannels` to an individual check or a [check group](/constructs/check-group-v2) for finer control. Run `npx checkly deploy` again to apply your alerting, and see the [alert channels overview](/communicate/alerts/channels) for every supported channel.
  </Step>
</Steps>

<Note>
  When you're done experimenting, tear down everything this project created with `npx checkly destroy`.
</Note>

## Go deeper

<Columns cols={2}>
  <Card title="Constructs reference" href="/constructs/overview">
    Every check, monitor, and alert channel you can define as code.
  </Card>

  <Card title="CLI reference" href="/cli/overview">
    All `npx checkly` commands and options.
  </Card>

  <Card title="Browser Checks" href="/detect/synthetic-monitoring/browser-checks/quickstart">
    Monitor realistic user flows with Playwright.
  </Card>

  <Card title="API Checks" href="/detect/synthetic-monitoring/api-checks/quickstart">
    Monitor your backend services and endpoints.
  </Card>

  <Card title="Alerts" href="/communicate/alerts/overview">
    Configure who gets notified, and how.
  </Card>

  <Card title="CI/CD integration" href="/integrations/ci-cd/overview">
    Run and deploy your checks from your pipeline.
  </Card>
</Columns>
