<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Checkly Blog: Monitoring Insights & Trends]]></title><description><![CDATA[Learn about the latest tips, tricks & how-to articles on advanced synthetic monitoring, Playwright & Monitoring as Code trends.]]></description><link>https://www.checklyhq.com/blog</link><image><url>https://www.checklyhq.com/favicon-32x32.png</url><title>Checkly Blog: Monitoring Insights &amp; Trends</title><link>https://www.checklyhq.com/blog</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 11:49:43 GMT</lastBuildDate><atom:link href="https://www.checklyhq.com/blog/rss" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[We Let AI Agents Rewrite a 92M-Message-a-Day Service in Go. Zero Incidents.]]></title><description><![CDATA[How Checkly rewrote a Node.js service handling 92M messages a day into Go using AI agents, and the test harness that made it safe to ship.]]></description><link>https://www.checklyhq.com/blog/agentic-rewrite-nodejs-to-go</link><guid isPermaLink="false">apaJdRIAAC0AgdhI</guid><category><![CDATA[AI]]></category><category><![CDATA[Development]]></category><category><![CDATA[Playwright]]></category><dc:creator><![CDATA[Edvinas Janusevicius]]></dc:creator><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;Our Results Daemon processes about 92 million messages a day. We recently rewrote it from Node.js to Go, and we let Claude Code write it.&lt;/p&gt;&lt;p&gt;We wanted to know whether we could trust an agentic rewrite for a critical, high-throughput production service rather than a prototype. It shipped with zero incidents, a 70% reduction in running pods, and a lighter database load. Go&amp;#x27;s stronger type system also proved a better fit for agents than JavaScript, adding protection against regressions and letting us ship faster and with more confidence.&lt;/p&gt;&lt;p&gt;What made it work was the test harness we built before the agent wrote a line. Here&amp;#x27;s how we designed it, and the principles you can reuse on your own legacy services.&lt;/p&gt;&lt;h2 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Checkly is a monitoring platform that runs synthetic checks, automated scripts that emulate real users, and uptime checks that confirm a system component is operational. A runner component executes all of these and produces a result that has to be processed, stored, and alerted on.&lt;/p&gt;&lt;p&gt;Since we introduced uptime checks, and with the company&amp;#x27;s overall growth, the volume of checks run on our platform has doubled over the last year. Some components started degrading under that load. The most notable one was Results Daemon, a Node.js component written in vanilla JavaScript.&lt;/p&gt;&lt;p&gt;Results Daemon is a background worker. It consumes results from our runner, writes them to databases, determines the check outcome, issues alerts, and schedules retries as needed. It also publishes WebSocket updates to our CLI and UI. In total, &lt;strong&gt;this component processes approximately 92,000,000 messages every day&lt;/strong&gt;, around 40,000,000 of them check results and the rest WebSocket publishes.&lt;/p&gt;&lt;p&gt;At that scale, it was becoming a bottleneck. It paged our on-call engineers more often, and limited type safety made every change harder to land safely. So we decided to rewrite Results Daemon in Go using agentic engineering.&lt;/p&gt;&lt;h2 id=&quot;designing-a-test-harness&quot;&gt;&lt;a href=&quot;#designing-a-test-harness&quot;&gt;Designing a test harness&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;We built the harness before we started the rewrite. If an agent is going to write the code, something other than a human reviewer has to define what correct means.&lt;/p&gt;&lt;p&gt;We built it on these design principles:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The harness tests the component as a black box. There is zero coupling between the code or language of the system under test and the harness itself.&lt;/li&gt;&lt;li&gt;Every test case provides an input and expects a deterministic output, with all outputs recorded in &amp;quot;golden files.&amp;quot; These are generated against the legacy system and later used by the rewrite to assert byte-to-byte parity.&lt;/li&gt;&lt;li&gt;Non-deterministic fields, such as UUIDs or timestamps generated during the test itself, are written as &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;&amp;lt;uuid&amp;gt;&lt;/code&gt; or &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;&amp;lt;timestamp&amp;gt;&lt;/code&gt; and are still type-checked, to minimize the risk of differences in behavior slipping through.&lt;/li&gt;&lt;li&gt;Surrounding components (databases, queues, caches, other services) are categorized as boundaries. These are managed strictly by the harness, and the system under test is only pointed at them using environment variables.&lt;/li&gt;&lt;li&gt;Boundaries use real instances of the service in testing. If data is written to PostgreSQL, the harness uses a real PostgreSQL container rather than an emulated one.&lt;/li&gt;&lt;li&gt;For simpler boundaries such as SQS queues, we built our own emulator instead of using ElasticMQ or LocalStack. We found it more performant and simpler, both in our tests and in our assertions.&lt;/li&gt;&lt;li&gt;A set of &amp;quot;oracle&amp;quot; classes fetches the test output and asserts whether the test failed. For example, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;PostgresOracle.expectResultToMatchSnapshot(testId)&lt;/code&gt; fetches the relevant output and asserts its byte-level accuracy against the established golden file.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Three technical choices carried the harness:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Playwright&lt;/strong&gt;, a testing framework built for reliability, with strong tooling for network interception and parallel test execution. Our own synthetic monitoring offering is built on Playwright, so we already knew it well, and its black-box model fit what we were doing here.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt;, the simplest way to start and tear down containers for our boundaries, both locally and in CI.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Toxiproxy&lt;/strong&gt;, a TCP proxy that emulates network conditions and let us test how the system behaves when surrounding infrastructure fails.&lt;/li&gt;&lt;/ul&gt;&lt;section&gt;&lt;img alt=&quot;Checkly test harness architecture: input and output boundaries, oracle classes, and the Results Daemon as the system under test&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;1472&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;my-2 border border-gray-300 border-solid rounded-lg cursor-pointer border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/X6aWeJO4EvODKqFR_01-test-harness-architecture.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/X6aWeJO4EvODKqFR_01-test-harness-architecture.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;div class=&quot;cursor-pointer hidden&quot;&gt;&lt;div class=&quot;fixed inset-0 z-[99999] bg-black bg-opacity-50 transition-opacity&quot; aria-hidden=&quot;true&quot;&gt;&lt;/div&gt;&lt;div class=&quot;fixed inset-0 z-[99999] p-6 flex items-center h-full max-w-5xl mx-auto&quot;&gt;&lt;img alt=&quot;Checkly test harness architecture: input and output boundaries, oracle classes, and the Results Daemon as the system under test&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;1472&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;w-full max-h-full overflow-hidden border border-gray-300 border-solid rounded-lg border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/X6aWeJO4EvODKqFR_01-test-harness-architecture.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/X6aWeJO4EvODKqFR_01-test-harness-architecture.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;h2 id=&quot;building-test-cases&quot;&gt;&lt;a href=&quot;#building-test-cases&quot;&gt;Building test cases&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;With the architecture settled, the next step was building actual test cases. Results Daemon&amp;#x27;s outputs depend on two things:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The check result, the data object representing the outcome of a check execution. It holds the outcome state of the check run (Failed | Degraded | Success) and other metadata.&lt;/li&gt;&lt;li&gt;The check configuration at the time the result was received: retry rules for rescheduling, alert rules for notifications, and so on.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;From there it followed quickly that behavior coverage depends directly on the diversity of the inputs. A harness that covers every combination of check result and configuration covers every possible code path, with zero coupling to the implementation. That gave us our first principle:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The quality of the harness depends on the quality of the inputs you can provide. The more diverse and realistic the inputs, the greater the coverage of code paths and behaviors. In our case, the number of outcomes is represented by &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;(accountConfigs × groupConfigs × checkConfigs × resultOutcomes)&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We generated those inputs from our internal data lake. We extracted all account, group, and check configurations along with every result outcome from the last 24 hours, which is the longest interval we schedule checks at. We loaded all of it into a ClickHouse instance, and each dataset was &amp;quot;collapsed&amp;quot; into a unique set of configurations and outcomes, each tagged with its number of occurrences. We then used that data to seed realistic scenarios and pin them to business rules. For example, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;a re-dispatch takes its runtime from the account when the job pins none&lt;/code&gt;.&lt;/p&gt;&lt;section&gt;&lt;img alt=&quot;Test input generation: an agent proposes cases while account, group, check and result data flows from the data lake into ClickHouse&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;900&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;my-2 border border-gray-300 border-solid rounded-lg cursor-pointer border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/hLxTnObQCOmJHb5N_02-test-input-generation.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/hLxTnObQCOmJHb5N_02-test-input-generation.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;div class=&quot;cursor-pointer hidden&quot;&gt;&lt;div class=&quot;fixed inset-0 z-[99999] bg-black bg-opacity-50 transition-opacity&quot; aria-hidden=&quot;true&quot;&gt;&lt;/div&gt;&lt;div class=&quot;fixed inset-0 z-[99999] p-6 flex items-center h-full max-w-5xl mx-auto&quot;&gt;&lt;img alt=&quot;Test input generation: an agent proposes cases while account, group, check and result data flows from the data lake into ClickHouse&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;900&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;w-full max-h-full overflow-hidden border border-gray-300 border-solid rounded-lg border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/hLxTnObQCOmJHb5N_02-test-input-generation.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/hLxTnObQCOmJHb5N_02-test-input-generation.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;img alt=&quot;Collapsing 24 hours of production configurations and result outcomes into unique scenarios, each with its occurrence count&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;1040&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;my-2 border border-gray-300 border-solid rounded-lg cursor-pointer border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/Gavvc9zTv-h2d9Ay_03-collapsing-configs.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/Gavvc9zTv-h2d9Ay_03-collapsing-configs.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;div class=&quot;cursor-pointer hidden&quot;&gt;&lt;div class=&quot;fixed inset-0 z-[99999] bg-black bg-opacity-50 transition-opacity&quot; aria-hidden=&quot;true&quot;&gt;&lt;/div&gt;&lt;div class=&quot;fixed inset-0 z-[99999] p-6 flex items-center h-full max-w-5xl mx-auto&quot;&gt;&lt;img alt=&quot;Collapsing 24 hours of production configurations and result outcomes into unique scenarios, each with its occurrence count&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;1040&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;w-full max-h-full overflow-hidden border border-gray-300 border-solid rounded-lg border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/Gavvc9zTv-h2d9Ay_03-collapsing-configs.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/Gavvc9zTv-h2d9Ay_03-collapsing-configs.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;After generating the test cases, we used code coverage reports to estimate how effective the harness was, targeting between 90% and 100%. We also fed those reports back to the agent to review, identify gaps, and propose test cases for anything missed. We expected some gaps to remain, but with all relevant files sufficiently covered and every scoped feature included, we considered the harness ready for a test run.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Code coverage is a great metric to track as you start out with your initial set of test cases, since high code coverage means the core behaviors are covered. However, it does measure direct system actual behavior and is therefore likely to miss edge cases.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We also built a separate suite of tests that caught failure modes when infrastructure failures occur, e.g., PostgreSQL going down, using Toxiproxy. These were focused on how behavior changes and what data is lost when a piece of infrastructure goes down.&lt;/p&gt;&lt;h2 id=&quot;the-agentic-rewrite&quot;&gt;&lt;a href=&quot;#the-agentic-rewrite&quot;&gt;The agentic rewrite&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A prerequisite for this approach was an earlier migration to a monorepo running on &lt;a target=&quot;_blank&quot; href=&quot;https://tilt.dev/&quot; rel=&quot;noreferrer&quot;&gt;Tilt&lt;/a&gt;, which lets us spin up the whole platform end to end in a local development environment.&lt;/p&gt;&lt;p&gt;We dispatched an instance of Claude Code, using &lt;a target=&quot;_blank&quot; href=&quot;https://www.anthropic.com/claude/fable&quot; rel=&quot;noreferrer&quot;&gt;Fable&lt;/a&gt;, and gave it one instruction: &amp;quot;build a Go service that consumes data from input queues, processes the messages, and writes the outputs to downstream applications such as databases, caches, and other queues,&amp;quot; with the legacy implementation available as a reference. The main acceptance criterion was that the test harness passed against the new implementation.&lt;/p&gt;&lt;p&gt;The agent ran overnight and produced a deployable service of about 13,000 lines of application code, architecturally mirroring the legacy implementation. &lt;strong&gt;It also kept token usage within the daily limits of a $200 subscription.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;We ran an earlier attempt with the same instructions using &lt;a target=&quot;_blank&quot; href=&quot;https://www.anthropic.com/claude/opus&quot; rel=&quot;noreferrer&quot;&gt;Opus&lt;/a&gt;. That implementation did not meet our bar and was discarded.&lt;/p&gt;&lt;section&gt;&lt;img alt=&quot;The agent loop: generate code, run the test harness, review failures, repeat until the harness passes&quot; loading=&quot;lazy&quot; width=&quot;2280&quot; height=&quot;1308&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;my-2 border border-gray-300 border-solid rounded-lg cursor-pointer border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/cIGBL4jjZ3DPd8kJ_04-agent-rewrite-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/cIGBL4jjZ3DPd8kJ_04-agent-rewrite-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;div class=&quot;cursor-pointer hidden&quot;&gt;&lt;div class=&quot;fixed inset-0 z-[99999] bg-black bg-opacity-50 transition-opacity&quot; aria-hidden=&quot;true&quot;&gt;&lt;/div&gt;&lt;div class=&quot;fixed inset-0 z-[99999] p-6 flex items-center h-full max-w-5xl mx-auto&quot;&gt;&lt;img alt=&quot;The agent loop: generate code, run the test harness, review failures, repeat until the harness passes&quot; loading=&quot;lazy&quot; width=&quot;2280&quot; height=&quot;1308&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;w-full max-h-full overflow-hidden border border-gray-300 border-solid rounded-lg border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/cIGBL4jjZ3DPd8kJ_04-agent-rewrite-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/cIGBL4jjZ3DPd8kJ_04-agent-rewrite-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;After reviewing the implementation, we deployed the application to every environment except production, using an internal account to push results so we could get feedback quickly. The review also surfaced anti-patterns we wanted gone and improvements we wanted in:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Removing configuration generated at runtime. The legacy application derived its configuration from partial values provided via environment variables. That has been a pain point in the past when debugging and making configuration changes, especially under pressure during incidents.&lt;/li&gt;&lt;li&gt;Improving end-to-end observability. The legacy service had high-level observability, but given the increase in throughput, there was clear room to do better.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We implemented both with human supervision, which gave us two more principles:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Human intervention is sometimes required, especially to find and fix anti-patterns an agent inherited from the legacy application or introduced itself. For us this meant removing all configuration derivations and making static environment variables the only way the application is configured, plus improving observability. That improved the system&amp;#x27;s operability and simplified the code in both the rewrite and the harness.&lt;/li&gt;&lt;li&gt;Take the rewrite as an opportunity to improve things. In our case that meant expanding end-to-end observability. At this message volume, recording low-level metrics such as database connection utilization, CPU, memory, and timings of individual code execution steps was a necessary addition for long-term operational excellence.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;With those in place, the next step was production.&lt;/p&gt;&lt;h2 id=&quot;first-deployment-what-we-got-wrong&quot;&gt;&lt;a href=&quot;#first-deployment-what-we-got-wrong&quot;&gt;First deployment: what we got wrong&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Before deploying, we had to decide how to migrate customers. The simplest approach was to spin up separate infrastructure (queues) and patch the consumers to push data to the new queue for accounts with a specific feature flag enabled.&lt;/p&gt;&lt;section&gt;&lt;img alt=&quot;The GO_DAEMON feature flag routing account traffic to either the legacy Node.js daemon or the new Go daemon&quot; loading=&quot;lazy&quot; width=&quot;2280&quot; height=&quot;1296&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;my-2 border border-gray-300 border-solid rounded-lg cursor-pointer border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/UvlbSbgKf1CNmxfr_05-feature-flag-rollout.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/UvlbSbgKf1CNmxfr_05-feature-flag-rollout.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;div class=&quot;cursor-pointer hidden&quot;&gt;&lt;div class=&quot;fixed inset-0 z-[99999] bg-black bg-opacity-50 transition-opacity&quot; aria-hidden=&quot;true&quot;&gt;&lt;/div&gt;&lt;div class=&quot;fixed inset-0 z-[99999] p-6 flex items-center h-full max-w-5xl mx-auto&quot;&gt;&lt;img alt=&quot;The GO_DAEMON feature flag routing account traffic to either the legacy Node.js daemon or the new Go daemon&quot; loading=&quot;lazy&quot; width=&quot;2280&quot; height=&quot;1296&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;w-full max-h-full overflow-hidden border border-gray-300 border-solid rounded-lg border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/UvlbSbgKf1CNmxfr_05-feature-flag-rollout.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/UvlbSbgKf1CNmxfr_05-feature-flag-rollout.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;Once the infrastructure was ready, we deployed the Go application across all environments and migrated internal accounts. We ran into issues almost immediately, mainly retries failing.&lt;/p&gt;&lt;p&gt;The root cause was a critical gap in the harness: our local environment&amp;#x27;s surrounding infrastructure did not match production. The harness modeled a simplified local queue topology instead of the real one. Locally, retries were routed to 3 queues based on check type alone. In production, routing also depends on factors like priority and hosting type, for a total of 18 possible queues per region. Because the harness assumed the local topology, the agent built its retry logic around it, and the gap made its way into the new application.&lt;/p&gt;&lt;p&gt;We made that mistake during design. The initial boundary classification was too high-level and assumed production behavior that proved wrong.&lt;/p&gt;&lt;p&gt;We updated the harness to align with production, removed all code branches that only ran in the local environment, and followed up with a human-supervised refactor of the retry module. A day later, the daemon was processing results for our internal accounts, around 3% of total platform load.&lt;/p&gt;&lt;p&gt;The retry-queue gap left us with three principles for the harness going forward:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The harness environment must align with production as closely as possible.&lt;/li&gt;&lt;li&gt;Every boundary must be established down to its lowest unit. Every single queue, every DB table, accounted for.&lt;/li&gt;&lt;li&gt;Every assumption about the surrounding infrastructure must be written down and verified, not inferred.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;rolling-out-to-customers&quot;&gt;&lt;a href=&quot;#rolling-out-to-customers&quot;&gt;Rolling out to customers&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The migration strategy was deliberately boring. Before migrating any customer, the new daemon had already been through the harness and a full rollout across our own internal accounts on real production traffic. On top of that, we migrated customer accounts in stages to reduce blast radius, so each cohort benefited from what we learned on the previous one:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Free accounts, on a trial period or hobbyists.&lt;/li&gt;&lt;li&gt;Paid accounts, on a monthly subscription.&lt;/li&gt;&lt;li&gt;Enterprise accounts, with signed enterprise deals.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Migrating a cohort meant flipping a feature flag, which instantly switched their traffic from the legacy daemon to the new one. After each flip, we monitored for 24 to 48 hours to confirm no results were dropped, failure rates across the platform stayed consistent, and no support escalations pointed back to the daemon before moving on.&lt;/p&gt;&lt;p&gt;During this period, both daemons were processing real traffic, which meant both had to stay in sync. A change in one needed to land in the other. To enforce that without slowing anyone down, we updated CI to run the harness against both the legacy application and the new daemon, blocking any pull request that failed for either.&lt;/p&gt;&lt;p&gt;When customers found or flagged bugs, we used a simple TDD loop to fix them: reproduce the gap in the harness first, then fix the underlying issue. That let us close an issue in about an hour, including CI and deployment time.&lt;/p&gt;&lt;p&gt;The issues we hit were minor, and nearly all of them were edge cases the harness hadn&amp;#x27;t covered. Beyond those, none of our customers noticed they had been migrated.&lt;/p&gt;&lt;section&gt;&lt;img alt=&quot;Fixing a bug by reproducing it in the harness first, then validating the fix against both the legacy daemon and the Go rewrite&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;1480&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;my-2 border border-gray-300 border-solid rounded-lg cursor-pointer border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/sZFPdb7ZQiPkGJJN_06-bug-fix-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/sZFPdb7ZQiPkGJJN_06-bug-fix-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;div class=&quot;cursor-pointer hidden&quot;&gt;&lt;div class=&quot;fixed inset-0 z-[99999] bg-black bg-opacity-50 transition-opacity&quot; aria-hidden=&quot;true&quot;&gt;&lt;/div&gt;&lt;div class=&quot;fixed inset-0 z-[99999] p-6 flex items-center h-full max-w-5xl mx-auto&quot;&gt;&lt;img alt=&quot;Fixing a bug by reproducing it in the harness first, then validating the fix against both the legacy daemon and the Go rewrite&quot; loading=&quot;lazy&quot; width=&quot;2720&quot; height=&quot;1480&quot; decoding=&quot;async&quot; data-nimg=&quot;1&quot; class=&quot;w-full max-h-full overflow-hidden border border-gray-300 border-solid rounded-lg border-opacity-20&quot; style=&quot;color:transparent&quot; srcSet=&quot;https://images.prismic.io/checklyhq/sZFPdb7ZQiPkGJJN_06-bug-fix-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840 1x&quot; src=&quot;https://images.prismic.io/checklyhq/sZFPdb7ZQiPkGJJN_06-bug-fix-loop.png?auto=format%2Ccompress&amp;amp;fit=max&amp;amp;w=3840&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;After a week of migrating customers, monitoring dashboards, and fixing small bugs, the migration was complete, and we decommissioned the legacy workload.&lt;/p&gt;&lt;h2 id=&quot;results&quot;&gt;&lt;a href=&quot;#results&quot;&gt;Results&lt;/a&gt;&lt;/h2&gt;&lt;h3 id=&quot;better-database-performance&quot;&gt;&lt;a href=&quot;#better-database-performance&quot;&gt;Better database performance&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The tooling we chose to talk to the database, &lt;a target=&quot;_blank&quot; href=&quot;https://sqlc.dev/&quot; rel=&quot;noreferrer&quot;&gt;sqlc&lt;/a&gt;, produced more performant queries.&lt;/li&gt;&lt;li&gt;Row locking dropped because Go&amp;#x27;s concurrency model executes operations inside transactions faster.&lt;/li&gt;&lt;li&gt;Together, that gave us &lt;strong&gt;60% fewer total average active sessions (AAS) on our database and a roughly 15% reduction in database CPU&lt;/strong&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;improved-efficiency-and-operability&quot;&gt;&lt;a href=&quot;#improved-efficiency-and-operability&quot;&gt;Improved efficiency and operability&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The new daemon freed up around 15 vCPU and 45GB of memory, as the new application needed far fewer pods to support the workload.&lt;/li&gt;&lt;li&gt;The additional observability built into the new application helps with triaging during any alerts or incidents and enables us to make informed decisions when refactoring the code.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;improved-developer-experience&quot;&gt;&lt;a href=&quot;#improved-developer-experience&quot;&gt;Improved developer experience&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Go&amp;#x27;s type system works much better with agents and adds another layer of protection against regressions.&lt;/li&gt;&lt;li&gt;The test harness guarantees consistent behavior before any rollout. That confidence shows up as faster feature and bug-fix shipping, more frequent deployments, and fewer alerts for our on-call engineers.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;With a harness that validates behavior at this level of rigor, &lt;strong&gt;we can now ship agent-written code faster than before&lt;/strong&gt;, trusting the harness to catch regressions instead of relying on manual review alone.&lt;/p&gt;&lt;h2 id=&quot;summary&quot;&gt;&lt;a href=&quot;#summary&quot;&gt;Summary&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Rewriting legacy applications is never easy, even with agents doing the heavy lifting. We got there by designing and building a strict test harness first, then letting the agent work inside it. Rigorous testing, strict boundary definition, and knowing when to step in as a human are what made this work, and those principles will hold up as the tooling keeps changing.&lt;/p&gt;&lt;p&gt;If you want to see the testing philosophy behind this in a product rather than a blog post, it is the same one behind Checkly: &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/product/monitoring-as-code/&quot; rel=&quot;noreferrer&quot;&gt;Monitoring as Code&lt;/a&gt;, real Playwright scripts running against production, and results you can trust enough to act on. &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/&quot; rel=&quot;noreferrer&quot;&gt;Start monitoring for free&lt;/a&gt;, or read the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/&quot; rel=&quot;noreferrer&quot;&gt;docs&lt;/a&gt; to see how it fits your stack.&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Metabase Security Incident]]></title><description><![CDATA[On 3 August 2026, an attacker exploited a zero-day vulnerability in Metabase, the third-party analytics tool we use internally, and gained read access to a database holding a copy of Checkly operational data. The attacker bypassed authentication and obtained an administrator session on our Metabase Cloud instance. Metabase has since blocked the attack, patched the vulnerability, and published a security update. The attacker did not access our production platform. If you put authentication values directly in your check configurations, or you use OTEL API keys for trace collection, or you want to be extra safe about potential data being accessed in an encrypted state, please rotate your credentials now.  The rest of this post explains what was exposed, what was not, and what we are doing about it. We are sorry this happened. The vulnerability was in a vendor's product, but protecting your data is our job, and this incident put some of it at risk. What happened Metabase is a business intelligence tool we use to analyze product usage and operational metrics. It connects to a data warehouse that holds a copy of Checkly operational data, separate from our production platform. The zero-day allowed the attacker to create an administrator session without valid credentials. No password was stolen, and no Checkly system was directly breached. With that session, the attacker queried the connected data warehouse through Metabase for about 26 minutes on August 3rd, 2026. All activity was read-only. Metabase discovered the attack against Metabase Cloud the same day, blocked the endpoints the attacker used, and patched the vulnerability. They notified customers, law enforcement, and engaged a third-party forensics firm on August 6th. On August 10th, we concluded our investigation of the attacker's activity in our instance using detailed logs Metabase provided to complete our own analysis of the affected systems. What may have been exposed The data warehouse contained check configur...]]></description><link>https://www.checklyhq.com/blog/metabase-security-incident</link><guid isPermaLink="false">ann5KREAACwAdGiQ</guid><category><![CDATA[Security]]></category><dc:creator><![CDATA[]]></dc:creator><pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;On 3 August 2026, an attacker exploited a zero-day vulnerability in &lt;a target=&quot;_blank&quot; href=&quot;https://www.metabase.com/&quot; rel=&quot;noreferrer&quot;&gt;Metabase&lt;/a&gt;, the third-party analytics tool we use internally, and gained read access to a database holding a copy of Checkly operational data. The attacker bypassed authentication and obtained an administrator session on our Metabase Cloud instance. Metabase has since blocked the attack, patched the vulnerability, and published a&lt;a target=&quot;_blank&quot; href=&quot;https://www.metabase.com/blog/security-update&quot; rel=&quot;noreferrer&quot;&gt; security update&lt;/a&gt;. The attacker did not access our production platform.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;If you put authentication values directly in your check configurations, or you use OTEL API keys for trace collection, or you want to be extra safe about potential data being accessed in an encrypted state, please rotate your credentials now.&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;The rest of this post explains what was exposed, what was not, and what we are doing about it.&lt;/p&gt;&lt;p&gt;We are sorry this happened. The vulnerability was in a vendor&amp;#x27;s product, but protecting your data is our job, and this incident put some of it at risk.&lt;/p&gt;&lt;h2 id=&quot;what-happened&quot;&gt;&lt;a href=&quot;#what-happened&quot;&gt;What happened&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Metabase is a business intelligence tool we use to analyze product usage and operational metrics. It connects to a data warehouse that holds a copy of Checkly operational data, separate from our production platform.&lt;/p&gt;&lt;p&gt;The zero-day allowed the attacker to create an administrator session without valid credentials. No password was stolen, and no Checkly system was directly breached. With that session, the attacker queried the connected data warehouse through Metabase for about 26 minutes on August 3rd, 2026. All activity was read-only.&lt;/p&gt;&lt;p&gt;Metabase discovered the attack against Metabase Cloud the same day, blocked the endpoints the attacker used, and patched the vulnerability. They notified customers, law enforcement, and engaged a third-party forensics firm on August 6th. On August 10th, we concluded our investigation of the attacker&amp;#x27;s activity in our instance using detailed logs Metabase provided to complete our own analysis of the affected systems.&lt;/p&gt;&lt;h2 id=&quot;what-may-have-been-exposed&quot;&gt;&lt;a href=&quot;#what-may-have-been-exposed&quot;&gt;What may have been exposed&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The data warehouse contained check configuration and account data, potentially including authorization keys or headers if your checks send them. Specifically:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Credentials you store as Checkly secrets are encrypted at rest and injected only at run time. &lt;strong&gt;These were not exposed in plaintext&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;Checkly stores custom values added directly in a check&amp;#x27;s configuration (custom headers, cookies, query string parameters, or authorization headers) in plaintext. You should consider these values exposed.&lt;/li&gt;&lt;li&gt;Cryptographic hashes of OTEL API keys used for trace collection were also accessed.&lt;/li&gt;&lt;li&gt;Encrypted tokens used in integrations with Vercel, Coralogix, Slack, and Prometheus.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;what-was-not-affected&quot;&gt;&lt;a href=&quot;#what-was-not-affected&quot;&gt;What was not affected&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Access was read-only and lasted about 26 minutes on 3 August. The attacker did not modify, disable, or create any checks, alerts, or settings.&lt;/li&gt;&lt;li&gt;The attacker made no changes to your account, users, or API keys, and created no new ones.&lt;/li&gt;&lt;li&gt;The attacker did not access our production platform; neither the production database nor the Checkly platform, including check execution infrastructure and alerting, were ever breached.&lt;/li&gt;&lt;li&gt;We reviewed our cloud audit logs and found no evidence of anyone reaching the data warehouse from outside our known analytics tooling.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;what-you-need-to-do-now&quot;&gt;&lt;a href=&quot;#what-you-need-to-do-now&quot;&gt;What you need to do now&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;Rotate any credentials and secrets added directly to a check configuration (custom headers, cookies, query string parameters, or authorization headers).&lt;/li&gt;&lt;li&gt;Rotate all OTEL API keys in use.&lt;/li&gt;&lt;li&gt;Review the systems those credentials protect for unauthorized use since 3 August 2026.&lt;/li&gt;&lt;li&gt;Reauthorize Vercel, Prometheus, Slack, and/or Coralogix integrations&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;If your checks only use Checkly secrets for authentication, you do not need to rotate them. For future security, we recommend storing secrets and sensitive data with &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/platform/secrets/&quot; rel=&quot;noreferrer&quot;&gt;Checkly Secrets&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;what-we-did&quot;&gt;&lt;a href=&quot;#what-we-did&quot;&gt;What we did&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;We rotated the credentials Metabase uses to reach the data warehouse.&lt;/li&gt;&lt;li&gt;We reset all Metabase user passwords, removed the compromised administrator account, and rotated all Metabase API keys.&lt;/li&gt;&lt;li&gt;We audited the admin accounts on the instance and confirmed the attacker created none.&lt;/li&gt;&lt;li&gt;We verified through cloud audit logs that only our known analytics tooling used the warehouse credentials.&lt;/li&gt;&lt;li&gt;We are contacting affected customers directly.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;what-we-are-changing&quot;&gt;&lt;a href=&quot;#what-we-are-changing&quot;&gt;What we are changing&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Rotating credentials fixes the immediate problem. It does not fix the reason this hurt: our analytics environment held more sensitive data and had broader access than it needed. So we are making these changes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Extensive audit of analytics and processing tools to limit the exposure surface of any potentially sensitive data.&lt;/li&gt;&lt;li&gt;Improve our sanitization process when storing check configurations and data for analytic processing by scoping down data access so only required information is accessed.&lt;/li&gt;&lt;li&gt;Vendor security notices will page our on-call engineers directly.&lt;/li&gt;&lt;li&gt;Future product features around proactively communicating to customers when potentially sensitive data is exposed in their check configurations.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We will update this post if Metabase&amp;#x27;s ongoing forensic investigation or our own review turns up anything that changes the guidance above.&lt;/p&gt;&lt;p&gt;If you have questions or see suspicious activity on systems your checks touch, contact us at support@checklyhq.com. &lt;/p&gt;&lt;p&gt;Hannes Lenke CEO, Checkly&lt;/p&gt;&lt;h2 id=&quot;frequently-asked-questions&quot;&gt;&lt;a href=&quot;#frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/a&gt;&lt;/h2&gt;&lt;h3 id=&quot;am-i-affected-&quot;&gt;&lt;a href=&quot;#am-i-affected-&quot;&gt;&lt;strong&gt;Am I affected?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Sensitive data from your account was potentially exposed if:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;You hard-coded sensitive information in check configurations, like API check custom request headers, query string parameters, authorization headers / cookies, and in Browser check and Multistep check scripts.&lt;/li&gt;&lt;li&gt;You set up an OpenTelemetry integration with Checkly. Cryptographic hashes of OTEL API keys used for trace collection were accessed.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You should:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Rotate any credentials and secrets added directly to a check configuration (custom headers, cookies, query string parameters, or authorization headers).&lt;/li&gt;&lt;li&gt;Rotate all OTEL API keys in use.&lt;/li&gt;&lt;li&gt;Review the systems those credentials protect for unauthorized use since 3 August 2026.&lt;/li&gt;&lt;li&gt;Reauthorize integrations (including Vercel, Prometheus, Coralogix, etc)&lt;/li&gt;&lt;/ol&gt;&lt;h3 id=&quot;were-environment-variables-and-secrets-exposed-&quot;&gt;&lt;a href=&quot;#were-environment-variables-and-secrets-exposed-&quot;&gt;&lt;strong&gt;Were environment variables and secrets exposed?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Per-check&lt;/strong&gt;: created and saved in the check configuration&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Plain environment variables:&lt;/strong&gt; name, metadata, and values were exposed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Locked environment variables:&lt;/strong&gt; name, metadata, and encrypted values were exposed. Values were not exposed in plain text.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Environment secrets:&lt;/strong&gt; name, metadata, and encrypted values were exposed. Values were not exposed in plain text.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Per-group&lt;/strong&gt;: created and saved in the group configuration&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We do not have any evidence that the attacker queried for the group configuration data. However, these were accessible via Metabase, which the attacker had access to, so we recommend rotating those credentials to be on the safe side.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Plain environment variables:&lt;/strong&gt; name, metadata, and values were potentially exposed&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Locked environment variables:&lt;/strong&gt; name, metadata, and encrypted values were potentially exposed. Value was not exposed in plain text.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Environment secrets:&lt;/strong&gt; name, metadata, and encrypted values were potentially exposed. Values were not exposed in plain text.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Global account environment variables&lt;/strong&gt;: created for your entire account on the &lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/accounts/environment-variables&quot; rel=&quot;noreferrer&quot;&gt;‘Global environment variables and secrets’ page&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Plain environment variables:&lt;/strong&gt; Name and metadata exposed. Values were not exposed, as they were not accessible via Metabase.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Locked environment variables:&lt;/strong&gt; Name and metadata exposed. Values were not exposed, as they were not accessible via Metabase.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Environment secrets:&lt;/strong&gt; Name and metadata exposed. Values were not exposed, as they were not accessible via Metabase.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;For all encrypted values that were potentially exposed, we recommend rotating those credentials to be on the safe side&lt;/strong&gt; and protect against decrypting them in the future, once more sophisticated mechanisms like quantum computing are available.&lt;/p&gt;&lt;h3 id=&quot;were-service-api-keys-user-api-keys-or-private-location-api-keys-exposed-&quot;&gt;&lt;a href=&quot;#were-service-api-keys-user-api-keys-or-private-location-api-keys-exposed-&quot;&gt;&lt;strong&gt;Were service API keys, user API keys, or private location API keys exposed?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;No. However, we recommend you rotate them to be on the safe side.&lt;/p&gt;&lt;h3 id=&quot;do-i-need-to-change-my-checkly-account-password-&quot;&gt;&lt;a href=&quot;#do-i-need-to-change-my-checkly-account-password-&quot;&gt;&lt;strong&gt;Do I need to change my Checkly account password?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;No, these are stored on a completely separate system and were not exposed.&lt;/p&gt;&lt;h3 id=&quot;were-alert-channels-exposed-&quot;&gt;&lt;a href=&quot;#were-alert-channels-exposed-&quot;&gt;&lt;strong&gt;Were alert channels exposed?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;No. Webhook URLs, Slack tokens, PagerDuty keys, and alert email addresses were not exposed. We recommend rotating those credentials to be on the safe side.&lt;/p&gt;&lt;h3 id=&quot;were-playwright-and-other-scripts-exposed-&quot;&gt;&lt;a href=&quot;#were-playwright-and-other-scripts-exposed-&quot;&gt;&lt;strong&gt;Were Playwright and other scripts exposed?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;A subset of API check setup and teardown scripts, Browser check scripts, and Multistep check scripts were exposed.&lt;/p&gt;&lt;p&gt;You should rotate any hard-coded sensitive information in those scripts.&lt;/p&gt;&lt;p&gt;Playwright Check Suite scripts were not exposed since they were stored in a separate system and not accessible in Metabase.&lt;/p&gt;&lt;h3 id=&quot;were-check-results-and-related-artefacts-(job-logs-request/response-details-playwright-traces-screenshots-videos-etc-)-exposed-&quot;&gt;&lt;a href=&quot;#were-check-results-and-related-artefacts-(job-logs-request/response-details-playwright-traces-screenshots-videos-etc-)-exposed-&quot;&gt;&lt;strong&gt;Were check results and related artefacts (job logs, request/response details, Playwright traces, screenshots, videos, etc.) exposed?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Plain request details were exposed. Other result details and artefacts were not exposed.&lt;/p&gt;&lt;h3 id=&quot;do-i-need-to-rotate-api-check-‘basic-authentication-information-&quot;&gt;&lt;a href=&quot;#do-i-need-to-rotate-api-check-‘basic-authentication-information-&quot;&gt;&lt;strong&gt;Do I need to rotate API check ‘basic authentication’ information?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;If you added basic authentication credentials to your API check using our dedicated ‘Basic Authentication’ feature, the usernames are stored as plain text but the passwords are encrypted.&lt;/p&gt;&lt;p&gt;We recommend rotating those credentials to be on the safe side and protect against decrypting them in the future, once more sophisticated mechanisms like quantum computing are available.&lt;/p&gt;&lt;h3 id=&quot;how-do-i-rotate-the-prometheus-integration-&quot;&gt;&lt;a href=&quot;#how-do-i-rotate-the-prometheus-integration-&quot;&gt;&lt;strong&gt;How do I rotate the Prometheus integration?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;On the &lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/accounts/settings/account/integrations&quot; rel=&quot;noreferrer&quot;&gt;Integrations page&lt;/a&gt;, remove the integration entirely with the ‘Remove Prometheus integration’ button. Then, create the integration again. This will generate a new bearer token for you to use.&lt;/p&gt;&lt;h3 id=&quot;we-have-an-sso-connection-with-checkly-do-we-need-to-rotate-secrets-or-certificates-associated-with-that-&quot;&gt;&lt;a href=&quot;#we-have-an-sso-connection-with-checkly-do-we-need-to-rotate-secrets-or-certificates-associated-with-that-&quot;&gt;&lt;strong&gt;We have an SSO connection with Checkly. Do we need to rotate secrets or certificates associated with that?&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;No, these are stored on a completely separate system and were not exposed.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[CLIs are more token-efficient than MCP. Or are they?]]></title><description><![CDATA[MCP servers used to be the token-hungry option. Deferred tool loading and resource links changed that. A side-by-side Playwright MCP vs CLI token comparison.]]></description><link>https://www.checklyhq.com/blog/mcp-vs-cli-token-efficiency</link><guid isPermaLink="false">ams4yxEAAC0Ae-4s</guid><category><![CDATA[AI]]></category><category><![CDATA[Playwright]]></category><category><![CDATA[Development]]></category><dc:creator><![CDATA[Stefan Judis]]></dc:creator><pubDate>Thu, 30 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;MCP servers have a reputation: they eat your context window. CLIs paired with skills, on the other hand, are more token efficient. But is this still true? I dropped all my MCP servers five months ago. Five months is a long time in AI land.&lt;/p&gt;&lt;p&gt;When Anthropic came up with &lt;a target=&quot;_blank&quot; href=&quot;https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview&quot; rel=&quot;noreferrer&quot;&gt;the concept of skills&lt;/a&gt;, many people stopped using MCP servers in favor of CLI tooling and skills. CLIs integrate nicely with coding agents and generally skills were supposed to be lighter on tokens because things were pulled in lazily and on demand. CLIs plus skills became the default advice for coding agents, and MCP got labeled as the token-hungry way to do the same thing.&lt;/p&gt;&lt;p&gt;We at Checkly are heavily involved in the Playwright ecosystem. Playwright offers &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/microsoft/playwright-mcp&quot; rel=&quot;noreferrer&quot;&gt;an MCP server&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/microsoft/playwright-cli&quot; rel=&quot;noreferrer&quot;&gt;a CLI&lt;/a&gt;, too. There&amp;#x27;s &lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=Be0ceKN81S8&quot; rel=&quot;noreferrer&quot;&gt;this &amp;quot;famous&amp;quot; YouTube video&lt;/a&gt; from the Playwright team making exactly the case for the CLI, and I bought it, and switched from MCP to the CLI.&lt;/p&gt;&lt;p&gt;The video was released in February 2026 and it aged poorly.&lt;strong&gt; There&amp;#x27;s no big difference in using CLIs or MCPs these days&lt;/strong&gt;.&lt;/p&gt;&lt;h2 id=&quot;why-is-mcp-supposed-to-eat-up-your-context-window-&quot;&gt;&lt;a href=&quot;#why-is-mcp-supposed-to-eat-up-your-context-window-&quot;&gt;Why is MCP supposed to eat up your context window?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There were two real problems if you tried MCP servers in 2025.&lt;/p&gt;&lt;p&gt;The major problem: the moment your agent connected to an MCP server, it pulled every tool definition into context. All of them, upfront, whether the conversation would ever touch them or not. For the Playwright MCP server that meant 48 tool schemas at 5.9k tokens before you typed a single prompt. This was the problem skills were supposed to solve.&lt;/p&gt;&lt;p&gt;And Playwright is a mild case. If you wanted to use GitHub&amp;#x27;s MCP server it wasted 17.8k tokens &amp;quot;for nothing&amp;quot;.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/Pf0DqS-D_DENH3SI_mcp-vs-cli-github-mcp-token-cost.png?auto=format,compress&quot; alt=&quot;Context window cost of the GitHub MCP server tool definitions&quot;/&gt;&lt;/p&gt;&lt;p&gt;If you switched to skills, agents only loaded the skill files&amp;#x27; one-line description (roughly 30-50 tokens) and read the full files if the agent actually needed them. For established tooling like the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;gh&lt;/code&gt; CLI, you often don&amp;#x27;t even need a skill. Modern LLMs know their way around it pretty well with common CLI tools.&lt;/p&gt;&lt;p&gt;The second problem, and this one might be a bit more Playwright specific, was that every single MCP action, every click and every keystroke, came back with the entire page snapshot inlined. The context window was filling up with YAML wall after YAML wall. This is the part that produced the scary comparison numbers floating around.&lt;/p&gt;&lt;p&gt;So yes, back in 2025 the criticism was fair and it seemed like a no-brainer to use CLIs.&lt;/p&gt;&lt;h2 id=&quot;what-changed-since-then&quot;&gt;&lt;a href=&quot;#what-changed-since-then&quot;&gt;What changed since then&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Both problems got fixed. On the upfront side, modern agent harnesses defer MCP tool loading and optimize tool calls with some tricks. Claude Code, for example, only keeps the tool names around and pulls a full tool definition in when a tool is actually called. Anthropic digs into the underlying idea of reading tool definitions on demand in &lt;a target=&quot;_blank&quot; href=&quot;https://www.anthropic.com/engineering/code-execution-with-mcp&quot; rel=&quot;noreferrer&quot;&gt;&amp;quot;Code execution with MCP: Building more efficient agents&amp;quot;&lt;/a&gt;. The key fact is that MCP tool definitions get pulled in lazily now, similar to how CLI skills work, and stay out of your context window until the agent actually needs them.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/MTiZO2KU-p5stxbk_mcp-vs-cli-deferred-tool-loading.png?auto=format,compress&quot; alt=&quot;Claude Code keeps only MCP tool names in context and loads definitions on demand&quot;/&gt;&lt;/p&gt;&lt;p&gt;And on the per-action side, &lt;a target=&quot;_blank&quot; href=&quot;https://modelcontextprotocol.io/specification/2025-06-18/changelog&quot; rel=&quot;noreferrer&quot;&gt;an MCP specification change&lt;/a&gt; allowed Playwright to stop inlining snapshots. Previously, the MCP spec was fairly strict about the communication flow. All content had to be included in the tool call results. This is the reason why the MCP always returned the current page snapshot. But &lt;a target=&quot;_blank&quot; href=&quot;https://modelcontextprotocol.io/specification/2025-06-18/server/tools#resource-links&quot; rel=&quot;noreferrer&quot;&gt;with resource links&lt;/a&gt; the MCP server changed its general behavior and now writes snapshots to disk, responding with a resource URL. If the agent decides that it needs the current page snapshot it can go ahead and read it. But it won&amp;#x27;t be included if it isn&amp;#x27;t needed.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/rG_HmsbgfPPFZ_o5_mcp-vs-cli-resource-links-snapshots.png?auto=format,compress&quot; alt=&quot;Playwright MCP writes page snapshots to disk and returns a resource link&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Writing page state to disk and letting the agent grep into it is exactly the pull model the CLI was praised fo&lt;/strong&gt;r. By now, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;playwright-cli&lt;/code&gt; commands literally invoke the MCP tools by name under the hood (&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;click&lt;/code&gt; calls &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;browser_click&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;find&lt;/code&gt; calls &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;browser_find&lt;/code&gt;). The Playwright CLI and MCP use the same backend, same snapshot files on disk.&lt;/p&gt;&lt;h2 id=&quot;there-s-no-difference-anymore-&quot;&gt;&lt;a href=&quot;#there-s-no-difference-anymore-&quot;&gt;There&amp;#x27;s no difference anymore?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;But let&amp;#x27;s look at some numbers. I gave the same task to two fresh Claude Code sessions, one with the Playwright MCP server, one with only the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;playwright-cli&lt;/code&gt; and the installed CLI skill:&lt;/p&gt;&lt;blockquote class=&quot;bg-gray-100 p-4 border-l-2 my-4 border-blue-300 inline-block space-y-4&quot;&gt;&lt;p&gt;Please open my example demo shop and search for &amp;quot;liquid&amp;quot;. Click the first product and add the product to the cart. Validate that the cart is showing the correct amount and close it.&lt;/p&gt;&lt;/blockquote&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/Ilfg9Hz_DTmVFaqu_mcp-vs-cli-token-comparison.png?auto=format,compress&quot; alt=&quot;Token consumption comparison between the Playwright MCP server and the Playwright CLI&quot;/&gt;&lt;/p&gt;&lt;p&gt;The result after running the same task three times was that MCP and skill-based CLI flows have more or less the same token consumption. The MCP session ended at 48k to 50k tokens of context, the CLI session at 45k to 48k. I didn&amp;#x27;t go much deeper but while seeing what both agent flows were doing it became obvious that they&amp;#x27;re both doing the exact same thing. There might be small differences, &lt;strong&gt;but the CLI output and MCP tool results look almost identical&lt;/strong&gt;, so I didn&amp;#x27;t see much value in running the experiment again. I also ran this comparison live in &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/webinars/playwright-built-for-agents/&quot; rel=&quot;noreferrer&quot;&gt;our Playwright webinar&lt;/a&gt;; if you want to watch the measurement happen in real time, the recording is on-demand.&lt;/p&gt;&lt;h2 id=&quot;ai-advice-comes-with-an-expiry-date&quot;&gt;&lt;a href=&quot;#ai-advice-comes-with-an-expiry-date&quot;&gt;AI advice comes with an expiry date&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;It&amp;#x27;s exhausting but every piece of advice in the AI or agent space has a shelf life measured in months. &amp;quot;MCP loads all tools upfront&amp;quot; was true, then harnesses shipped deferred loading. &amp;quot;Playwright MCP inlines a snapshot per action&amp;quot; was true, then snapshots moved to disk. The viral Playwright video that made me switch was accurate when it was recorded and stale within a quarter.&lt;/p&gt;&lt;p&gt;So, &lt;strong&gt;&amp;quot;don&amp;#x27;t use MCP, it&amp;#x27;s too token hungry&amp;quot; is old news&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;If a product provides a CLI and MCP, compare features and functionality first, because they often don&amp;#x27;t match. Take our own tooling at Checkly as an example: &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/cli/&quot; rel=&quot;noreferrer&quot;&gt;the Checkly CLI&lt;/a&gt; is built for the Monitoring as Code flow to create, test and deploy your monitoring from a local project. &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/ai/mcp-server&quot; rel=&quot;noreferrer&quot;&gt;The Checkly MCP server&lt;/a&gt; is for live account operations like inspecting check health, investigating failures and kicking off &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/resolve/ai-root-cause-analysis/overview/&quot; rel=&quot;noreferrer&quot;&gt;Rocky AI root cause analyses&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Only when both sides genuinely match, like Playwright&amp;#x27;s do, does it come down to preference. And yes, I&amp;#x27;ve since brought some of my MCP servers back. I prefer to use MCP in Claude Desktop and CLIs in Claude Code these days. But it&amp;#x27;s really up to you!&lt;/p&gt;&lt;p&gt;The only thing to keep in mind is that if there&amp;#x27;s a &amp;quot;common&amp;quot; best practice about token consumption, check your context window every now and then. What was true a couple of months ago probably isn&amp;#x27;t anymore.&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[How Upstash Monitors Every Redis Replica with Checkly]]></title><description><![CDATA[How Upstash monitors uptime for every Redis replica: Checkly URL monitors in Terraform, checks from 18 global locations, and an end-to-end QStash check.]]></description><link>https://www.checklyhq.com/blog/how-upstash-monitors-every-redis-replica-with-checkly</link><guid isPermaLink="false">ak-6fhIAACcAHlWJ</guid><category><![CDATA[Monitoring as Code (MaC)]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[Uptime Monitoring]]></category><dc:creator><![CDATA[Ilter Kavlak]]></dc:creator><pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;&lt;em&gt;This is a guest post by Ilter Kavlak, Site Reliability Engineer at Upstash. It&amp;#x27;s a companion to &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/blog/how-upstash-monitors-uptime&quot; rel=&quot;noreferrer&quot;&gt;his post on the Upstash blog&lt;/a&gt;, which covers the internal side of the same monitoring stack.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;There&amp;#x27;s a support ticket every SRE dreads: &amp;quot;is something wrong with my database?&amp;quot; The outage is bad enough. Worse is the possibility that the customer knew first.&lt;/p&gt;&lt;p&gt;At Upstash, we treat that scenario as two failures rather than one: the incident itself, and the uptime monitoring gap that let a customer beat us to it. We write a postmortem for the gap, too.&lt;/p&gt;&lt;p&gt;This post is about the layer we built to make sure that never happens: a fleet of Checkly checks that watches our platform from the outside, the way a customer would. One check per replica, running every minute from 18 locations around the world, all of it defined in Terraform. I&amp;#x27;ll walk through what we check, how a failing check reaches a human, and how we monitor a product where &amp;quot;reachable&amp;quot; and &amp;quot;working&amp;quot; are very different claims.&lt;/p&gt;&lt;h2 id=&quot;why-every-replica-gets-its-own-uptime-check&quot;&gt;&lt;a href=&quot;#why-every-replica-gets-its-own-uptime-check&quot;&gt;Why every replica gets its own uptime check&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/redis&quot; rel=&quot;noreferrer&quot;&gt;Upstash Redis&lt;/a&gt; is multitenant and multizone. Every database is backed by at least two replicas, and with the &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/docs/redis/overall/enterprise#multi-zone-high-availability&quot; rel=&quot;noreferrer&quot;&gt;Prod Pack&lt;/a&gt; those replicas live in different availability zones. When a replica dies, the survivors elect the most up-to-date among themselves and the database keeps serving; customers notice nothing.&lt;/p&gt;&lt;p&gt;That resilience is exactly what makes replica-level monitoring easy to skip. If your checks only watch the database endpoint, a dead replica is invisible: the endpoint stays green while you quietly run with less redundancy than you promised your customers. And the &lt;em&gt;next&lt;/em&gt; failure is no longer a non-event.&lt;/p&gt;&lt;p&gt;So our rule is blunt. A dead replica is an incident even when no customer can feel it. Every single replica gets its own uptime check, and losing any one of them wakes the oncall.&lt;/p&gt;&lt;h2 id=&quot;a-couple-hundred-url-monitors-all-in-terraform&quot;&gt;&lt;a href=&quot;#a-couple-hundred-url-monitors-all-in-terraform&quot;&gt;A couple hundred URL monitors, all in Terraform&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Because Upstash Redis &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/docs/redis/features/restapi&quot; rel=&quot;noreferrer&quot;&gt;speaks HTTP alongside the Redis protocol&lt;/a&gt;, health checking stays simple. No Redis client, no connection pooling, no scripted scenario. Each replica exposes a /ping endpoint over HTTPS, and a 200 means that replica is serving its databases the same way it would serve a real client.&lt;/p&gt;&lt;p&gt;We use &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/detect/uptime-monitoring/url-monitors/overview/&quot; rel=&quot;noreferrer&quot;&gt;Checkly URL monitors&lt;/a&gt; for these, defined in &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/iac/terraform/overview/&quot; rel=&quot;noreferrer&quot;&gt;Terraform&lt;/a&gt;. Each replica is one module block:&lt;/p&gt;&lt;div class=&quot;code-block theme-light&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;check-eu-central-1-r2&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  source &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;../modules/checkly_url_monitor&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  name              &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;eu-central-1-r2&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  base_url          &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;https://&amp;lt;replica-endpoint&amp;gt;.upstash.io/ping&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  frequency_minutes &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  locations         &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.default_locations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  alert_channel_ids &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.default_alert_channel_ids&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This is &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/concepts/monitoring-as-code/&quot; rel=&quot;noreferrer&quot;&gt;Monitoring as Code&lt;/a&gt;, and it&amp;#x27;s the feature that made us commit to Checkly. Our monitoring configuration lives in the same repository as the rest of our infrastructure, and a single apply deploys or updates the whole fleet. By now, the file reads like a census: one block per replica, a couple of hundred in total, spanning AWS and GCP regions from Tokyo to São Paulo. When a new replica joins a cluster, a new block gets written, reviewed, and applied like any other infrastructure change. No monitor is ever created by clicking around a dashboard; &lt;strong&gt;if it isn&amp;#x27;t in git, it doesn&amp;#x27;t exist in Checkly.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;That discipline would be optional at two checks. At two hundred, it&amp;#x27;s the only way to be sure nobody forgot one.&lt;/p&gt;&lt;p&gt;Redis isn&amp;#x27;t the only product in that file. &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/vector&quot; rel=&quot;noreferrer&quot;&gt;Upstash Vector&lt;/a&gt; and &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/docs/search/overall/getstarted&quot; rel=&quot;noreferrer&quot;&gt;Search&lt;/a&gt; replicas get the same per-replica treatment, except their checks go beyond a ping: each one upserts a record and runs a query against it, because an index that accepts connections but can&amp;#x27;t answer queries is not &amp;quot;up&amp;quot; in any sense a customer cares about. Keep that idea in mind for the QStash section below.&lt;/p&gt;&lt;h2 id=&quot;from-18-locations-every-minute&quot;&gt;&lt;a href=&quot;#from-18-locations-every-minute&quot;&gt;From 18 locations, every minute&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The hardest-working parameter in that module block is locations. Upstash serves clients globally, with &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/docs/redis/features/globaldatabase&quot; rel=&quot;noreferrer&quot;&gt;replicas placed close to their readers&lt;/a&gt;, so a replica answering from one vantage point proves very little. Every monitor runs from all 18 of the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/concepts/locations/&quot; rel=&quot;noreferrer&quot;&gt;Checkly locations&lt;/a&gt; we&amp;#x27;ve configured, covering North and South America, Europe, Africa, and Asia-Pacific. A routing problem that only affects clients in Singapore is a full outage for a client in Singapore, so our monitoring treats it as one.&lt;/p&gt;&lt;p&gt;Each monitor runs every minute, and a failed request is &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/communicate/alerts/retries/&quot; rel=&quot;noreferrer&quot;&gt;retried after a short backoff&lt;/a&gt; before anything alerts, since a single dropped packet somewhere on the public internet is no reason to wake a human. And we refuse to conflate &lt;em&gt;slow&lt;/em&gt; with &lt;em&gt;down&lt;/em&gt;: a response over five seconds marks the monitor degraded, and past ten it counts as failed. Two different signals, routed two different ways.&lt;/p&gt;&lt;h2 id=&quot;how-a-failing-check-reaches-a-human&quot;&gt;&lt;a href=&quot;#how-a-failing-check-reaches-a-human&quot;&gt;How a failing check reaches a human&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Every monitor is wired to the same set of alert channels, also defined in Terraform:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/incident-management/opsgenie/&quot; rel=&quot;noreferrer&quot;&gt;&lt;strong&gt;Opsgenie&lt;/strong&gt;&lt;/a&gt; pages the oncall on failure. This is the loud one.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Slack&lt;/strong&gt; receives both failures and recoveries, giving the rest of the team context without waking anyone.&lt;/li&gt;&lt;li&gt;Degraded-state notifications land in a &lt;strong&gt;Slack channel of their own&lt;/strong&gt;. Slowness deserves eyes but not a 3 a.m. page, and it shouldn&amp;#x27;t drown in a busy alerts channel either.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When a replica check fails, the oncall is looking at it within a couple of minutes, whatever the hour. None of that is remarkable. The habit worth writing down is how incidents &lt;em&gt;end&lt;/em&gt;: we don&amp;#x27;t call anything resolved because internal dashboards look healthy. &lt;strong&gt;Resolved means the Checkly check is green again&lt;/strong&gt;, from all 18 locations. Internal metrics can tell you a process is running; only the external check can tell you a client on the other side of the planet is actually being served. The second claim is the one customers experience, so it&amp;#x27;s the one that closes the incident.&lt;/p&gt;&lt;h2 id=&quot;qstash-proving-messages-actually-get-delivered&quot;&gt;&lt;a href=&quot;#qstash-proving-messages-actually-get-delivered&quot;&gt;QStash: proving messages actually get delivered&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;For &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/qstash&quot; rel=&quot;noreferrer&quot;&gt;QStash&lt;/a&gt;, our message queue and task scheduler, a health endpoint would prove almost nothing. QStash exists to &lt;em&gt;deliver messages&lt;/em&gt;; it could happily return a 200 for every publish, deliver none of them, and a ping check would stay green the whole time.&lt;/p&gt;&lt;p&gt;So instead of a ping, QStash gets a &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/detect/synthetic-monitoring/api-checks/overview/&quot; rel=&quot;noreferrer&quot;&gt;Checkly API check&lt;/a&gt; that uses the product the way a customer would. The check publishes a real message through the &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/docs/qstash/api-reference/messages/publish-a-message&quot; rel=&quot;noreferrer&quot;&gt;QStash publish API&lt;/a&gt; and points it at an Opsgenie heartbeat endpoint, so every successful delivery resets the heartbeat&amp;#x27;s timer.&lt;/p&gt;&lt;p&gt;One message tests the whole pipeline, and the two ways it can fail are distinguishable:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;The publish fails.&lt;/strong&gt; QStash is unreachable or rejecting requests. The Checkly check turns red and pages the oncall.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The publish succeeds but nothing arrives.&lt;/strong&gt; QStash accepted the request and then failed to deliver it. The heartbeat falls silent, Opsgenie notices the silence, and the page goes out.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Either way a human is investigating within minutes, and the alert already names &lt;em&gt;which half of the flow&lt;/em&gt; broke before anyone opens a dashboard. That&amp;#x27;s a serious head start.&lt;/p&gt;&lt;p&gt;My favorite property of this check is that it&amp;#x27;s indistinguishable from a customer. Same publish API, same delivery path, same retries as real traffic. There is no separate test mode that could pass while production fails.&lt;/p&gt;&lt;h2 id=&quot;what-checkly-doesn-t-cover-on-purpose&quot;&gt;&lt;a href=&quot;#what-checkly-doesn-t-cover-on-purpose&quot;&gt;What Checkly doesn&amp;#x27;t cover, on purpose&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;External checks answer one question: would a customer be served right now, from where they are? Two other layers answer the questions they can&amp;#x27;t.&lt;/p&gt;&lt;p&gt;Internally, a federated Prometheus stack watches the clusters themselves and catches pod-level trouble. And in every region, a fleet of benchmark clients (deployed deliberately outside the clusters they measure) pushes a steady mix of reads and writes around the clock, recording every latency it observes. That fleet is our second, independent paging path, and its historical dashboards are where slow-moving problems like release regressions and noisy neighbors show up as trend lines long before they&amp;#x27;d trip any single alert. Both layers are managed the same way as the Checkly monitors: Terraform modules in the same repository, one workflow for everything. I&amp;#x27;ve written about that side of the stack in detail &lt;a target=&quot;_blank&quot; href=&quot;https://upstash.com/blog/how-upstash-monitors-uptime&quot; rel=&quot;noreferrer&quot;&gt;on the Upstash blog&lt;/a&gt;.&lt;/p&gt;&lt;section class=&quot;theme-light py-10 md:py-12&quot; data-slice-type=&quot;dynamic_data_table&quot; data-slice-variation=&quot;default&quot;&gt;&lt;div class=&quot;overflow-x-auto pb-2 [scrollbar-color:theme(colors.checkly.blue)_theme(colors.gray.100)] [scrollbar-width:thin] [&amp;amp;::-webkit-scrollbar-thumb]:rounded-full [&amp;amp;::-webkit-scrollbar-thumb]:bg-checkly-blue [&amp;amp;::-webkit-scrollbar-track]:rounded-full [&amp;amp;::-webkit-scrollbar-track]:bg-gray-100 [&amp;amp;::-webkit-scrollbar]:h-2&quot;&gt;&lt;table class=&quot;w-full text-left text-sm max-md:text-xs [&amp;amp;_td]:whitespace-nowrap [&amp;amp;_tr:first-child]:font-semibold [&amp;amp;_tr:first-child]:text-checkly-deep-blue&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Layer&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Question it answers&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Who gets woken&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Checkly per-replica checks (Redis, Vector, Search)&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Is each replica serving traffic, from every region, right now?&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Oncall&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Internal cluster monitoring&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Is the software healthy on the inside?&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Oncall&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Continuous latency benchmarks&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Is each replica as fast as it should be?&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Oncall on failure, internal alerts on drift&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;QStash end-to-end check&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Does the product do its real job, end to end?&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Oncall, with the broken half already identified&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;Every layer exists to cover a blind spot in the others. &lt;strong&gt;But when internal and external monitoring disagree, the external answer wins the argument, because it&amp;#x27;s the only one describing what customers actually experience.&lt;/strong&gt;&lt;/p&gt;&lt;h2 id=&quot;the-philosophy-in-five-sentences&quot;&gt;&lt;a href=&quot;#the-philosophy-in-five-sentences&quot;&gt;The philosophy, in five sentences&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Watch every replica, because redundancy you can&amp;#x27;t verify isn&amp;#x27;t redundancy. Watch from wherever your users actually are. Treat ‘slow’ as its own signal rather than a milder form of down. Test the thing the product promises to do, not just whether it answers. And don&amp;#x27;t declare victory until the outside world agrees.&lt;/p&gt;&lt;p&gt;None of this prevents outages; hardware still fails, zones still have bad days, and the internet remains the internet. What it buys is time and clarity: minutes from failure to a human engaged, an alert that names what broke, and a client&amp;#x27;s-eye definition of &amp;quot;fixed.&amp;quot; The ticket asking &amp;quot;is something wrong?&amp;quot; should only ever get one reply: &amp;quot;yes, we know, and we&amp;#x27;re already on it.&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Upstash runs a couple hundred Checkly monitors, every one of them defined in code. If you want the same workflow, start with &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/concepts/monitoring-as-code/&quot; rel=&quot;noreferrer&quot;&gt;Monitoring as Code&lt;/a&gt;: define your monitors in TypeScript with the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/cli/&quot; rel=&quot;noreferrer&quot;&gt;Checkly CLI&lt;/a&gt;, or use the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/iac/terraform/overview/&quot; rel=&quot;noreferrer&quot;&gt;Terraform provider&lt;/a&gt; like Upstash does. &lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/signup/&quot; rel=&quot;noreferrer&quot;&gt;Start monitoring for free&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Autoscaling Checkly Private Location Agents in Kubernetes with KEDA]]></title><description><![CDATA[Monitor your Private Location health with Checkly, and autoscale agents with KEDA on live load. Stop guessing at agent capacity.]]></description><link>https://www.checklyhq.com/blog/autoscaling-checkly-agents-with-keda-in-kubernetes</link><guid isPermaLink="false">ZDkQ7BEAACIAiBc2</guid><category><![CDATA[Product]]></category><category><![CDATA[Prometheus]]></category><dc:creator><![CDATA[Edvinas Janusevicius]]></dc:creator><pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;Monitoring load is not always steady. A team might add a new batch of checks or run several ad hoc tests during a rollout. When that happens, your Private Location agents need to pick up more work at once.&lt;/p&gt;&lt;p&gt;If there aren’t enough agents available during a burst, checks start piling up in the queue, which can delay or disrupt check execution. But solving this by running a high number of agents around the clock has the opposite problem: most of that capacity sits idle until the next busy period.&lt;/p&gt;&lt;p&gt;Autoscaling solves both ends of that problem. You scale agents up when checks queue, scale back down when the burst clears, and stop guessing in between. This guide covers two things that landed together: the new Private Location metrics that show you whether your agents are running efficiently, and the KEDA setup that automatically scales your agent deployment.&lt;/p&gt;&lt;h2 id=&quot;how-do-you-know-if-a-private-location-has-enough-agents-&quot;&gt;&lt;a href=&quot;#how-do-you-know-if-a-private-location-has-enough-agents-&quot;&gt;How do you know if a Private Location has enough agents?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;You can now monitor Private Location health with Checkly, so capacity stops being a guessing game. &lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/accounts/private-locations&quot; rel=&quot;noreferrer&quot;&gt;Open any Private Location in the UI&lt;/a&gt; and you&amp;#x27;ll find three metrics that tell you exactly how your agents are doing:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Queue duration&lt;/strong&gt;: how long check runs wait before an agent picks them up. This is the number to watch. If it creeps up, your agents may be falling behind on work.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Agent count&lt;/strong&gt;: how many agents are currently reporting for the location.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Scheduled check runs&lt;/strong&gt;: how many runs are queued for the location right now.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These metrics are also available via our &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/observability/prometheus-v2/#private-location-metrics&quot; rel=&quot;noreferrer&quot;&gt;Prometheus v2 integration&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/7TFhRN2oaq9W9iPF_DASHBOARD-2-.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;Together, these signals help you understand whether your agents are healthy and whether your Private Location has enough capacity. For example, if two agents are reporting but queue duration keeps climbing and scheduled runs are stacking up, you may be under-provisioned. If ten agents are reporting and queue duration stays near zero all day, you may be running more capacity than you need. Those are the two states autoscaling exists to fix, and now you can see which one you&amp;#x27;re in.&lt;/p&gt;&lt;h2 id=&quot;scaling-on-the-right-signal&quot;&gt;&lt;a href=&quot;#scaling-on-the-right-signal&quot;&gt;Scaling on the right signal&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Checkly agents are stateless: they sit in your network, pull scheduled checks from a shared queue, run them, and send the results back. You can add or remove agents freely without losing or duplicating work. That&amp;#x27;s the property that makes scaling safe.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://prismic-io.s3.amazonaws.com/checklyhq/Y2Y0ZWE2MGUtZmQwOC00NWRkLWEyNjAtODgzOTE2YmYxMjMx_untitled-2022-06-15-1142-1.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;To develop a practical approach to autoscaling, we studied a range of large Private Location setups across customers, including &lt;a target=&quot;_self&quot; href=&quot;https://www.checklyhq.com/case-study/dvag-migrates-to-checkly/&quot; rel=&quot;noreferrer&quot;&gt;DVAG&lt;/a&gt;, &lt;a target=&quot;_self&quot; href=&quot;https://www.checklyhq.com/case-study/modernizing-linkedins-monitoring-infrastructure/&quot; rel=&quot;noreferrer&quot;&gt;LinkedIn&lt;/a&gt;, Sherwin-Williams, and Auto Trader. Looking at how those fleets handle different checks and workloads helped us identify the signal that best reflects a location’s current demand.&lt;/p&gt;&lt;p&gt;For teams running agents on Kubernetes, that signal is &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly_private_location_check_runs&lt;/code&gt;. This gauge reports the number of check runs routed through a Private Location, broken down by state.&lt;/p&gt;&lt;p&gt;Two states matter for capacity:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;queued&lt;/code&gt;: the check run is scheduled, but no agent has picked it up yet.&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;inflight&lt;/code&gt;: an agent is running it right now.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Add those two and you have the total live load on the location, which is the signal you want driving replica count. To use this metric, make sure &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/observability/prometheus-v2/&quot; rel=&quot;noreferrer&quot;&gt;Prometheus V2 metrics&lt;/a&gt; are enabled for your account.&lt;/p&gt;&lt;p&gt;ℹ️ If your existing KEDA config still uses &lt;/p&gt;&lt;p&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly_private_location_oldest_scheduled_check_run&lt;/code&gt;, consider switching to &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly_private_location_check_runs&lt;/code&gt; with the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;queued&lt;/code&gt; and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;inflight&lt;/code&gt; states. The older metric is useful for spotting backlog, but &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;queued&lt;/code&gt; plus &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;inflight&lt;/code&gt; gives KEDA a more direct signal for current load.&lt;/p&gt;&lt;h2 id=&quot;setting-up-keda&quot;&gt;&lt;a href=&quot;#setting-up-keda&quot;&gt;Setting up KEDA&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://keda.sh&quot; rel=&quot;noreferrer&quot;&gt;KEDA&lt;/a&gt; (Kubernetes Event-Driven Autoscaling) reads a Prometheus metric and scales a Kubernetes deployment up or down based on that value. You&amp;#x27;ll need KEDA installed in the cluster, your agents deployed via the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/checkly/helm-charts/tree/main/charts/agent&quot; rel=&quot;noreferrer&quot;&gt;Checkly agent Helm chart&lt;/a&gt;, and &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/observability/prometheus-v2/&quot; rel=&quot;noreferrer&quot;&gt;Prometheus V2&lt;/a&gt; enabled for your Checkly account.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s a &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;ScaledObject&lt;/code&gt; with sensible defaults. Adjust the bounds to your workload:&lt;/p&gt;&lt;div class=&quot;code-block theme-light&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;keda.sh/v1alpha1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;ScaledObject&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;checkly-agent-autoscaler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;scaleTargetRef&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;lt;namespace_for_agent_deployment&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;lt;agent_deployment_name&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;minReplicaCount&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;maxReplicaCount&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;advanced&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;horizontalPodAutoscalerConfig&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;behavior&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;scaleUp&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;policies&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;Pods&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;periodSeconds&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;scaleDown&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;selectPolicy&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;Min&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;policies&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;Pods&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;periodSeconds&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;triggers&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    - &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;prometheus&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;serverAddress&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;http://prometheus-k8s.monitoring.svc.cluster.local:9090&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;metricName&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;checkly_private_location_check_runs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;threshold&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;sum(checkly_private_location_check_runs{state=~&amp;quot;queued|inflight&amp;quot;, private_location_slug_name=&amp;quot;&amp;lt;slug&amp;gt;&amp;quot;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The query targets a single Private Location using &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;private_location_slug_name&lt;/code&gt;. If you run multiple Private Locations, create one &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;ScaledObject&lt;/code&gt; for each. Because the slug name is immutable, renaming the location in the UI won’t affect your scaling config.&lt;/p&gt;&lt;p&gt;If you deploy agents with the Helm chart, template the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;ScaledObject&lt;/code&gt; alongside your chart values. This keeps the autoscaler tied to the agent deployment instead of managing it as a separate manifest.&lt;/p&gt;&lt;p&gt;For a Prometheus instance outside the cluster, add an &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;authenticationRef&lt;/code&gt; that points to a &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;TriggerAuthentication&lt;/code&gt; with the required credentials.&lt;/p&gt;&lt;h2 id=&quot;how-many-pods-will-you-get-&quot;&gt;&lt;a href=&quot;#how-many-pods-will-you-get-&quot;&gt;How many pods will you get?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Set the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;threshold&lt;/code&gt; to match your agent &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;JOB_CONCURRENCY&lt;/code&gt;. This defines how many checks one agent pod can process at the same time. With the default &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;JOB_CONCURRENCY&lt;/code&gt; of &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;1&lt;/code&gt;, use &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;threshold: &amp;quot;1&amp;quot;&lt;/code&gt;. That means KEDA will try to keep roughly one queued or in-flight check run per agent pod, within your min and max replica limits.&lt;/p&gt;&lt;p&gt;For example, with &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;minReplicaCount: 2&lt;/code&gt; and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;maxReplicaCount: 10&lt;/code&gt;:&lt;/p&gt;&lt;section class=&quot;theme-light py-10 md:py-12&quot; data-slice-type=&quot;dynamic_data_table&quot; data-slice-variation=&quot;default&quot;&gt;&lt;div class=&quot;overflow-x-auto pb-2 [scrollbar-color:theme(colors.checkly.blue)_theme(colors.gray.100)] [scrollbar-width:thin] [&amp;amp;::-webkit-scrollbar-thumb]:rounded-full [&amp;amp;::-webkit-scrollbar-thumb]:bg-checkly-blue [&amp;amp;::-webkit-scrollbar-track]:rounded-full [&amp;amp;::-webkit-scrollbar-track]:bg-gray-100 [&amp;amp;::-webkit-scrollbar]:h-2&quot;&gt;&lt;table class=&quot;w-full text-left text-sm max-md:text-xs [&amp;amp;_td]:whitespace-nowrap [&amp;amp;_tr:first-child]:font-semibold [&amp;amp;_tr:first-child]:text-checkly-deep-blue&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Queued + in-flight check runs&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Resulting pods&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;0&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;2 (idle floor)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;2&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;3&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;3&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;7&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;7&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;20&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;10 (capped)&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/section&gt;&lt;figure class=&quot;my-6&quot;&gt;&lt;video class=&quot;w-full rounded-lg border border-gray-300 border-solid border-opacity-20&quot; autoplay=&quot;&quot; loop=&quot;&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; preload=&quot;auto&quot;&gt;&lt;source src=&quot;https://checklyhq.cdn.prismic.io/checklyhq/a1yAa7wDzbHnJPGP_autoscaling-testing-blog-v6.mp4&quot;/&gt;Your browser does not support the video tag.&lt;/video&gt;&lt;figcaption class=&quot;mt-2 text-center text text-sm&quot;&gt;Autoscaling in action: a burst of checks spikes the queue, the agent count scales from 1 to 11 to clear the backlog, then settles back to a right-sized floor.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;A few rules of thumb for the bounds:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Keep &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;minReplicaCount&lt;/code&gt; at 2 or higher. One agent is a single point of failure, and if it dies your whole location goes dark until a replacement spins up.&lt;/li&gt;&lt;li&gt;Set &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;maxReplicaCount&lt;/code&gt; above your expected peak load, because check runs that pile up past the cap get dropped after the queue&amp;#x27;s six-minute TTL.&lt;/li&gt;&lt;li&gt;Leave &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;threshold&lt;/code&gt; at &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;&amp;quot;1&amp;quot;&lt;/code&gt; unless you&amp;#x27;ve raised &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;JOB_CONCURRENCY&lt;/code&gt;; packing more checks per pod can delay long-running checks.&lt;/li&gt;&lt;li&gt;If you want to scale to zero when a location is completely idle, set &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;minReplicaCount: 0&lt;/code&gt; and tune &lt;a target=&quot;_blank&quot; href=&quot;https://keda.sh/docs/latest/reference/scaledobject-spec/#cooldownperiod&quot; rel=&quot;noreferrer&quot;&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;cooldownPeriod&lt;/code&gt;&lt;/a&gt;, which controls how long KEDA waits after load drops before scaling all the way down.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;don-t-kill-checks-mid-run&quot;&gt;&lt;a href=&quot;#don-t-kill-checks-mid-run&quot;&gt;Don&amp;#x27;t kill checks mid-run&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Scaling down means evicting pods, and an evicted pod might be running a check. Checkly handles this for you: an in-flight check on a terminating pod gets rerun on another agent after a 300-second timeout, so a scale-down never silently loses a result. To give a pod room to finish its current work before Kubernetes sends &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SIGKILL&lt;/code&gt;, set &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;terminationGracePeriodSeconds&lt;/code&gt; above that window on the agent pod spec:&lt;/p&gt;&lt;div class=&quot;code-block theme-light&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;template&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;terminationGracePeriodSeconds&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;330&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Set it to match your longest check type. Most checks finish fast, but Playwright Check Suites can run up to an hour, so bump the grace period accordingly:&lt;/p&gt;&lt;section class=&quot;theme-light py-10 md:py-12&quot; data-slice-type=&quot;dynamic_data_table&quot; data-slice-variation=&quot;default&quot;&gt;&lt;div class=&quot;overflow-x-auto pb-2 [scrollbar-color:theme(colors.checkly.blue)_theme(colors.gray.100)] [scrollbar-width:thin] [&amp;amp;::-webkit-scrollbar-thumb]:rounded-full [&amp;amp;::-webkit-scrollbar-thumb]:bg-checkly-blue [&amp;amp;::-webkit-scrollbar-track]:rounded-full [&amp;amp;::-webkit-scrollbar-track]:bg-gray-100 [&amp;amp;::-webkit-scrollbar]:h-2&quot;&gt;&lt;table class=&quot;w-full text-left text-sm max-md:text-xs [&amp;amp;_td]:whitespace-nowrap [&amp;amp;_tr:first-child]:font-semibold [&amp;amp;_tr:first-child]:text-checkly-deep-blue&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Check type&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Maximum runtime&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;API, TCP, DNS, ICMP&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;30 seconds&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Browser&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;4 minutes&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Multistep&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;4 minutes&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Playwright Check Suite&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;60 minutes&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;If you run Playwright Check Suites in this location, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;terminationGracePeriodSeconds&lt;/code&gt; can go as high as 1800.&lt;/p&gt;&lt;h2 id=&quot;what-this-gets-you&quot;&gt;&lt;a href=&quot;#what-this-gets-you&quot;&gt;What this gets you&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Your checks stay reliable under load. When a deploy or a traffic spike floods the queue, agents scale up to clear it instead of letting runs wait. That means faster, more dependable detection from inside your own infrastructure.&lt;/p&gt;&lt;p&gt;You also avoid paying for idle capacity. Rather than keeping enough agents running all day to handle occasional peaks, you can maintain a smaller baseline and scale up only when needed. Across multiple Private Locations, that unused capacity can add up quickly.&lt;/p&gt;&lt;h2 id=&quot;get-started&quot;&gt;&lt;a href=&quot;#get-started&quot;&gt;Get started&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Private Locations are available on Checkly&amp;#x27;s Team and Enterprise plans. If you&amp;#x27;re already running agents on Kubernetes, follow the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/platform/private-locations/autoscaling/&quot; rel=&quot;noreferrer&quot;&gt;Private Location Autoscaling guide&lt;/a&gt; for the complete setup, including how to verify that KEDA is receiving the metric. Enable &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/integrations/observability/prometheus-v2/&quot; rel=&quot;noreferrer&quot;&gt;Prometheus V2&lt;/a&gt;, apply in the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;ScaledObject&lt;/code&gt;, and run a batch of checks to see how your agent deployment scales with demand.&lt;/p&gt;&lt;p&gt;Already using Private Locations? Open a location in the Checkly UI to view its queue duration, agent count, and scheduled check runs. These metrics help you quickly identify whether you have too little or too much capacity.&lt;/p&gt;&lt;p&gt;New to Checkly? &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/pricing/&quot; rel=&quot;noreferrer&quot;&gt;See pricing&lt;/a&gt; to find the plan that fits, or &lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/signup&quot; rel=&quot;noreferrer&quot;&gt;start for free&lt;/a&gt; to try the rest of the platform.&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Rocky reads your stack, not just your check]]></title><description><![CDATA[Rocky AI root cause analysis now reads OpenTelemetry traces. When a Checkly check fails, Rocky walks the backend span chain to find the root cause.]]></description><link>https://www.checklyhq.com/blog/rocky-ai-opentelemetry-traces</link><guid isPermaLink="false">ah_0pxIAAC4Af59-</guid><category><![CDATA[AI]]></category><category><![CDATA[Announcements]]></category><category><![CDATA[OpenTelemetry]]></category><dc:creator><![CDATA[Stefan Judis]]></dc:creator><pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;You get an infrastructure alert. Something&amp;#x27;s off, so you task your agent to investigate, and it ends up grepping through the logs. You both wonder if there&amp;#x27;s customer impact.&lt;/p&gt;&lt;p&gt;There’s a simple rule: &lt;strong&gt;AI agents in the incident loop are only as good as the signal you feed them. And logs alone aren&amp;#x27;t a great signal.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Synthetic monitoring at least solves the impact question. When a check fails, something user-facing is broken. You know &lt;em&gt;what&lt;/em&gt; broke, not &lt;em&gt;why&lt;/em&gt;. OpenTelemetry traces have answered that &lt;em&gt;why&lt;/em&gt; for a while, and &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/traces-open-telemetry/&quot; rel=&quot;noreferrer&quot;&gt;Checkly supports them natively&lt;/a&gt;. But there was an unacceptable catch in the agentic world: a human still had to correlate the two by switching tabs, finding the right service, copying a trace ID, and walking the spans. By the time they had an answer, the next check had already run.&lt;/p&gt;&lt;blockquote class=&quot;bg-gray-100 p-4 border-l-2 my-4 border-blue-300 inline-block space-y-4&quot;&gt;&lt;p&gt;&amp;quot;We have a lot of traces collected, but people maybe don&amp;#x27;t know they exist… I think Checkly is a way to integrate traces into developers&amp;#x27; workflow.&amp;quot;&lt;/p&gt;&lt;p&gt;— Observability lead, leading public-safety tech company&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Rocky AI, &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/resolve/ai-root-cause-analysis/overview/&quot; rel=&quot;noreferrer&quot;&gt;Checkly&amp;#x27;s agent&lt;/a&gt;, now does that investigation walk for you. &lt;strong&gt;If a check fails, Rocky reads your OpenTelemetry traces and walks the spans behind the failure.&lt;/strong&gt; When you&amp;#x27;re on call, &amp;quot;Where do I even start looking?&amp;quot; becomes &amp;quot;Let me validate my agent&amp;#x27;s fix!&amp;quot;.&lt;/p&gt;&lt;figure class=&quot;my-6&quot;&gt;&lt;video class=&quot;w-full rounded-lg border border-gray-300 border-solid border-opacity-20&quot; autoplay=&quot;&quot; loop=&quot;&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; preload=&quot;auto&quot;&gt;&lt;source src=&quot;https://checklyhq.cdn.prismic.io/checklyhq/aiFGaQeQX7-eWuVk_RockyOtelRCABlog.mp4&quot;/&gt;Your browser does not support the video tag.&lt;/video&gt;&lt;figcaption class=&quot;mt-2 text-center text text-sm&quot;&gt;Rocky Analysis using OTEL traces&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id=&quot;what-rocky-ai-reads-per-check-type&quot;&gt;&lt;a href=&quot;#what-rocky-ai-reads-per-check-type&quot;&gt;What Rocky AI reads, per check type&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Good signal in, good answer out. So Rocky&amp;#x27;s context comes in three layers:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The failure itself (whatever the check type produces: request, response, headers, traceroute, assertions, test source, etc.)&lt;/li&gt;&lt;li&gt;A set of on-demand tools Rocky reaches for when the picture is incomplete (the last passing run, PCAP data for API checks, Playwright trace files for browser failures)&lt;/li&gt;&lt;li&gt;Context provided by a human (the check description field, the tags, the &amp;quot;add context&amp;quot; box in the RCA UI)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;OTEL traces are the newest tool in that on-demand layer.&lt;/p&gt;&lt;section class=&quot;theme-light py-10 md:py-12&quot; data-slice-type=&quot;dynamic_data_table&quot; data-slice-variation=&quot;default&quot;&gt;&lt;div class=&quot;overflow-x-auto pb-2 [scrollbar-color:theme(colors.checkly.blue)_theme(colors.gray.100)] [scrollbar-width:thin] [&amp;amp;::-webkit-scrollbar-thumb]:rounded-full [&amp;amp;::-webkit-scrollbar-thumb]:bg-checkly-blue [&amp;amp;::-webkit-scrollbar-track]:rounded-full [&amp;amp;::-webkit-scrollbar-track]:bg-gray-100 [&amp;amp;::-webkit-scrollbar]:h-2 [&amp;amp;_td]:text-center [&amp;amp;_th]:text-center&quot;&gt;&lt;table class=&quot;w-full text-left text-sm max-md:text-xs [&amp;amp;_td]:whitespace-nowrap [&amp;amp;_tr:first-child]:font-semibold [&amp;amp;_tr:first-child]:text-checkly-deep-blue&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Source&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;API&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Playwright&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Browser&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;MultiStep&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;DNS&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;TCP&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;ICMP&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Notes&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Check Result Payload&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Check Description&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Description context&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;User Context&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;UI text box&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Tags&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Tag names&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Last Passing Result&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;On-demand tool&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;OTEL traces (new!)&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;On-demand tool&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;PCAP&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;API-Checks only&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;text-gray-500 even:bg-gray-100&quot;&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;Playwright Trace&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;✅&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;-&lt;/p&gt;&lt;/td&gt;&lt;td class=&quot;px-5 py-4 first:font-semibold first:text-checkly-deep-blue&quot;&gt;&lt;p&gt;On-demand tool&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/section&gt;&lt;h2 id=&quot;what-rocky-ai-does-with-otel-traces&quot;&gt;&lt;a href=&quot;#what-rocky-ai-does-with-otel-traces&quot;&gt;What Rocky AI does with OTEL traces&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Once you set up traces, every check Checkly runs injects a W3C &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;traceparent&lt;/code&gt; header (tagged &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;tracestate: checkly=true&lt;/code&gt;) on its outgoing requests. Your backend&amp;#x27;s OpenTelemetry instrumentation continues that same trace, so your spans share the trace ID Checkly generated. When those traces are sent back to Checkly, it stitches them to the originating check run by trace ID. That&amp;#x27;s what puts your backend traces right alongside a failing check, giving Rocky the evidence to pinpoint the root cause.&lt;/p&gt;&lt;p&gt;A 500 error on an API or Playwright check might trace back to a downstream identity provider returning DNS errors, a Clickhouse server timing out, or a third-party payment API throwing 502s through your load balancer. The same check failure could have countless reasons, different stories in the spans, and multiple teams that own the fix.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/ah_-aweQX7-eWpn3_otel.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;Rocky classifies (&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;INFRASTRUCTURE_ERROR&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;DOWNSTREAM_DEPENDENCY&lt;/code&gt;), names the offending service, and writes a root cause, user impact, and suggested fix. It all lands in whatever alert channel you already use, Slack, PagerDuty, a webhook.&lt;/p&gt;&lt;p&gt;There&amp;#x27;s no separate add-on. If &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/resolve/traces/import/open-telemetry/&quot; rel=&quot;noreferrer&quot;&gt;your traces are flowing into Checkly&lt;/a&gt;, Rocky reads them.&lt;/p&gt;&lt;p&gt;Remember the agent you tasked at the top of this post? The one grepping logs? It can read this analysis too.&lt;/p&gt;&lt;h2 id=&quot;the-same-root-cause-analysis-for-your-coding-agent&quot;&gt;&lt;a href=&quot;#the-same-root-cause-analysis-for-your-coding-agent&quot;&gt;The same root cause analysis, for your coding agent&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Rocky&amp;#x27;s analysis &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/blog/rocky-ai-cli-and-public-api/&quot; rel=&quot;noreferrer&quot;&gt;is also available via the Checkly CLI&lt;/a&gt;, and who loves using CLI tools? Your agent!&lt;/p&gt;&lt;p&gt;Make sure to install the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/ai/skills/&quot; rel=&quot;noreferrer&quot;&gt;Checkly skills&lt;/a&gt;, point your coding agent at a failing check, and ask it to investigate. It picks up the right CLI commands on its own and reads the same classification, root cause, user impact, and suggested fix. Including, when it&amp;#x27;s available, the OTEL trace Rocky walked.&lt;/p&gt;&lt;figure class=&quot;my-6&quot;&gt;&lt;video class=&quot;w-full rounded-lg border border-gray-300 border-solid border-opacity-20&quot; autoplay=&quot;&quot; loop=&quot;&quot; controls=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot; preload=&quot;auto&quot;&gt;&lt;source src=&quot;https://checklyhq.cdn.prismic.io/checklyhq/aiFM4AeQX7-eWuZ0_rocky-otel-chat.mp4&quot;/&gt;Your browser does not support the video tag.&lt;/video&gt;&lt;figcaption class=&quot;mt-2 text-center text text-sm&quot;&gt;Agent Conversation using Rocky&amp;#x27;s Root Cause Analysis&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;That&amp;#x27;s &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/blog/the-agentic-software-layer/&quot; rel=&quot;noreferrer&quot;&gt;the agentic layer&lt;/a&gt; in action. There&amp;#x27;s no magic. Just CLI commands and agents helping each other out with good signal. And what about you?&lt;/p&gt;&lt;p&gt;You don&amp;#x27;t need to post screenshots into Slack threads, or investigate by hand. You&amp;#x27;re only in charge of validating the fix! Welcome to the new world.&lt;/p&gt;&lt;h2 id=&quot;wire-up-otel-and-inspect-the-why&quot;&gt;&lt;a href=&quot;#wire-up-otel-and-inspect-the-why&quot;&gt;Wire up OTEL and inspect the &lt;em&gt;why&lt;/em&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re already on Checkly with OTEL flowing in, Rocky is already walking those traces. Enjoy! Open a failing check and read the analysis.&lt;/p&gt;&lt;p&gt;If you&amp;#x27;re not yet sending traces to Checkly, the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/resolve/traces/how-it-works/&quot; rel=&quot;noreferrer&quot;&gt;setup docs&lt;/a&gt; get you there.&lt;/p&gt;&lt;p&gt;Without traces, Rocky&amp;#x27;s intelligence stops at the border of your app. With them, your check failures come with the &lt;em&gt;why&lt;/em&gt; attached so you can stop hunting for it. And your agent will happily stop grepping logs. Win-win!&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Two AI agents, one incident: Rocky AI comes to the terminal]]></title><description><![CDATA[Rocky AI analysis is now in your Checkly CLI and behind a public API. Pull root cause analysis straight from `checkly checks get` to get your agents context to fix failed checks faster]]></description><link>https://www.checklyhq.com/blog/rocky-ai-cli-and-public-api</link><guid isPermaLink="false">ae97rRoAAEQAoHhx</guid><category><![CDATA[AI]]></category><category><![CDATA[Announcements]]></category><category><![CDATA[Monitoring as Code (MaC)]]></category><dc:creator><![CDATA[Stefan Judis]]></dc:creator><pubDate>Wed, 29 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;A Playwright Check fails at 2 am. The login flow is broken. Until today, that alert triggered a human to get up, open the Checkly dashboard, copy &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/resolve/ai-root-cause-analysis/overview/&quot; rel=&quot;noreferrer&quot;&gt;Rocky AI root cause analysis (RCA)&lt;/a&gt;, and then tell an agent to get to work.&lt;/p&gt;&lt;p&gt;There were two AI agents, one incident, and no way for them to talk to each other.&lt;/p&gt;&lt;p&gt;The extended &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly checks&lt;/code&gt; and new &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly rca&lt;/code&gt; CLI commands close that gap. Your coding agent can now pull Rocky AI&amp;#x27;s analysis into its ongoing work, read the diagnosis, and go fix the code. Everything happens in the same session.&lt;/p&gt;&lt;p&gt;There&amp;#x27;s no poor soul on call required to pass around information.&lt;/p&gt;&lt;h2 id=&quot;meet-the-two-agents&quot;&gt;&lt;a href=&quot;#meet-the-two-agents&quot;&gt;Meet the two agents&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;One sees production from the outside. The other sees the code from the inside.&lt;/p&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/blog/introducing-rocky-ai/&quot; rel=&quot;noreferrer&quot;&gt;Rocky AI&lt;/a&gt; is the one watching your production site. It knows about failed checks, error messages, monitoring scripts, logs, metrics, network waterfalls, packet captures, and Playwright traces. Its entire and only job is to come back with a classification, a plain-English root cause, a user-impact assessment, evidence, and a suggested fix.&lt;/p&gt;&lt;p&gt;Your coding agent, on the other hand, is the one handling your application. If it uses &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/blog/the-agentic-software-layer/&quot; rel=&quot;noreferrer&quot;&gt;the agentic layer&lt;/a&gt;, it can query databases, tail logs, hit APIs, and poke at your entire infrastructure. It can see production from the inside, the way the code sees it.&lt;/p&gt;&lt;p&gt;What it couldn&amp;#x27;t reach, until now, was Rocky AI analysis itself. Rocky sits a layer above the raw signals. It&amp;#x27;s a specialist who&amp;#x27;s already analyzed everything your monitoring produces into one diagnosis. For your coding agent, that&amp;#x27;s gold. Your agent skips the evaluation and already knows the kind of bug plus the evidence to reason from. Without Rocky&amp;#x27;s analysis, your agent has to redo the triage from scratch, which only burns tokens and risks the wrong fix. Especially on production alerts, every minute counts.&lt;/p&gt;&lt;p&gt;Until now, those two agents have never met. Rocky AI analysis stayed inside the Checkly UI. Your coding agent had plenty of reach, except for your alert analysis. This changes now.&lt;/p&gt;&lt;h2 id=&quot;rocky-ai-analysis-in-your-terminal&quot;&gt;&lt;a href=&quot;#rocky-ai-analysis-in-your-terminal&quot;&gt;Rocky AI analysis, in your terminal&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you have &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/resolve/ai-root-cause-analysis/overview/#automatic-analysis&quot; rel=&quot;noreferrer&quot;&gt;automatic Rocky analysis&lt;/a&gt; enabled, the root cause analysis is already embedded in the check result. Your agent doesn&amp;#x27;t need a new command. &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly checks&lt;/code&gt; already returns the results:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# access the failing checks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--status&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;failing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# access check results&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;check-i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# access the root cause analysis for the current error group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;check-i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--error-group&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;group-i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The error group&amp;#x27;s output includes the root cause, user impact, cited evidence (HTTP traces, assertions, timings), and reference links. Everything Rocky already checked and analyzed is available for you and your agent.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/afH2KsBOoF08xanx_AdobeExpress-RockyAITerminal-ErrorGroupRCA-1-.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;when-should-you-use-checkly-rca-directly-&quot;&gt;&lt;a href=&quot;#when-should-you-use-checkly-rca-directly-&quot;&gt;When should you use &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly rca&lt;/code&gt; directly?&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;There are two cases where you reach for &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/cli/checkly-rca/&quot; rel=&quot;noreferrer&quot;&gt;the dedicated &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;rca&lt;/code&gt; command&lt;/a&gt;:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;You&amp;#x27;ve turned off automatic analysis&lt;/strong&gt; to control your invocation quota, and you want to trigger RCA only for specific failures.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;You want to analyze a past failure&lt;/strong&gt; that never got an automatic analysis. It could be a flaky check from last week, a historical outage, anything predating when you enabled Rocky.&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# Run a fresh analysis on an error group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;rca&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--error-group&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;group-i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--watch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# Fetch a previously-triggered analysis by its RCA ID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;rca&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;rca-i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--output&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;rca&lt;/code&gt; command supports different output formats: &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;detail&lt;/code&gt;(default, human-friendly), &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;md&lt;/code&gt; (good for PR descriptions), and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;json&lt;/code&gt; (the one agents love).&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/afH27MBOoF08xaoN_AdobeExpress-RockyAITerminal-RcaRunWatch-2-.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;not-in-the-terminal-the-same-data-is-in-the-public-api&quot;&gt;&lt;a href=&quot;#not-in-the-terminal-the-same-data-is-in-the-public-api&quot;&gt;&lt;strong&gt;Not in the terminal? The same data is in the public API&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;There &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/api-reference/rocky-ai/retrieve-one-root-cause-analysis/&quot; rel=&quot;noreferrer&quot;&gt;are three new endpoints&lt;/a&gt; to analyze your failing checks and start new Rocky analyses:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;GET /v1/root-cause-analyses/{id}&lt;/code&gt; to retrieve an existing root cause analysis&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;POST /v1/root-cause-analyses/error-groups/{errorGroupId}&lt;/code&gt; to generate a new root cause analysis for a check error group&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;POST /v1/root-cause-analyses/test-session-error-groups/{testsessionErrorGroupId}&lt;/code&gt; to generate a new root cause analysis for a test session error group&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;from-alert-to-pr-a-fast-and-optimized-agent-loop&quot;&gt;&lt;a href=&quot;#from-alert-to-pr-a-fast-and-optimized-agent-loop&quot;&gt;From alert to PR — a fast and optimized agent loop&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Here&amp;#x27;s the workflow end-to-end with an agent driving.&lt;/p&gt;&lt;p&gt;An alert is triggered. Rocky has already analyzed what&amp;#x27;s going on. It pulled the evidence, classified the failure, and wrote up the root cause. You hand it over to your agent, telling it only that &amp;quot;something&amp;#x27;s off&amp;quot;.&lt;/p&gt;&lt;p&gt;From there, your agent already knows which commands to reach for. &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/ai/skills/&quot; rel=&quot;noreferrer&quot;&gt;The Checkly skill&lt;/a&gt; taught it the playbook. It finds the failing check, accesses the analysis, and gets to work — pointed at the right surface, whether the fix lands in the check config, the production code, or infrastructure. The investigation is already done. Less guessing, quicker resolution.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/afH3ScBOoF08xaom_AdobeExpress-RockyAITerminal-InvestigateAlertSquare-5-.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;See the full loop in motion.&lt;/strong&gt; Stefan demos the end-to-end agentic workflow, from generating checks with coding agents to resolving incidents with Rocky AI, on the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/webinars/our-agentic-workflow-e2e&quot; rel=&quot;noreferrer&quot;&gt;agentic workflow webinar&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;get-started&quot;&gt;&lt;a href=&quot;#get-started&quot;&gt;Get started&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Install or upgrade to the latest Checkly CLI:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npm &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly@latest&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Install &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/ai/skills/&quot; rel=&quot;noreferrer&quot;&gt;the Checkly skills&lt;/a&gt; so your agent knows which commands to use:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;skills&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Tell your coding agent to investigate a failing check. With automatic analysis on, Rocky AI analysis comes inline:  &lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;blockquote class=&quot;bg-gray-100 p-4 border-l-2 my-4 border-blue-300 inline-block&quot;&gt;I&amp;#x27;ve received a Checkly alert. Can you investigate?&lt;/blockquote&gt;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;And that’s it!  &lt;/p&gt;&lt;p&gt;Previously, there were two AI agents, one incident, and a human connecting them.  &lt;/p&gt;&lt;p&gt;Now, &lt;strong&gt;there&amp;#x27;s a single prompt&lt;/strong&gt;. That&amp;#x27;s the agentic layer in action. Specialized agents work together to resolve production issues as quickly as possible. Isn&amp;#x27;t this beautiful?&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[How to Monitor a Shopify Store with Playwright and Checkly]]></title><description><![CDATA[Learn how to monitor Shopify storefronts with Playwright and Checkly, including bot protection, consent popups, and checkout monitoring.]]></description><link>https://www.checklyhq.com/blog/monitoring-shopify-store-playwright-checkly</link><guid isPermaLink="false">adzXCxoAAEkAB7dD</guid><category><![CDATA[Playwright]]></category><category><![CDATA[Synthetic Monitoring]]></category><category><![CDATA[Monitoring as Code (MaC)]]></category><dc:creator><![CDATA[Vince Graics]]></dc:creator><pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;&lt;em&gt;This is a guest post by Vince Graics, Staff QA Engineer at World of Books.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;If you&amp;#x27;re running a Shopify storefront and want reliable synthetic monitoring, you&amp;#x27;ll hit a wall. Shopify&amp;#x27;s bot detection doesn&amp;#x27;t care that your headless browser is friendly; it sees datacenter IPs and acts accordingly. Cart API calls get hit with &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;429&lt;/code&gt; rate limits, Cloudflare challenge pages pop up mid-check, and you&amp;#x27;re left wondering whether the bug is in your code or in the platform fighting you.&lt;/p&gt;&lt;p&gt;At &lt;a target=&quot;_blank&quot; href=&quot;https://www.worldofbooks.com/&quot; rel=&quot;noreferrer&quot;&gt;World of Books&lt;/a&gt;, a UK-based secondhand bookseller running on Shopify, we ran into all of this while setting up monitoring with Checkly. The good news: Shopify actually has a fix for the bot-protection problem. The bad news: almost nobody talks about it, and there are a couple of non-obvious traps along the way.&lt;/p&gt;&lt;p&gt;This guide covers how we solved three Shopify-specific problems: bot protection headers, consent pop-up interception, and checkout flow testing. The patterns here work for any Shopify store. Swap out the selectors, plug in your store&amp;#x27;s URLs, and you have a working setup to monitor your Shopify store with Playwright.&lt;/p&gt;&lt;h2 id=&quot;what-makes-shopify-stores-hard-to-monitor-&quot;&gt;&lt;a href=&quot;#what-makes-shopify-stores-hard-to-monitor-&quot;&gt;What makes Shopify stores hard to monitor?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Shopify stores introduce platform-level obstacles that standard Playwright tests don&amp;#x27;t account for.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Bot protection.&lt;/strong&gt; Shopify evaluates incoming traffic based on IP reputation, headers, and behavioral patterns. Monitoring checks run from cloud infrastructure, and datacenter IPs get treated with suspicion. Sometimes you get a &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;429 Too Many Requests&lt;/code&gt; on a cart API call. Sometimes Cloudflare intercepts the request entirely and serves a challenge page. And sometimes everything &lt;em&gt;looks&lt;/em&gt; like it loaded, the page shell renders, the layout is there, but the interactive parts are quietly broken. A search page shows zero product cards. A mini-cart notification never appears.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Privacy and consent interception.&lt;/strong&gt; Shopify&amp;#x27;s privacy SDK fires on every page load, showing a cookie consent banner and blocking script execution until the user accepts. In a headless context, that banner just sits there, adding flakiness and wasted seconds to every run.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Checkout DOM isolation.&lt;/strong&gt; Shopify&amp;#x27;s checkout runs on &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkout.shopify.com&lt;/code&gt; with a completely different markup. The selectors you wrote for the storefront don&amp;#x27;t work on checkout, and the page structure can change between Shopify editions.&lt;/p&gt;&lt;p&gt;Each section below tackles one of these problems and builds on the solution.&lt;/p&gt;&lt;h2 id=&quot;how-do-you-bypass-shopify-bot-protection-&quot;&gt;&lt;a href=&quot;#how-do-you-bypass-shopify-bot-protection-&quot;&gt;How do you bypass Shopify bot protection?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Shopify provides a mechanism for authorized crawlers to identify themselves: &lt;a target=&quot;_blank&quot; href=&quot;https://help.shopify.com/en/manual/promoting-marketing/seo/crawling-your-store&quot; rel=&quot;noreferrer&quot;&gt;HTTP signature headers&lt;/a&gt;. You register your crawler in the Shopify admin, and Shopify gives you three headers: &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;Signature&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;Signature-Input&lt;/code&gt;, and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;Signature-Agent&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;When your requests include these headers, Shopify&amp;#x27;s bot protection lets them through cleanly.&lt;/p&gt;&lt;h3 id=&quot;creating-your-crawler-signature-in-shopify&quot;&gt;&lt;a href=&quot;#creating-your-crawler-signature-in-shopify&quot;&gt;Creating your crawler signature in Shopify&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;From your Shopify admin:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Go to &lt;strong&gt;Online Store &amp;gt; Preferences&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;In the &lt;strong&gt;Crawler access&lt;/strong&gt; section, click &lt;strong&gt;Create signature&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Enter a descriptive name (e.g., &amp;quot;Checkly Monitoring&amp;quot;)&lt;/li&gt;&lt;li&gt;Select the domain and an expiration period&lt;/li&gt;&lt;li&gt;Copy the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;Signature-Input&lt;/code&gt; and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;Signature&lt;/code&gt; values&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The third header, Signature-Agent, is static; its value is always &amp;quot;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;&amp;lt;https://shopify.com&amp;gt;&lt;/code&gt;&amp;quot; (with quotes).&lt;/p&gt;&lt;p&gt;One thing to watch for: signatures have an expiration date. Set a calendar reminder to rotate them before they expire, or your checks will start failing again with zero code changes. When they expire, every check returns a challenge page and it looks like your entire store is down.&lt;/p&gt;&lt;h3 id=&quot;storing-headers-as-checkly-secrets&quot;&gt;&lt;a href=&quot;#storing-headers-as-checkly-secrets&quot;&gt;Storing headers as Checkly secrets&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Add the three values as &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/platform/secrets/&quot; rel=&quot;noreferrer&quot;&gt;secrets in your Checkly account&lt;/a&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SHOPIFY_SIGNATURE&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SHOPIFY_SIGNATURE_INPUT&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SHOPIFY_SIGNATURE_AGENT&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This keeps your credentials out of code and makes them available to all your &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/browser-checks/playwright-test/&quot; rel=&quot;noreferrer&quot;&gt;browser checks&lt;/a&gt; at runtime.&lt;/p&gt;&lt;h3 id=&quot;injecting-the-headers-in-playwright&quot;&gt;&lt;a href=&quot;#injecting-the-headers-in-playwright&quot;&gt;Injecting the headers in Playwright&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The simplest approach, and what you should try first:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.setExtraHTTPHeaders&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Signature&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Signature-Input&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE_INPUT&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Signature-Agent&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE_AGENT&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;setExtraHTTPHeaders&lt;/code&gt; adds these headers to every request the page makes. For many Shopify stores, this just works and you&amp;#x27;re done.&lt;/p&gt;&lt;h3 id=&quot;when-you-need-scoped-header-injection&quot;&gt;&lt;a href=&quot;#when-you-need-scoped-header-injection&quot;&gt;When you need scoped header injection&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;If your store uses third-party services that don&amp;#x27;t play nice with extra headers, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;setExtraHTTPHeaders&lt;/code&gt; can cause problems. At World of Books, we hit this with a third-party search provider: the extra headers on cross-origin requests appeared to interfere with its responses, and product listings silently came back empty. No errors, no warnings; just an empty product grid and a check that fails for reasons that take an hour to debug.&lt;/p&gt;&lt;p&gt;The fix is Playwright&amp;#x27;s &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;page.route()&lt;/code&gt;, which scopes header injection to your own domain:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;crawlerHeaders&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;Record&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE_INPUT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE_AGENT&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Signature&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Signature-Input&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE_INPUT&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Signature-Agent&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;SHOPIFY_SIGNATURE_AGENT&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.route&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;**/www.yourstore.com/**&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; route &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.continue&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    headers&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.request&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.headers&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;crawlerHeaders }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  })&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Third-party requests pass through untouched. A few things to note:&lt;/p&gt;&lt;p&gt;All three headers are required together. If any are missing, skip the injection entirely; partial headers won&amp;#x27;t work with Shopify&amp;#x27;s validation. And spread existing headers first: &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;route.continue()&lt;/code&gt; replaces headers entirely, so the spread preserves cookies, content types, and everything else the browser set. After your test, call &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;page.unrouteAll({ behavior: &amp;#x27;ignoreErrors&amp;#x27; })&lt;/code&gt; to avoid route handler leaks between checks.&lt;/p&gt;&lt;h3 id=&quot;scaling-this-with-playwright-fixtures&quot;&gt;&lt;a href=&quot;#scaling-this-with-playwright-fixtures&quot;&gt;Scaling this with Playwright fixtures&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Once you have more than a couple of checks, you don&amp;#x27;t want to repeat the header setup in every file. Playwright fixtures let you extend the base &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;page&lt;/code&gt; object once and use it everywhere:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; { test &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; base } &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.extend&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; ({ page }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; use) &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.keys&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(crawlerHeaders).&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.route&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;**/www.yourstore.com/**&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; route &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.continue&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;          headers&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;route&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.request&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.headers&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;crawlerHeaders }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        })&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(page);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.unrouteAll&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({ behavior&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;ignoreErrors&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Every check that imports &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;test&lt;/code&gt; from this fixture gets crawler header injection automatically. No headers configured? The fixture is a no-op; your checks still work locally without Shopify credentials.&lt;/p&gt;&lt;h2 id=&quot;how-do-you-handle-shopify-consent-popups-&quot;&gt;&lt;a href=&quot;#how-do-you-handle-shopify-consent-popups-&quot;&gt;How do you handle Shopify consent popups?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The consent banner problem is frustrating because it&amp;#x27;s invisible in manual testing (you click it once and forget it) but it breaks every automated check.&lt;/p&gt;&lt;p&gt;Playwright&amp;#x27;s &lt;a target=&quot;_blank&quot; href=&quot;https://playwright.dev/docs/api/class-page#page-add-locator-handler&quot; rel=&quot;noreferrer&quot;&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;page.addLocatorHandler()&lt;/code&gt;&lt;/a&gt; lets you register a handler that fires whenever a matching element appears. Think of it as a popup bouncer for your checks:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.extend&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; ({ page }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; use) &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.addLocatorHandler&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.locator&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;[aria-label=&amp;quot;Close popup&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.locator&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;[aria-label=&amp;quot;Close popup&amp;quot;]&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.click&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(page);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This works well for stores with a single, consistent popup. If your store has multiple overlays (newsletter signups, region selectors), you can register additional handlers with different locators. The key is keeping the selectors stable; &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;aria-label&lt;/code&gt; attributes tend to survive theme updates better than CSS classes.&lt;/p&gt;&lt;h2 id=&quot;how-do-you-test-shopify-checkout-&quot;&gt;&lt;a href=&quot;#how-do-you-test-shopify-checkout-&quot;&gt;How do you test Shopify checkout?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Checkout is where monitoring gets tricky, because you&amp;#x27;re crossing into &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkout.shopify.com&lt;/code&gt; with its own DOM, its own selectors, and real money involved.&lt;/p&gt;&lt;h3 id=&quot;setting-up-safe-checkout-testing-with-shopify-flow&quot;&gt;&lt;a href=&quot;#setting-up-safe-checkout-testing-with-shopify-flow&quot;&gt;Setting up safe checkout testing with Shopify Flow&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;You can&amp;#x27;t just skip checkout monitoring; it&amp;#x27;s the flow that matters most to your business. But running real transactions in production sounds terrifying. Here&amp;#x27;s the approach my team at World of Books came up with, using &lt;a target=&quot;_blank&quot; href=&quot;https://apps.shopify.com/flow&quot; rel=&quot;noreferrer&quot;&gt;Shopify Flow&lt;/a&gt;:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Get a company card&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Create a dedicated test user&lt;/strong&gt; on your production store&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Set up a Flow automation&lt;/strong&gt;: if this specific user purchases something, the workflow immediately refunds the order and cancels the trade&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Run your checkout checks&lt;/strong&gt; against this test user&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;You can now run regular checkout validations until you run out of the company card budget, and wait for the refunds. It&amp;#x27;s not elegant, but it works, and it tests the &lt;em&gt;real&lt;/em&gt; checkout flow, not a staging approximation.&lt;/p&gt;&lt;h2 id=&quot;deploying-to-checkly&quot;&gt;&lt;a href=&quot;#deploying-to-checkly&quot;&gt;Deploying to Checkly&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Once the checks pass locally, deploy with the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/cli/&quot; rel=&quot;noreferrer&quot;&gt;Checkly CLI&lt;/a&gt;:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;# Test against Checkly infrastructure first&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;checkly test &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;record&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;# Deploy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;checkly deploy &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;f &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;o&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Set your environment variables in the Checkly dashboard under the check group. The required ones: &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SHOPIFY_SIGNATURE&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SHOPIFY_SIGNATURE_INPUT&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SHOPIFY_SIGNATURE_AGENT&lt;/code&gt;. Add &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;LOGIN_EMAIL&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;LOGIN_PASSWORD&lt;/code&gt;, and discount codes if you&amp;#x27;re monitoring authenticated or promotional flows.&lt;/p&gt;&lt;p&gt;Because everything lives in your repo as code, your Shopify monitoring ships through the same CI/CD pipeline as your application. That&amp;#x27;s the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/product/monitoring-as-code/&quot; rel=&quot;noreferrer&quot;&gt;Monitoring as Code&lt;/a&gt; approach: your checks are versioned, reviewed in PRs, and deployed automatically. No clicking through a UI to update a threshold.&lt;/p&gt;&lt;h2 id=&quot;troubleshooting-common-failures&quot;&gt;&lt;a href=&quot;#troubleshooting-common-failures&quot;&gt;Troubleshooting common failures&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Challenge page instead of storefront.&lt;/strong&gt; Your crawler headers are missing or expired. Regenerate them in Shopify Admin and update the env vars in Checkly.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Login fails or loops.&lt;/strong&gt; Test account credentials are wrong, the account is locked, or MFA got enabled. Use a dedicated test account that the store admin has allowlisted.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Discount code shows &amp;quot;not valid.&amp;quot;&lt;/strong&gt; The code expired, hit its usage limit, or targets the wrong region. Verify it in Shopify Admin &amp;gt; Discounts. Use unlimited test codes.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Checks pass locally, fail on Checkly.&lt;/strong&gt; Almost always missing environment variables. Run &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly env ls&lt;/code&gt; to verify. Second most common cause: viewport mismatch. Set &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;viewport: { width: 1920, height: 1080 }&lt;/code&gt; explicitly in your Playwright config.&lt;/p&gt;&lt;h2 id=&quot;wrapping-up&quot;&gt;&lt;a href=&quot;#wrapping-up&quot;&gt;Wrapping up&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;At World of Books, customer experience is the reason we monitor our Shopify storefront so closely. If search breaks, checkout stalls, or a pop-up blocks the flow, it&amp;#x27;s important that we know before our customers do. Shopify can be difficult to test with headless browsers, but once we added crawler-signature headers via Checkly secrets, used a Playwright fixture to centralize header injection and consent handling, and set up Shopify Flow to clean up checkout test orders, the setup became reliable. The checks now see the same storefront our customers see, without the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;429&lt;/code&gt;s, Cloudflare challenges, or quiet failures that make Shopify monitoring so frustrating.&lt;/p&gt;&lt;p&gt;If your checks keep mysteriously failing, check your headers.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/cli/&quot; rel=&quot;noreferrer&quot;&gt;Checkly CLI documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/browser-checks/playwright-test/&quot; rel=&quot;noreferrer&quot;&gt;Playwright browser check docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://help.shopify.com/en/manual/promoting-marketing/seo/crawling-your-store&quot; rel=&quot;noreferrer&quot;&gt;Shopify crawler header documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/signup&quot; rel=&quot;noreferrer&quot;&gt;Sign up for Checkly free&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Checkly Playwright Reporter: A Cloud Dashboard for Your Playwright Tests]]></title><description><![CDATA[Send Playwright test runs to Checkly with traces, videos, screenshots, flaky test visibility, and session history, then take key tests into monitoring.]]></description><link>https://www.checklyhq.com/blog/checkly-playwright-reporter</link><guid isPermaLink="false">acOgGRoAAEYAuCWu</guid><category><![CDATA[Product]]></category><category><![CDATA[Playwright]]></category><category><![CDATA[Announcements]]></category><dc:creator><![CDATA[Pırıl Kavlak,María de Antón]]></dc:creator><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;&lt;strong&gt;The Checkly Playwright Reporter&lt;/strong&gt; is an npm package that sends the results of npx playwright test to Checkly as a cloud test session, including traces, screenshots, videos, and full debugging context. Run your Playwright suite in CI or locally, and every result gets a persistent, shareable home in Checkly with AI-powered analysis, richer trace-derived views, and a direct path to production monitoring.&lt;/p&gt;&lt;p&gt;It does not replace Playwright. It makes the output of Playwright much easier to work with.&lt;/p&gt;&lt;p&gt;Today, the reporter is available at no additional cost on all Checkly plans.&lt;/p&gt;&lt;h2 id=&quot;why-we-built-this&quot;&gt;&lt;a href=&quot;#why-we-built-this&quot;&gt;Why we built this&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Checkly has supported Playwright for years. You could write Playwright tests, validate them with npx checkly test, and deploy them as production monitors with npx checkly deploy. That workflow is powerful for production monitoring.&lt;/p&gt;&lt;p&gt;But most teams run npx playwright test hundreds of times a week in GitHub Actions, GitLab CI, or locally, and those results never reach Checkly. The evidence ends up scattered across CI logs, local trace files, and one-off HTML reports. That&amp;#x27;s manageable for an individual, but it breaks down for a team.&lt;/p&gt;&lt;p&gt;The Checkly Playwright Reporter helps close that gap by giving teams a shared place to review Playwright runs in Checkly.&lt;/p&gt;&lt;p&gt;From there, teams can run Playwright Check Suites with npx checkly pw-test, and when a test is important enough, npx checkly deploy can take it into production monitoring.&lt;/p&gt;&lt;p&gt;But it is not only about having a place to persist your test results. Once those results are in Checkly, &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/product/ai-analysis/&quot; rel=&quot;noreferrer&quot;&gt;Rocky AI&lt;/a&gt; can help analyze failed runs directly in the UI.&lt;/p&gt;&lt;p&gt;When enabled, Rocky AI can include AI-assisted root cause analysis and visibility into recurring failures across runs.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/ac1Nm5GXnQHGZLQZ_rockyAIanalysis.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;what-you-get-beyond-a-hosted-report&quot;&gt;&lt;a href=&quot;#what-you-get-beyond-a-hosted-report&quot;&gt;What you get beyond a hosted report&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Today, there are several ways to get Playwright test results into the cloud, including Microsoft&amp;#x27;s own Playwright Workspaces. But most of them stop at hosting: they take the same local Playwright HTML report and put it behind a URL. That solves the sharing problem. It does not solve the understanding problem.&lt;/p&gt;&lt;p&gt;The Checkly Playwright Reporter goes further:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Filterable network view&lt;/strong&gt; — every request and response captured from the trace, organized so you can focus on the failures instead of scanning a raw list.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Filterable browser console&lt;/strong&gt; — browser console output pulled into a cleaner view, including an errors-only filter.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Automatic secret scrubbing&lt;/strong&gt; — secrets can be scrubbed before upload, including support for the CHECKLY_SECRET_ prefix and sensitive header redaction.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;System performance graphs&lt;/strong&gt; — CPU and memory usage tracked throughout the test run, so you can spot whether a flaky or failing test might be tied to resource pressure.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Terminal progress and summary table&lt;/strong&gt; — a clearer terminal view of what passed, failed, flaked, or got skipped across projects.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Automatic git detection&lt;/strong&gt; — branch, commit, and author metadata can be attached to sessions automatically in CI and local git environments.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;History across runs&lt;/strong&gt; — instead of treating every run as an isolated local report, you can review patterns over time and see when the same failures keep coming back.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Hosting a report gives you a link. A reporting system gives you answers.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/ac1NypGXnQHGZLQc_viewsourcecode.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;how-to-set-up-the-checkly-playwright-reporter&quot;&gt;&lt;a href=&quot;#how-to-set-up-the-checkly-playwright-reporter&quot;&gt;How to set up the Checkly Playwright Reporter&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;You need:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Node.js 18 or newer&lt;/li&gt;&lt;li&gt;Playwright 1.40 or newer&lt;/li&gt;&lt;li&gt;a Checkly account&lt;/li&gt;&lt;li&gt;your CHECKLY_API_KEY and CHECKLY_ACCOUNT_ID&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Install the package:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npm install &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;save&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;dev @checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;playwright&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;reporter&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Add it to your  playwright.config.ts:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; { defineConfig } &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; { createChecklyReporter } &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;@checkly/playwright-reporter&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;defineConfig&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  reporter&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    [&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;list&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;createChecklyReporter&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  ]&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  use&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    screenshot&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;only-on-failure&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    video&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;retain-on-failure&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    trace&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;on&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Set credentials:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;CHECKLY_API_KEY&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;your_api_key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;CHECKLY_ACCOUNT_ID&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;your_account_id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Then run your suite as usual:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx playwright test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;When the run finishes, you get a Checkly test session URL in the terminal. That is the entire setup. No cloud infrastructure to provision, no storage accounts to link, no role assignments to configure.&lt;/p&gt;&lt;h2 id=&quot;try-the-checkly-playwright-reporter&quot;&gt;&lt;a href=&quot;#try-the-checkly-playwright-reporter&quot;&gt;&lt;strong&gt;Try the Checkly Playwright Reporter&lt;/strong&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If your team already uses Playwright, this is the fastest way to stop losing useful test context after the run.&lt;/p&gt;&lt;p&gt;Start here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/detect/testing/playwright-reporter/&quot; rel=&quot;noreferrer&quot;&gt;Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/detect/testing/playwright-reporter-changelog/&quot; rel=&quot;noreferrer&quot;&gt;Reporter changelog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/checkly/playwright-reporter-demo&quot; rel=&quot;noreferrer&quot;&gt;Demo repo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.npmjs.com/package/@checkly/playwright-reporter&quot; rel=&quot;noreferrer&quot;&gt;npm package&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;section data-slice-type=&quot;blog_faq&quot; data-slice-variation=&quot;default&quot; class=&quot;py-10 mt-4&quot;&gt;&lt;h2 class=&quot;title mb-2 text-2xl md:text-3xl&quot;&gt;Frequently Asked Questions&lt;/h2&gt;&lt;div class=&quot;space-y-3&quot;&gt;&lt;div class=&quot;rounded-2xl border border-blue-300/20 transition-[border-color] duration-200 ease-out hover:border-blue-300/35&quot;&gt;&lt;button type=&quot;button&quot; aria-expanded=&quot;false&quot; class=&quot;flex justify-between items-center px-6 py-5 md:px-8 w-full text-left text-checkly-deep-blue cursor-pointer transition-transform duration-150 motion-safe:active:scale-[0.995]&quot;&gt;&lt;span class=&quot;select-none text-base&quot;&gt;Is the Checkly Playwright Reporter free?&lt;/span&gt;&lt;svg viewBox=&quot;0 0 14 8&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;w-3 shrink-0 transition-transform duration-[250ms] ease-out rotate-0&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M0.46967 0.46967C0.762563 0.176777 1.23744 0.176777 1.53033 0.46967L7 5.93934L12.4697 0.46967C12.7626 0.176777 13.2374 0.176777 13.5303 0.46967C13.8232 0.762563 13.8232 1.23744 13.5303 1.53033L7.53033 7.53033C7.23744 7.82322 6.76256 7.82322 6.46967 7.53033L0.46967 1.53033C0.176777 1.23744 0.176777 0.762563 0.46967 0.46967Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;div style=&quot;max-height:0px;opacity:0;transition:max-height 250ms cubic-bezier(0.23, 1, 0.32, 1), opacity 150ms ease-out;overflow:hidden&quot;&gt;&lt;div class=&quot;px-6 pb-6 md:px-8 md:pb-8 rich-text&quot;&gt;&lt;p&gt;Yes. The reporter is free on all Checkly plans today, including the free tier. As we learn from usage and continue improving the product, pricing may evolve over time. Our goal is to keep it highly competitive relative to other reporting tools and make it easy for teams to get started.&lt;/p&gt;&lt;p&gt;If you are already using the reporter and want to share feedback, &lt;a target=&quot;_blank&quot; href=&quot;mailto:support@checklyhq.com&quot; rel=&quot;noreferrer&quot;&gt;get in touch&lt;/a&gt;! We&amp;#x27;d love to hear from early users helping shape the product.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rounded-2xl border border-blue-300/20 transition-[border-color] duration-200 ease-out hover:border-blue-300/35&quot;&gt;&lt;button type=&quot;button&quot; aria-expanded=&quot;false&quot; class=&quot;flex justify-between items-center px-6 py-5 md:px-8 w-full text-left text-checkly-deep-blue cursor-pointer transition-transform duration-150 motion-safe:active:scale-[0.995]&quot;&gt;&lt;span class=&quot;select-none text-base&quot;&gt;Can I use the reporter in CI?&lt;/span&gt;&lt;svg viewBox=&quot;0 0 14 8&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;w-3 shrink-0 transition-transform duration-[250ms] ease-out rotate-0&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M0.46967 0.46967C0.762563 0.176777 1.23744 0.176777 1.53033 0.46967L7 5.93934L12.4697 0.46967C12.7626 0.176777 13.2374 0.176777 13.5303 0.46967C13.8232 0.762563 13.8232 1.23744 13.5303 1.53033L7.53033 7.53033C7.23744 7.82322 6.76256 7.82322 6.46967 7.53033L0.46967 1.53033C0.176777 1.23744 0.176777 0.762563 0.46967 0.46967Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;div style=&quot;max-height:0px;opacity:0;transition:max-height 250ms cubic-bezier(0.23, 1, 0.32, 1), opacity 150ms ease-out;overflow:hidden&quot;&gt;&lt;div class=&quot;px-6 pb-6 md:px-8 md:pb-8 rich-text&quot;&gt;&lt;p&gt;Yes. The reporter works with local and CI runs, as long as the Checkly credentials are available.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;rounded-2xl border border-blue-300/20 transition-[border-color] duration-200 ease-out hover:border-blue-300/35&quot;&gt;&lt;button type=&quot;button&quot; aria-expanded=&quot;false&quot; class=&quot;flex justify-between items-center px-6 py-5 md:px-8 w-full text-left text-checkly-deep-blue cursor-pointer transition-transform duration-150 motion-safe:active:scale-[0.995]&quot;&gt;&lt;span class=&quot;select-none text-base&quot;&gt;Does the reporter automatically turn tests into monitors?&lt;/span&gt;&lt;svg viewBox=&quot;0 0 14 8&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;w-3 shrink-0 transition-transform duration-[250ms] ease-out rotate-0&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M0.46967 0.46967C0.762563 0.176777 1.23744 0.176777 1.53033 0.46967L7 5.93934L12.4697 0.46967C12.7626 0.176777 13.2374 0.176777 13.5303 0.46967C13.8232 0.762563 13.8232 1.23744 13.5303 1.53033L7.53033 7.53033C7.23744 7.82322 6.76256 7.82322 6.46967 7.53033L0.46967 1.53033C0.176777 1.23744 0.176777 0.762563 0.46967 0.46967Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;div style=&quot;max-height:0px;opacity:0;transition:max-height 250ms cubic-bezier(0.23, 1, 0.32, 1), opacity 150ms ease-out;overflow:hidden&quot;&gt;&lt;div class=&quot;px-6 pb-6 md:px-8 md:pb-8 rich-text&quot;&gt;&lt;p&gt;No. The reporter uploads test runs as Checkly test sessions. Production monitoring is the next step in Checkly’s &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/quickstarts/playwright-check/&quot; rel=&quot;noreferrer&quot;&gt;Playwright monitoring workflow&lt;/a&gt;, where teams define Playwright Check Suites in a checkly.config.ts file and deploy them as monitors.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;]]&gt;</content:encoded></item><item><title><![CDATA[One CLI, Two Audiences: How We Built for Agents and Humans]]></title><description><![CDATA[50% of Checkly CLI users are already coding agents. Learn how built-in skills, structured output, and agent guardrails make one CLI work for humans and agents alike.]]></description><link>https://www.checklyhq.com/blog/agentic-cli</link><guid isPermaLink="false">acVVJRoAAE4Aur67</guid><category><![CDATA[AI]]></category><category><![CDATA[Product]]></category><dc:creator><![CDATA[Stefan Judis]]></dc:creator><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;Half of the Checkly CLI users are already coding agents. This is not a prediction — it&amp;#x27;s what the data shows today.&lt;/p&gt;&lt;p&gt;Since February, more and more agents have been using the CLI to manage and configure their Checkly monitoring setups. Right now, we&amp;#x27;re at 50% human and 50% agentic CLI users. And we predict that by the end of 2026, it won&amp;#x27;t be humans using the CLI; the agents will have taken over.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVVrpGXnQHGZAdk_agentic-cli-users.png?auto=format,compress&quot; alt=&quot;Graph showing that 50% CLI users are human and 50% agents.&quot;/&gt;&lt;/p&gt;&lt;p&gt;The terminal became the primary interface for AI agents doing real work in the Checkly ecosystem. Configuring monitoring, resolving incidents, and communicating outages; all this can be done automatically.&lt;/p&gt;&lt;p&gt;The CLI became &lt;a href=&quot;/blog/the-agentic-software-layer/&quot;&gt;the new agentic layer&lt;/a&gt;. So we asked: how do you build for two audiences at once?&lt;/p&gt;&lt;h2 id=&quot;the-full-agentic-loop-from-alert-to-resolution&quot;&gt;&lt;a href=&quot;#the-full-agentic-loop-from-alert-to-resolution&quot;&gt;The full agentic loop — from alert to resolution&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;To show what this looks like in practice, here&amp;#x27;s a real scenario: &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/detect/synthetic-monitoring/playwright-checks/overview/&quot; rel=&quot;noreferrer&quot;&gt;a Playwright check&lt;/a&gt; detects that the storefront&amp;#x27;s login flow is broken. The old way would be to manually open the Checkly dashboard, click through results, and switch between the IDE, alert information, and Git logs to figure out what&amp;#x27;s off. We now hand these tasks to the agent with a single prompt.&lt;/p&gt;&lt;blockquote class=&quot;bg-gray-100 p-4 border-l-2 my-4 border-blue-300 inline-block space-y-4&quot;&gt;&lt;p&gt;I just received a monitoring alert in Checkly about a broken login flow. Can you check what&amp;#x27;s up, investigate a fix, and communicate the issue?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;It&amp;#x27;s a simple but powerful prompt. Here&amp;#x27;s what happens next:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;The agent discovers Checkly capabilities.&lt;/strong&gt; With the installed &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/ai/skills/&quot; rel=&quot;noreferrer&quot;&gt;Checkly Skill&lt;/a&gt;, it pulls in the context it needs to act. Available commands, your account information and plan, investigation playbooks, and best practices; all these things become accessible through &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly skills.&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The agent investigates.&lt;/strong&gt; It calls &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly checks&lt;/code&gt; to get the current state of all monitors, identify the failing check, and analyze the Playwright error. It reads the check results, correlates them with your codebase, and additional context sources. Eventually, it finds the root cause.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The agent communicates.&lt;/strong&gt; Before fixing anything, it tries to open an incident so customers know what&amp;#x27;s happening, but the CLI rejects the command and prompts for confirmation. Agents can&amp;#x27;t just declare a public incident without approval. Once confirmed, the incident goes live: &amp;quot;Login flow is broken, users cannot log in.&amp;quot;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The agent provides a fix and deploys.&lt;/strong&gt; It applies the fix, commits, and pushes. Your existing CI/CD pipeline takes it from there — the agent waits for the deployment to complete.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The agent verifies.&lt;/strong&gt; Once deployed, it triggers the Checkly checks to confirm the fix actually works.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;The agent resolves.&lt;/strong&gt; If all the ad hoc tests pass, the incident is resolved with a summary of what happened and what was done. The status page goes green.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;This might sound like future music, but you can see this flow in action below.&lt;/p&gt;&lt;div data-oembed=&quot;https://www.youtube.com/watch?v=wkP21FuZx4c&quot; data-oembed-type=&quot;video&quot; data-oembed-provider=&quot;YouTube&quot;&gt;&lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/wkP21FuZx4c?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;Automate Your Monitoring and Incident Handling: How Agents Dominate the Checkly CLI&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Coding agents can handle the full incident life cycle today. Detect, understand, communicate, fix, verify, resolve; all this can happen in a single agent session. All actions are enabled through the CLI. There&amp;#x27;s no need for you to open a monitoring dashboard. There&amp;#x27;s no context switching. Sit back and let the agent be the incident manager.&lt;/p&gt;&lt;p&gt;But how does this work in detail? How did the agent know what to do?&lt;/p&gt;&lt;h2 id=&quot;checkly-skills-teach-your-agent-how-to-handle-your-monitoring&quot;&gt;&lt;a href=&quot;#checkly-skills-teach-your-agent-how-to-handle-your-monitoring&quot;&gt;Checkly Skills: teach your agent how to handle your monitoring&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Your agent didn&amp;#x27;t hallucinate, fetch docs, or browse the internet. It was tasked by &lt;a target=&quot;_blank&quot; href=&quot;https://checklyhq.com/docs/ai/skills/&quot; rel=&quot;noreferrer&quot;&gt;the Checkly skill&lt;/a&gt; to rely on the built-in documentation accessible via &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;You can install the Checkly skill with a single command:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;skills&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;This command drops a &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SKILL.md&lt;/code&gt; file into your project that any coding agent (Claude Code, Cursor, Codex, Copilot) can pick up. Everybody is raging about skills right now, but most skills have a fundamental flaw. &lt;strong&gt;Most skills are static&lt;/strong&gt;. If you look at all the skills listed on &lt;a target=&quot;_blank&quot; href=&quot;https://skills.sh/&quot; rel=&quot;noreferrer&quot;&gt;skills.sh&lt;/a&gt;, you&amp;#x27;ll find that the majority of them are on-off documentation that you need to update manually.&lt;/p&gt;&lt;p&gt;The Checkly skill file is different because it&amp;#x27;s only a thin wrapper around the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly skills&lt;/code&gt; command.&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Run `npx checkly skills communicate` for the full protocol details.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### `npx checkly skills initialize`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Learn how to initialize and set up a new Checkly CLI project from scratch.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### `npx checkly skills configure`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Learn how to create and manage monitoring checks using Checkly constructs and the CLI.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;#### `npx checkly skills configure api-checks`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Api Check construct (`ApiCheck`), assertions, and authentication setup scripts&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Yes, you read that right, &lt;strong&gt;we&amp;#x27;ve put optimized agent documentation right into the CLI itself.&lt;/strong&gt; Required monitoring context ships within the tooling you use to manage your monitoring. Every CLI version update brings updated documentation, new workflows, and current best practices. There&amp;#x27;s no web search, no stale docs, no external files to maintain. Whenever you update the CLI, your agent gets smarter.&lt;/p&gt;&lt;p&gt;But we didn&amp;#x27;t stop there. Skills also use progressive disclosure across three levels:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Overview&lt;/strong&gt; — &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills&lt;/code&gt; lists all available action categories: &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;initialize&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;configure&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;investigate&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;communicate&lt;/code&gt; and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;manage&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Action&lt;/strong&gt; — &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills investigate&lt;/code&gt; returns the detailed guide for that category — which commands to run, what to look for, and how to triage.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Reference&lt;/strong&gt; — &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills configure api-checks&lt;/code&gt; returns construct-level documentation for any resource.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The built-in Checkly skills save tokens and tell your agent exactly what to do. No guessing. No hallucinations.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVZ7ZGXnQHGZAmt_agentic-learn1.gif?auto=format,compress&quot; alt=&quot;Agent session showing the discovery of the skills command.&quot;/&gt;&lt;/p&gt;&lt;p&gt;This single command transforms your agent into an up-to-date Checkly expert. But what can your agent handle for you now that it knows every corner of the Checkly ecosystem?&lt;/p&gt;&lt;h2 id=&quot;structured-output-the-agent-s-dashboard&quot;&gt;&lt;a href=&quot;#structured-output-the-agent-s-dashboard&quot;&gt;Structured output: the agent&amp;#x27;s dashboard&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you&amp;#x27;re facing issues and alerts, as a human, you head into Checkly, open the dashboard, click through the check results, and scan the graphs. And while you could task your agent to open the web app with a browser, this process couldn&amp;#x27;t be more inefficient. We released new CLI commands to enable the agent to access structured output, replacing the good old Checkly dashboard you know and love.&lt;/p&gt;&lt;p&gt;Read commands support multiple output formats optimized for agentic workflows:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--output&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;12345&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--output&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;stats&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--output&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;table&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;It&amp;#x27;s the same data you&amp;#x27;ll find in your Checkly web app, but rendered in text. Agents get parseable data they can reason about.&lt;/p&gt;&lt;p&gt;The new read commands cover the full monitoring setup:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checks list&lt;/code&gt; : All checks with current status. Filter by name (&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--search&lt;/code&gt;), tag (&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--tag&lt;/code&gt;), or check type (&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--type&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checks get &amp;lt;id&amp;gt;&lt;/code&gt; : Configuration, recent results, error groups, and analytics for a single check. Customize with &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--stats-range&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--group-by&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--metrics&lt;/code&gt;, and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--filter-status&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checks stats&lt;/code&gt; : Availability, response times, and key metrics across multiple checks at once.&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# Stats for all production API checks over the last 7 days&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;stats&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--range=last7Days&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--tag=production&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--type=API&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVbBpGXnQHGZAn0_checks-list.gif?auto=format,compress&quot; alt=&quot;Different output options of the checks list command.&quot;/&gt;&lt;/p&gt;&lt;p&gt;By exposing the monitoring data via the CLI, your agent now understands what an alert means and how to investigate. With access to your codebase, it can get to work and provide a fix.&lt;/p&gt;&lt;h2 id=&quot;incident-lifecycle-through-the-cli&quot;&gt;&lt;a href=&quot;#incident-lifecycle-through-the-cli&quot;&gt;Incident lifecycle through the CLI&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Once the agent (and you) decide that you&amp;#x27;re facing a real issue, it&amp;#x27;s time to communicate it. The CLI covers the full incident lifecycle on your status pages:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;status-pages&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# discover your status pages&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;status-pages&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# inspect a specific page and its services&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;incidents&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;           &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# open a new incident&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;incidents&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# post a progress update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;incidents&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;     &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# close the incident&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The same communication loop a human on-call would run: detect, communicate, resolve. But this time, you&amp;#x27;ll be faster, don&amp;#x27;t have to leave your terminal, and can supervise your agent to do the dirty work.&lt;/p&gt;&lt;p&gt;But isn&amp;#x27;t it dangerous to let your agent handle incidents? We thought so, too!&lt;/p&gt;&lt;h2 id=&quot;guardrails-safe-autonomy&quot;&gt;&lt;a href=&quot;#guardrails-safe-autonomy&quot;&gt;Guardrails: safe autonomy&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Providing agents read-only commands was an easy decision, but what if wrong reasoning could have real consequences? What if the agent accidentally opens an incident, updates your monitors without you reviewing, or destroys your entire Checkly project, thinking it&amp;#x27;s &amp;quot;absolutely right&amp;quot;?&lt;/p&gt;&lt;p&gt;These actions and commands are deep in the danger zone, and you definitely don&amp;#x27;t want to wake up your teammates because your agent misconfigured something while you were vibing the time of your life.&lt;/p&gt;&lt;p&gt;We thought about how to handle these situations and decided to implement agent guardrails. If your agent decides to declare a public incident or deploy your monitoring, they need to ask you for confirmation first.&lt;/p&gt;&lt;p&gt;Critical commands implement an agent confirmation protocol. The CLI detects agent usage by checking for environment variables that coding agents set automatically (like &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;CLAUDE_CODE&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;CURSOR_SESSION&lt;/code&gt;, or &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;CODEX&lt;/code&gt;). If we detect that an agent is running a critical command, the CLI returns an exit code &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;2&lt;/code&gt; with a JSON envelope:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;confirmation_required&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;quot;command&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;incidents create&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;quot;changes&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;Will create incident \\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;Login flow broken\\&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot; on status page \\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;Acme Store\\&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;Severity: major&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  ]&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;quot;confirmCommand&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;checkly incidents create --title=\\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;Login flow broken\\&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot; ... --force&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;This forces the agent to present the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;changes&lt;/code&gt; to the user, wait for approval, and only then run the provided &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;confirmCommand&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVcV5GXnQHGZApF_incident.gif?auto=format,compress&quot; alt=&quot;Guardrails in the Checkly incident command.&quot;/&gt;&lt;/p&gt;&lt;p&gt;And what if the agent gets it wrong? What if it misdiagnoses the root cause or opens an incident for a false positive? That&amp;#x27;s exactly why the confirmation protocol exists. &lt;strong&gt;The agent proposes, you approve.&lt;/strong&gt; A misdiagnosis becomes a learning moment, not an incident. The human stays in the loop for every action that has real-world consequences.&lt;/p&gt;&lt;h2 id=&quot;clis-are-the-new-agent-interface&quot;&gt;&lt;a href=&quot;#clis-are-the-new-agent-interface&quot;&gt;CLIs are the new agent interface&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;CLIs were built for humans first. But with a few design patterns, they become agent-ready. Here&amp;#x27;s what we learned building for both audiences:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Built-in documentation.&lt;/strong&gt; Don&amp;#x27;t make agents search the web or rely on external docs. Ship agent-optimized documentation inside the CLI itself. When the tooling updates, the docs update as well. Minimize stale knowledge and hallucinations.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Structured output.&lt;/strong&gt; Every read command should support machine-readable formats (&lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--output json&lt;/code&gt;, &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--output md&lt;/code&gt;). Agents don’t care about colorful output, and humans shouldn&amp;#x27;t have to read raw JSON. Support both worlds.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Human/agent detection.&lt;/strong&gt; Some CLI flows need to behave differently depending on who&amp;#x27;s running them. Detect the caller through environment variables and adapt — interactive prompts for humans, structured JSON responses, and additional command information for agents.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Agent guardrails.&lt;/strong&gt; Critical commands need a confirmation protocol. Enforce human approval. Autonomy without oversight is just a liability.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;These patterns aren&amp;#x27;t Checkly-specific. They&amp;#x27;re how every CLI should think about agent users. One CLI, two audiences — and the design choices made for agents make things better for everyone.&lt;/p&gt;&lt;p&gt;Half of our CLI users are already agents. Keep them coming!&lt;/p&gt;&lt;h2 id=&quot;get-started&quot;&gt;&lt;a href=&quot;#get-started&quot;&gt;Get started&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Upgrade to the latest Checkly CLI:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npm &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly@latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;Install the Checkly skill:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;skills&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;Or, if you don’t have Checkly set up yet. Tell your agent the following:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Run &amp;#39;npx checkly skills initialize&amp;#39; and follow the instructions.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-16 w-16&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;It will figure out the rest.&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Checkly and the Agentic Software Layer]]></title><description><![CDATA[CLIs are the new agent interface. Discover how Checkly turned its CLI into an agentic layer with built-in skills, structured output, and confirmation protocols for safe autonomous monitoring.]]></description><link>https://www.checklyhq.com/blog/the-agentic-software-layer</link><guid isPermaLink="false">acVVMhoAAEsAur7R</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[Hannes Lenke]]></dc:creator><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;November 24th, the &lt;a target=&quot;_blank&quot; href=&quot;https://www.anthropic.com/news/claude-opus-4-5&quot; rel=&quot;noreferrer&quot;&gt;Opus 4.5 release&lt;/a&gt; turned around the entire tech industry. This was the moment when agents became capable. Capable enough to write solid staff-level code. Capable enough to reason about alerts, investigate root causes much faster than most engineers, and set up the reliability layer faster.&lt;/p&gt;&lt;p&gt;For me, this feels like an iPhone moment on steroids; the adoption of AI is accelerating much faster than any adoption curve I’ve seen over the past few decades. This rapid growth is fueled by early adopters who experienced their eureka moments early on, followed by many startup CEOs who have been actively developing prompting software during the holidays, making significant progress 10x quicker than ever before.&lt;/p&gt;&lt;p&gt;Now, AI is a topic in every customer conversation. While it took years to adopt DevOps, AI is on track to outpace that by a wide margin; in fact, it is already surpassing it.&lt;/p&gt;&lt;p&gt;The rise of AI agents introduced a new user of developer tools, one that doesn&amp;#x27;t click buttons, doesn&amp;#x27;t read dashboards, and doesn&amp;#x27;t care about your beautifully designed settings page. Agents live in the terminal. They reason over text. Over the last few years, we introduced &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/learn/monitoring/monitoring-as-code/&quot; rel=&quot;noreferrer&quot;&gt;Monitoring as Code (MaC)&lt;/a&gt;, a workflow that enables developers to own reliability; in text. Accidentally, MaC is exactly what agents need.&lt;/p&gt;&lt;p&gt;You can see where we are going here. The work we did to make Checkly great for developers turns out to be the groundwork for making Checkly great for agents.&lt;/p&gt;&lt;p&gt;But &amp;quot;accidentally ready&amp;quot; isn’t a strategy - it was an opportunity.&lt;/p&gt;&lt;h2 id=&quot;three-layers-of-software-interfaces&quot;&gt;&lt;a href=&quot;#three-layers-of-software-interfaces&quot;&gt;Three Layers of Software Interfaces&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Every software platform serves its users through interfaces. Historically, there have been two, sometimes three:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;UIs&lt;/strong&gt; are built for humans. They&amp;#x27;re visual, interactive, optimized for comprehension and exploration. Dashboards, forms, drag-and-drop builders. These are how people interact with software.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;APIs&lt;/strong&gt; are built for machines. They&amp;#x27;re structured, predictable, and designed for integration between systems. CI/CD pipelines, webhooks, Terraform providers. This is how humans have automated software.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;CLIs&lt;/strong&gt; are built to enable engineers to scale and automate their interactions with APIs. Especially, but not only for developer tools.&lt;/p&gt;&lt;p&gt;Turns out &lt;strong&gt;CLIs are great interfaces and became the agentic layer,&lt;/strong&gt; and this is new. AI agents don&amp;#x27;t need pixel-perfect UIs or REST endpoints designed for static integrations. They need CLIs that output structured data in Markdown or JSON. They need progressive self-discovery, a way to explore capabilities without reading documentation. They need confirmation protocols for dangerous actions.&lt;/p&gt;&lt;p&gt;Most monitoring platforms were built for layer one. Some invested in layers two and three. Checkly is the first to double down on a new and redefined third layer. An application layer optimized for agents and for the modern software factory.&lt;/p&gt;&lt;h2 id=&quot;why-code-&amp;amp;-cli-first-platforms-win&quot;&gt;&lt;a href=&quot;#why-code-&amp;amp;-cli-first-platforms-win&quot;&gt;Why Code &amp;amp; CLI-First Platforms Win&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Here&amp;#x27;s the thing about Monitoring as Code: it was already agent-friendly before agents existed.&lt;/p&gt;&lt;p&gt;When your monitoring lives in &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;.ts&lt;/code&gt; files alongside your application code, an AI agent can read it, reason about it, generate new tests and checks, and deploy them the same way it works with any other code in your repository. There&amp;#x27;s no proprietary DSL to learn, no UI to scrape, no brittle browser automation required.&lt;/p&gt;&lt;p&gt;An agent working with the Checkly CLI can open your &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;__checks__&lt;/code&gt; directory, understand what&amp;#x27;s being monitored, identify gaps, write new checks using standard Playwright syntax, run &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly test&lt;/code&gt; to validate against our global infrastructure, and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly deploy&lt;/code&gt; to ship the entire monitoring setup. Every step happens in the terminal, in code, using tools the agent already knows.&lt;/p&gt;&lt;p&gt;Legacy monitoring platforms trapped behind proprietary UIs and frameworks can&amp;#x27;t offer this. They&amp;#x27;ll bolt on a chatbot and call it AI. That&amp;#x27;s &lt;strong&gt;not&lt;/strong&gt; the agentic layer: that&amp;#x27;s an AI-colored coat of paint.&lt;/p&gt;&lt;h2 id=&quot;making-the-implicit-explicit&quot;&gt;&lt;a href=&quot;#making-the-implicit-explicit&quot;&gt;Making the Implicit Explicit&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Being code &amp;amp; CLI-first gave Checkly the agentic head start. But a head start doesn’t finish the race. We&amp;#x27;ve shipped a new set of capabilities designed for the speed of this new world and purpose-built for agents.&lt;/p&gt;&lt;h3 id=&quot;teaching-your-agent-testing-and-monitoring&quot;&gt;&lt;a href=&quot;#teaching-your-agent-testing-and-monitoring&quot;&gt;Teaching your Agent Testing and Monitoring&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Your agent understands how to configure Checkly today, because it can read the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;checkly.config&lt;/code&gt; and &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;check.ts&lt;/code&gt; files. It also includes Checkly code in its training data, and if nothing else works, it can still fetch the docs to troubleshoot. But we thought, what if we could make it even easier?&lt;/p&gt;&lt;p&gt;Agent Skills are an open standard supported by Claude Code, Cursor, OpenAI Codex, and GitHub Copilot. Skills are providing agents with specialized knowledge on demand. &lt;strong&gt;Most skills out there are static files, though.&lt;/strong&gt; We thought we could do better than providing some Markdown files!&lt;/p&gt;&lt;p&gt;Install the Checkly skill and see the magic happen:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;skills&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;The Checkly &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;SKILL.md&lt;/code&gt; file is your agents entry point to learn how to set up, configure and handle Checkly testing and monitoring. However, the static file doesn&amp;#x27;t include all the Checkly information. The Checkly skill is only a thin wrapper around the new &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills&lt;/code&gt; command. The new command that teaches your agent where to find construct documentation, other CLI commands, and monitoring workflows right in the CLI itself using &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills&lt;/code&gt;.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVhqJGXnQHGZAvZ_agentic-learn-ezgif.com-video-to-gif-converter.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;Once your agent discovers the &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;npx checkly skills&lt;/code&gt; it can access agent-optimized docs to initialize, configure and manage the entire testing and monitoring setup. There&amp;#x27;s no relying on training data, no docs browsing, no context window compacting. Agents access the right docs when they need them.&lt;/p&gt;&lt;p&gt;But what does this mean in practice?&lt;/p&gt;&lt;h3 id=&quot;creating-your-monitoring-checks&quot;&gt;&lt;a href=&quot;#creating-your-monitoring-checks&quot;&gt;Creating your Monitoring Checks&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The big difference between the agentic CLI layer and built-in product AI is that agents already understand and manage your codebase. They read and write files all day. With the right tools, coding agents have all the context they need to automatically set up and test your monitoring.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVhqZGXnQHGZAva_agentic-product-create-ezgif.com-video-to-gif-converter.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;Your API endpoints, your login flows, your business logic; agents know about all of it. Task them to set up the monitoring and see your agent doing the work! In the previous world, you didn&amp;#x27;t have the time and energy to manage monitors for every page, endpoint, or application flow; now you do because your agent never gets tired.&lt;/p&gt;&lt;p&gt;Now, your agent can create, test, and deploy your entire monitoring!&lt;/p&gt;&lt;p&gt;More monitors also mean more alerts. Could your agent handle these, too?&lt;/p&gt;&lt;h3 id=&quot;investigating-failures-and-monitoring-results&quot;&gt;&lt;a href=&quot;#investigating-failures-and-monitoring-results&quot;&gt;Investigating Failures and Monitoring Results&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;If you received a monitoring alert in the old world, you usually log in to Checkly to understand what check failed and what triggered the alert. And while your agent could log in via a browser, it shouldn&amp;#x27;t need to do that to understand your monitoring setup.&lt;/p&gt;&lt;p&gt;A new set of read commands lets agents query and analyze your monitoring setup directly from the terminal:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# List all production API checks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--tag=production&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--type=API&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--output=json&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# Get 7-day stats for a check, grouped by location&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;12345&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--stats-range=last7Days&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--group-by=location&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-comment)&quot;&gt;# Analytics across all checks tagged &amp;quot;critical&amp;quot; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checks&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;stats&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--tag=critical&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--range=last7Days&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;Every command supports &lt;code class=&quot;bg-blue-300/15 py-0.5 px-1.5 text-base rounded break-words&quot;&gt;--output table|json|md&lt;/code&gt; — table for humans, JSON and Markdown for programmatic agent consumption. Metric defaults adapt to check type: response time percentiles for API checks, Web Vitals for browser checks, latency and packet loss for ICMP.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVX35GXnQHGZAjY_listimage.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;With these new commands, your agent can access all the monitoring information you usually look at in the Checkly dashboard. Pair this ability with code access and let your agent figure out the issue.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVhp5GXnQHGZAvY_agent-alert-ezgif.com-video-to-gif-converter.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;Detecting issues is only one part of the story. Could your agent communicate issues, too?&lt;/p&gt;&lt;h3 id=&quot;acting-on-incidents&quot;&gt;&lt;a href=&quot;#acting-on-incidents&quot;&gt;Acting On Incidents&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Agents can manage the full incident lifecycle on your status pages.&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;incidents&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--status-page-id&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--title=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;API degradation&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--severity=minor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;incidents&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;--message=&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;Root cause identified&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;incidents&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;Write commands implement a confirmation protocol designed for agent safety. When an agent runs a destructive or public-facing command, the CLI returns a JSON envelope describing the changes and provides a confirmation command.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acViRpGXnQHGZAwe_agent-incident-ezgif.com-video-to-gif-converter.gif?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;This enforced confirmation is critical. Agents that can take action without guardrails are a liability. Agents with structured confirmation flows are a force multiplier.&lt;/p&gt;&lt;p&gt;If you put all these features together, your agent can handle your entire incident management while you drink your coffee. Don&amp;#x27;t believe me? &lt;a target=&quot;_blank&quot; href=&quot;https://www.youtube.com/watch?v=wkP21FuZx4c&quot; rel=&quot;noreferrer&quot;&gt;Here&amp;#x27;s a video showing it entirely&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;the-agentic-layer-is-here&quot;&gt;&lt;a href=&quot;#the-agentic-layer-is-here&quot;&gt;The Agentic Layer is Here&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The shift to AI agents isn&amp;#x27;t coming. It&amp;#x27;s happening now. 50% percent of our active CLI users are already agents.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/acVVrpGXnQHGZAdk_agentic-cli-users.png?auto=format,compress&quot; alt=&quot;Graph showing that 50% CLI users are human and 50% agents.&quot;/&gt;&lt;/p&gt;&lt;p&gt;Development teams are using Claude Code, Cursor, and Copilot to write, test, and ship code. The tools in their stack that can&amp;#x27;t participate in that workflow will be replaced by tools that can.&lt;/p&gt;&lt;p&gt;Checkly is built for this moment. Upgrade your CLI, install the skill, and point your agent at your monitoring.&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npm &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly@latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;npx &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;checkly&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;skills&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;… or, if you don’t have Checkly set up yet. Tell your agent the following:&lt;/p&gt;&lt;div class=&quot;code-block code-block-inline syntax-bash&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;Run &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;npx checkly skills initialize&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;follow&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;the&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string)&quot;&gt;instructions.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-14 w-14&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-white/30 group-hover:text-white/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;p&gt;… and it will figure out the rest.&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[12,479 Applications, Zero Ghosting: A Look at Checkly's 2025 Hiring]]></title><description><![CDATA[In 2025, Checkly received 12,479 applications, of which we hired 24 people. Here's an honest look at our hiring funnel, speed, and data.]]></description><link>https://www.checklyhq.com/blog/checkly-2025-hiring-data</link><guid isPermaLink="false">abu-ihoAAEQAeYeX</guid><category><![CDATA[hiring]]></category><category><![CDATA[People]]></category><dc:creator><![CDATA[Lauren Singh]]></dc:creator><pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;Hiring is one of the most human things a company does, and one of the least transparent. We want to change that. Here&amp;#x27;s an honest look at what our hiring actually looked like in 2025: the volume, the speed, and the funnel.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;12 job postings. 24 people joined the team. 100% of applicants received a response.&lt;/strong&gt;&lt;/p&gt;&lt;h2 id=&quot;12-479-applications-12-job-postings-a-lot-of-trust-placed-in-us-&quot;&gt;&lt;a href=&quot;#12-479-applications-12-job-postings-a-lot-of-trust-placed-in-us-&quot;&gt;12,479 applications. 12 job postings. A lot of trust placed in us.&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In 2025, we received 12,479 applications across 12 job postings, an average of 1,040 applicants per posting. It&amp;#x27;s worth noting that some postings covered roles we hired for multiple times: for example, we brought on three Enterprise Account Executives from a single posting. Engineering, product, and design postings attracted the most interest, averaging around 1,105 applicants each, while go-to-market postings averaged 909.&lt;/p&gt;&lt;p&gt;Our most competitive posting was Senior Backend Engineer, with a total of 4,578 applicants.&lt;/p&gt;&lt;h2 id=&quot;roughly-1-in-58-applicants-progressed-to-interviews&quot;&gt;&lt;a href=&quot;#roughly-1-in-58-applicants-progressed-to-interviews&quot;&gt;Roughly 1 in 58 applicants progressed to interviews&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;We try to be thoughtful about who we move forward, and honest about the odds. Of 12,479 applicants, 217 progressed to the Hiring Manager interview stage, that&amp;#x27;s approximately 1.7%, or roughly 1 in 58. That&amp;#x27;s a tight funnel, and we don&amp;#x27;t shy away from saying so. What we will say is this: every single person who applied heard back from us. No ghosting, no black hole. We know that&amp;#x27;s not the norm, and we think it should be. Job searching is hard enough without silence on the other end. What made the difference for those who progressed? A genuine fit with the role, relevant experience for a developer tools company, and clear, async-friendly communication. We&amp;#x27;re a remote-first team, how someone writes and communicates matters.&lt;/p&gt;&lt;h2 id=&quot;where-our-hires-came-from&quot;&gt;&lt;a href=&quot;#where-our-hires-came-from&quot;&gt;Where our hires came from&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Not every hire looks the same, and neither does every pipeline. Here&amp;#x27;s how our 24 hires broke down by source:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Actively applied: 60%&lt;/li&gt;&lt;li&gt;Referrals from the team: 20%&lt;/li&gt;&lt;li&gt;Sourced by a recruiter: 20%&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The majority of our hires came through inbound applications, which means a well-written application genuinely matters. That said, referrals and sourcing play a real role too, and we&amp;#x27;re proud that team referrals account for a meaningful share of who joins us.&lt;/p&gt;&lt;h2 id=&quot;what-candidates-said-about-the-experience&quot;&gt;&lt;a href=&quot;#what-candidates-said-about-the-experience&quot;&gt;What candidates said about the experience&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;We ask every candidate who goes through our process to share feedback. In 2025, when asked how likely they were to recommend Checkly as an employer, the average score was &lt;strong&gt;4.25 out of 5&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Here&amp;#x27;s what a couple of candidates had to say:&lt;/p&gt;&lt;p&gt;&lt;em&gt;&amp;quot;The experience was overwhelmingly positive as I enjoyed speaking with all the stakeholders. Checkly is a place of high integrity that operates with the utmost professionalism.&amp;quot;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&amp;quot;I am glad that even though I was not selected to continue the process, I got interviewed anyway. This is a good approach from the company and I hope you continue like that. The application form was unique and my time was respected. Thank you.&amp;quot;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;We don&amp;#x27;t share this to pat ourselves on the back, we share it because we think transparency should run both ways. Candidates trust us with their time, and we want to be accountable to that.&lt;/p&gt;&lt;h2 id=&quot;from-application-to-offer-22-5-days-(median)&quot;&gt;&lt;a href=&quot;#from-application-to-offer-22-5-days-(median)&quot;&gt;From application to offer: 22.5 days (median)&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;We know job searching is stressful, so we try to move quickly. Our median time from application to offer was 22.5 days, and our fastest? Just 4 days. Here&amp;#x27;s how the stages broke down:&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/abvB27bci2UF6QZp_checkly-hiring-stages.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;The challenge stage, which applied to Engineering, Design, Support, and Customer Solutions roles only, naturally adds time, but it&amp;#x27;s an important part of how we assess real-world problem solving. Candidates are given up to 10 days to complete it, and we aim to make it focused and respectful of their time. If you&amp;#x27;re applying for a Product or GTM role, your process will typically be faster as there&amp;#x27;s no take-home challenge involved.&lt;/p&gt;&lt;h2 id=&quot;83%-offer-acceptance-rate&quot;&gt;&lt;a href=&quot;#83%-offer-acceptance-rate&quot;&gt;83% offer acceptance rate&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In 2025, 24 offers were accepted, an 83% offer acceptance rate. We take this as a signal that the process works. By the time we get to an offer, both sides have had enough real conversation to feel confident. We hope that continues to be true.&lt;/p&gt;&lt;h2 id=&quot;what-s-next&quot;&gt;&lt;a href=&quot;#what-s-next&quot;&gt;What&amp;#x27;s next&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sharing this data publicly is something we&amp;#x27;ll keep doing. Hiring is a two-way street, candidates invest real time and energy in applying, and the least we can do is be honest about what that process looks like from our side.&lt;/p&gt;&lt;p&gt;Looking ahead, 2026 is shaping up to be a big year for our go-to-market team. If you&amp;#x27;re in sales, solutions engineering or customer success and you&amp;#x27;re excited about the developer tools space, check out our &lt;a target=&quot;_blank&quot; href=&quot;https://jobs.ashbyhq.com/checkly?utm_source=cb&quot; rel=&quot;noreferrer&quot;&gt;open roles&lt;/a&gt; or join our &lt;a target=&quot;_blank&quot; href=&quot;https://jobs.ashbyhq.com/checkly/21acd589-f6eb-42cd-8c75-3eac4e3fb1e7?utm_source=cb&quot; rel=&quot;noreferrer&quot;&gt;talent community&lt;/a&gt;, we&amp;#x27;d love to hear from you. And if you&amp;#x27;ve been through our process, whether you joined us or not, we&amp;#x27;re always open to feedback. Hiring should feel human on both sides, and we&amp;#x27;re committed to keeping it that way.&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Expanding Uptime Monitoring Down The Stack: ICMP Monitors Are Now Available In Checkly]]></title><description><![CDATA[Checkly's ICMP monitors ping any host or IP to measure reachability, latency, and packet loss, available on all plans and fully integrated with Monitoring as Code.]]></description><link>https://www.checklyhq.com/blog/icmp-monitoring</link><guid isPermaLink="false">aa_L7BoAAEUAwakg</guid><category><![CDATA[Product]]></category><category><![CDATA[Uptime Monitoring]]></category><category><![CDATA[Announcements]]></category><dc:creator><![CDATA[Susa Tünker,Pırıl Kavlak]]></dc:creator><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;When we started building Checkly&amp;#x27;s uptime monitoring suite, the goal was to give engineering teams complete visibility across every layer of their stack, from application down to network, in one place. URL, TCP, DNS, and Heartbeat monitors covered a lot of that ground. But one fundamental piece was missing: the ability to simply ping a host and know if it&amp;#x27;s reachable.&lt;/p&gt;&lt;p&gt;We&amp;#x27;re now closing that gap by adding ICMP monitors to &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/product/uptime-monitoring/&quot; rel=&quot;noreferrer&quot;&gt;Checkly&amp;#x27;s uptime monitoring suite&lt;/a&gt;, available on all plans today, alongside URL, TCP, DNS, and Heartbeat.&lt;/p&gt;&lt;div data-oembed=&quot;https://www.youtube.com/watch?v=MKZm3iH9E4g&quot; data-oembed-type=&quot;video&quot; data-oembed-provider=&quot;YouTube&quot;&gt;&lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/MKZm3iH9E4g?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;ICMP Monitors Are Now Available in Checkly&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;what-is-icmp-monitoring-&quot;&gt;&lt;a href=&quot;#what-is-icmp-monitoring-&quot;&gt;What is ICMP monitoring?&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;ICMP monitors send scheduled ping requests to any host or IP address to measure reachability, latency, and packet loss. You can set assertions on any of these to define exactly what &amp;quot;healthy&amp;quot; means for each host.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/abAHZVxvIZEnjhq0_creationscreenw%3Aoheader.png?auto=format%2Ccompress&amp;amp;rect=7%2C0%2C2380%2C1278&amp;amp;w=2380&amp;amp;h=1278&quot; alt=&quot;ICMP monitor creating screen&quot;/&gt;&lt;/p&gt;&lt;p&gt;No application logic. No open ports required. ICMP is a low-level monitor that provides a direct network-level signal, independent of what is running on the machine.&lt;/p&gt;&lt;h2 id=&quot;what-you-can-monitor-with-icmp-requests&quot;&gt;&lt;a href=&quot;#what-you-can-monitor-with-icmp-requests&quot;&gt;What you can monitor with ICMP requests&lt;/a&gt;&lt;/h2&gt;&lt;h3 id=&quot;infrastructure-without-an-http-endpoint&quot;&gt;&lt;a href=&quot;#infrastructure-without-an-http-endpoint&quot;&gt;&lt;strong&gt;Infrastructure without an HTTP endpoint&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Databases, message queues, internal services, bare-metal servers, routers, and network devices don&amp;#x27;t serve web traffic, but they still need monitoring. TCP monitors cover many of these cases, but ICMP goes one level lower: no open port required. For hosts where no ports are intentionally exposed, ICMP is the right layer to monitor at. If a host can be pinged, it can be monitored in Checkly without adding extra tools to your stack.&lt;/p&gt;&lt;h3 id=&quot;private-networks-and-internal-hosts&quot;&gt;&lt;a href=&quot;#private-networks-and-internal-hosts&quot;&gt;&lt;strong&gt;Private networks and internal hosts&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;ICMP monitors are useful for hosts that aren&amp;#x27;t exposed to the public internet, making them valuable for teams monitoring internal infrastructure alongside their public-facing checks. &lt;em&gt;This is possible via Checkly Private Locations, with ICMP support coming soon.&lt;/em&gt;&lt;/p&gt;&lt;h3 id=&quot;incident-triage&quot;&gt;&lt;a href=&quot;#incident-triage&quot;&gt;&lt;strong&gt;Incident triage&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;When an alert fires, the first question is always: Is the machine down, or is the service down? ICMP gives you that answer immediately. If ICMP fails, it&amp;#x27;s a network issue. If ICMP passes and your HTTP check fails, the server is up, but the service is broken. The right team gets paged with the right context from the start.&lt;/p&gt;&lt;h3 id=&quot;regional-latency-comparison&quot;&gt;&lt;a href=&quot;#regional-latency-comparison&quot;&gt;&lt;strong&gt;Regional latency comparison&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Run ICMP monitors from multiple locations to compare latency across regions. If one region is consistently slower than others, you can catch geographic performance issues before they affect users in that area.&lt;/p&gt;&lt;p&gt;Some failures don&amp;#x27;t show up as outages. Intermittent packet loss is one of them. One of our beta users ran into exactly this:&lt;/p&gt;&lt;blockquote class=&quot;bg-gray-100 p-4 border-l-2 my-4 border-blue-300 inline-block space-y-4&quot;&gt;&lt;p&gt;&amp;quot;We had a serious issue in which every third packet was dropped, and it went completely undetected until Checkly caught it at the network level. That&amp;#x27;s the kind of signal that stops a problem before it becomes a customer-facing incident.&amp;quot;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;You can set separate degraded and failure thresholds on packet loss, and add latency assertions to define when to trigger an alert.&lt;/p&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/abAJz1xvIZEnjhru_Healthywithpreviouspacketlossissue-white.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;shipping-with-full-support-for-monitoring-as-code&quot;&gt;&lt;a href=&quot;#shipping-with-full-support-for-monitoring-as-code&quot;&gt;Shipping with full support for Monitoring as Code&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;ICMP monitors are fully integrated into Checkly&amp;#x27;s Monitoring as Code workflows, available in the CLI from &lt;strong&gt;v7.1.0&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Define your ICMP monitors in code alongside your Playwright and API checks, version them in Git, and deploy through CI/CD:&lt;/p&gt;&lt;div class=&quot;code-block theme-light&quot;&gt;&lt;div class=&quot;overflow-auto w-full flex pr-12&quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; { Frequency&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; IcmpAssertionBuilder&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; IcmpMonitor } &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;quot;checkly/constructs&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;IcmpMonitor&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;cloudflare-dns-icmp&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;Cloudflare DNS ICMP Monitor&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  activated&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  frequency&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;Frequency&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;EVERY_1M&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  maxPacketLossThreshold&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  degradedPacketLossThreshold&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  request&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    hostname&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;1.1.1.1&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    pingCount&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    assertions&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-keyword)&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;IcmpAssertionBuilder&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.latency&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;avg&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.lessThan&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;IcmpAssertionBuilder&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.latency&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-string-expression)&quot;&gt;&amp;#39;max&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-function)&quot;&gt;.lessThan&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-constant)&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: var(--shiki-token-punctuation)&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: var(--shiki-color-text)&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;button type=&quot;button&quot; class=&quot;group bg-inherit absolute rounded flex items-center justify-center top-0 right-0  text-white bg-inherit h-16 w-16&quot; title=&quot;Copy code to clipboard&quot;&gt;&lt;svg viewBox=&quot;0 0 16 11&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out text-checkly-blue -translate-y-2 opacity-0 scale-90&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M15.1085 0.558056C15.3526 0.802133 15.3526 1.19786 15.1085 1.44194L5.94187 10.6086C5.82466 10.7259 5.66568 10.7917 5.49992 10.7917C5.33416 10.7917 5.17519 10.7259 5.05798 10.6086L0.891309 6.44194C0.647232 6.19786 0.647233 5.80213 0.891312 5.55806C1.13539 5.31398 1.53112 5.31398 1.7752 5.55806L5.49992 9.28281L14.2246 0.55806C14.4687 0.313981 14.8644 0.31398 15.1085 0.558056Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg viewBox=&quot;0 0 18 19&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;absolute h-5 w-5 transition duration-200 ease-out translate-y-0 opacity-100 scale-100 text-gray-500/50 group-hover:text-gray-500/80&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M5.875 8.85929C5.875 7.59364 6.90101 6.56763 8.16667 6.56763H15.6667C16.9323 6.56763 17.9583 7.59365 17.9583 8.85929V16.3593C17.9583 17.6249 16.9323 18.651 15.6667 18.651H8.16667C6.901 18.651 5.875 17.6249 5.875 16.3593V8.85929ZM8.16667 7.81763C7.59137 7.81763 7.125 8.28399 7.125 8.85929V16.3593C7.125 16.9346 7.59138 17.401 8.16667 17.401H15.6667C16.2419 17.401 16.7083 16.9346 16.7083 16.3593V8.85929C16.7083 8.28398 16.2419 7.81763 15.6667 7.81763H8.16667Z&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M2.33464 1.98438C2.05836 1.98438 1.79341 2.09412 1.59807 2.28946C1.59807 2.28946 1.59807 2.28946 1.59807 2.28946M1.59807 2.28946C1.40272 2.48482 1.29297 2.74978 1.29297 3.02604V10.5261C1.29297 10.8023 1.4027 11.0672 1.59809 11.2626C1.79343 11.458 2.05838 11.5678 2.33464 11.5678H3.16797C3.51315 11.5678 3.79297 11.8476 3.79297 12.1928C3.79297 12.5379 3.51315 12.8178 3.16797 12.8178H2.33464C1.72684 12.8178 1.14393 12.5763 0.714149 12.1465C0.284418 11.7167 0.0429688 11.1338 0.0429688 10.5261V3.02604C0.0429688 2.41826 0.284405 1.83537 0.71417 1.40559C1.14395 0.975814 1.72686 0.734375 2.33464 0.734375H9.8346C10.4424 0.734375 11.0253 0.9758 11.4551 1.40563C11.8849 1.8354 12.1263 2.41827 12.1263 3.02604V3.85938C12.1263 4.20455 11.8465 4.48438 11.5013 4.48438C11.1561 4.48438 10.8763 4.20455 10.8763 3.85938V3.02604C10.8763 2.74979 10.7666 2.48485 10.5712 2.28949C10.3759 2.09419 10.111 1.98438 9.8346 1.98438H2.33464&quot; fill=&quot;currentColor&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;/div&gt;&lt;div class=&quot;card space-y-4 has-gradient&quot;&gt;&lt;div class=&quot;flex gap-2 items-center font-bold text-xl text-checkly-blue&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;w-5 h-5&quot; fill=&quot;none&quot; viewBox=&quot;0 0 81 85&quot;&gt;&lt;path fill=&quot;#0075FF&quot; d=&quot;M80.704 52.41V17.622C80.704 7.89 72.814 0 63.084 0H17.65C7.919 0 .029 7.89.029 17.621v34.79C-.818 78.54 17.219 77.375 19.9 77.375l20.433 1.352v.005h.068v-.005l20.433-1.352c2.682 0 20.719 1.168 19.872-24.964h-.002Z&quot;&gt;&lt;/path&gt;&lt;path fill=&quot;#fff&quot; d=&quot;M52.193 40.889c19.825-13.637 21.334-2.36 13.37 14.757l.003.002c-2.474 4.385 2.946 6.17 7.528 6.783.002.003-2.767 8.498-8.727 13.34l-10.23 2.42-3.301 1.033c-.027.002-4.627 1.386-5.32 1.58l-10.29-.002c-.694-.195-5.294-1.58-5.32-1.58l-3.3-1.034-10.231-2.42c-5.96-4.842-8.73-13.337-8.727-13.34 4.579-.612 10.002-2.398 7.527-6.782C7.212 38.527 8.72 27.252 28.546 40.889c3.711-1.544 7.172-1.857 11.762-1.954a.13.13 0 0 0 .031.002h.092c4.59.098 8.048.408 11.762 1.952Z&quot;&gt;&lt;/path&gt;&lt;path fill=&quot;#002F66&quot; d=&quot;M15.68 38.722c-.308.065-.618.155-.884.326-.857.555-.657 1.825-.586 2.69.137 1.655.5 3.314.933 4.929a22.657 22.657 0 0 0 1.147 3.306 18.673 18.673 0 0 1 1.744-2.29 22.039 22.039 0 0 1 1.546-1.579c2.838-2.625 5.663-3.93 5.663-3.93-2.725-1.959-6.05-4.21-9.56-3.455l-.003.003ZM65.053 38.722c.308.065.618.155.884.326.857.555.657 1.825.587 2.69-.137 1.655-.5 3.314-.934 4.929a22.657 22.657 0 0 1-1.147 3.306 18.673 18.673 0 0 0-1.743-2.29 22.039 22.039 0 0 0-1.547-1.579c-2.838-2.625-5.662-3.93-5.662-3.93 2.724-1.959 6.049-4.21 9.56-3.455l.002.003ZM45.502 80.784l-.04-.09c-.541-1.218-1.646-2.093-2.88-2.546a6.522 6.522 0 0 0-4.505.026c-1.21.46-2.27 1.326-2.809 2.52l-.039.09a.115.115 0 0 0-.008.018c1.086 1.775 2.98 3.174 5.113 3.198h.063c2.136-.021 4.026-1.418 5.115-3.195a.136.136 0 0 1-.008-.019l-.002-.002ZM37.74 63.057a8.05 8.05 0 0 0-1.654-1.373 10.12 10.12 0 0 0-2.093-.996 11.426 11.426 0 0 0-2.407-.542c-.862-.098-1.735-.1-2.598-.005-.907.097-1.804.302-2.664.607-.918.326-1.794.765-2.607 1.302a13.139 13.139 0 0 0-2.422 2.078c-.818.889-1.52 1.88-2.117 2.93a21.198 21.198 0 0 0-1.686 3.863 29.738 29.738 0 0 0-1.126 4.847c-.036.245-.073.487-.107.736v-.01c-.024.155-.087.51-.108.734 4.597.534 9.192 1.162 13.747 1.993-.079-.013.515-2.582.59-2.843.191-.678.425-1.349.751-1.975.458-.881 1.102-1.617 1.944-2.146.784-.492 1.654-.826 2.475-1.25.941-.486 1.846-1.072 2.603-1.817.745-.728.987-1.543.976-2.577a4.967 4.967 0 0 0-.405-1.888 6.063 6.063 0 0 0-1.091-1.67v.002ZM64.58 77.228c-.024-.227-.084-.579-.108-.734v.01c-.031-.25-.07-.491-.108-.736a29.727 29.727 0 0 0-1.125-4.847 21.35 21.35 0 0 0-1.686-3.864c-.597-1.049-1.3-2.04-2.117-2.93a13.24 13.24 0 0 0-2.423-2.077 11.947 11.947 0 0 0-2.606-1.302c-.86-.305-1.757-.51-2.664-.607a11.759 11.759 0 0 0-2.599.005 11.26 11.26 0 0 0-2.406.542c-.731.252-1.439.583-2.093.996a8.048 8.048 0 0 0-1.655 1.373 6.004 6.004 0 0 0-1.091 1.67 4.916 4.916 0 0 0-.405 1.889c-.01 1.033.231 1.846.975 2.577.758.744 1.663 1.33 2.604 1.817.82.424 1.691.755 2.475 1.25.842.528 1.486 1.265 1.944 2.146.323.626.56 1.296.752 1.975.073.26.668 2.83.589 2.843 4.555-.831 9.15-1.46 13.747-1.994v-.002Z&quot;&gt;&lt;/path&gt;&lt;path fill=&quot;#fff&quot; d=&quot;M31.56 69.08a2.046 2.046 0 1 0 0-4.092 2.046 2.046 0 0 0 0 4.092ZM49.173 69.08a2.046 2.046 0 1 0 0-4.092 2.046 2.046 0 0 0 0 4.092Z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;div&gt;Checkly Tip&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Or use an AI agent - copy this prompt to get started:&lt;br/&gt;&amp;quot;Create an ICMP monitor in Checkly for [your-hostname-or-ip]. Ping every minute from us-east-1 and eu-west-1. Set a degraded alert at 10% packet loss and a failure alert at 20% packet loss or average latency over 200ms.&amp;quot;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;ICMP monitors are also available in Terraform and Pulumi:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Terraform (v1.18.0+):&lt;/strong&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://registry.terraform.io/providers/checkly/checkly/latest/docs/resources/icmp_monitor&quot; rel=&quot;noreferrer&quot;&gt;checkly_icmp_monitor&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pulumi (v2.8.0):&lt;/strong&gt; &lt;a target=&quot;_blank&quot; href=&quot;https://www.pulumi.com/registry/packages/checkly/api-docs/icmpmonitor/&quot; rel=&quot;noreferrer&quot;&gt;checkly.IcmpMonitor&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;pricing-and-availability&quot;&gt;&lt;a href=&quot;#pricing-and-availability&quot;&gt;Pricing and availability&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;ICMP monitors are priced as uptime monitors: flat-rate per monitor, available on all plans today. Check out our &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/pricing/&quot; rel=&quot;noreferrer&quot;&gt;pricing page&lt;/a&gt; for full details.&lt;/p&gt;&lt;h2 id=&quot;get-started&quot;&gt;&lt;a href=&quot;#get-started&quot;&gt;Get started&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Try ICMP monitors in your &lt;a target=&quot;_blank&quot; href=&quot;https://app.checklyhq.com/checks/new/icmp&quot; rel=&quot;noreferrer&quot;&gt;Checkly dashboard&lt;/a&gt; or &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/docs/detect/uptime-monitoring/icmp-monitors/overview/&quot; rel=&quot;noreferrer&quot;&gt;read the documentation&lt;/a&gt; to learn more about configuration, assertions, and alerting.&lt;/p&gt;&lt;p&gt;Questions? Find us in the &lt;a target=&quot;_blank&quot; href=&quot;https://www.checklyhq.com/slack&quot; rel=&quot;noreferrer&quot;&gt;Checkly community on Slack&lt;strong&gt;→&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;]]&gt;</content:encoded></item><item><title><![CDATA[We Turned Our WireShark Wizard Into a Markdown File]]></title><description><![CDATA[Checkly's AI agent Rocky AI is now GA. Here are five lessons from building an AI root cause analysis agent into a SaaS product: data wrangling is still the hard part, model upgrades are nearly free, multi-model is as painful as multi-cloud, codifying human expertise into prompts works, and chat isn't always the right UI for AI.]]></description><link>https://www.checklyhq.com/blog/building-an-ai-agent</link><guid isPermaLink="false">aacqYxoAAEcAtQCi</guid><category><![CDATA[AI]]></category><category><![CDATA[Product]]></category><dc:creator><![CDATA[Tim Nolet]]></dc:creator><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;Rocky AI — Checkly’s AI agent — is now Generally Available. We developed Rocky AI over the last ~6 to 8 months. This is an aeon in AI-years.&lt;/p&gt;&lt;p&gt;During this period, we learned a ton. About AI, but mostly about how to fit them into an existing SaaS product, not just another chat widget. This is my ramble…&lt;/p&gt;&lt;h2 id=&quot;something-with-ai&quot;&gt;&lt;a href=&quot;#something-with-ai&quot;&gt;Something with AI&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Like almost everyone in SaaS-land, we were pondering doing “something with AI” at least since late 2024. We went with some hunches, looked at competitors, talked to customers, hacked on some prototypes. But it was hard to pinpoint a shippable MVP. We were probably going too broad and promising a bit too much.&lt;/p&gt;&lt;h2 id=&quot;save-me-time-and-no-magic-please&quot;&gt;&lt;a href=&quot;#save-me-time-and-no-magic-please&quot;&gt;Save me time, and no magic please&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;So we did a hard reset on our AI ambitions. Instead of shipping the whole kitchen sink, what if we focus on one time consuming task in the critical path of our users? One repetitive, but critical taks that came to mind is triaging a failed Playwright Check test. Specifically, could we use LLMs to quickly create an analysis of a Playwright trace file?&lt;/p&gt;&lt;p&gt;We immediately bumped into two challenges:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;A Playwright trace file can easily be 100Mb+. We need to parse it, remove unneeded data and turn it into a plain text representation. Counterintuitively, giving MORE data to an LLM does doet always guarantee better results. Or it just blows up the input token limit.&lt;/li&gt;&lt;li&gt;When the data wrangling done, how do we guide the LLM to make sense of the data? Sure, it can do some basic summary by itself, but we want to give it guidelines on what is important to look at, what things are typically related. We essentially want these ingrained triaging steps that (senior) engineers hold in their heads to made explicit.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Over the months we expanded our AI analysis skills to cover all our check types (Playwright, HTTP, TCP, DNS, ICMP etc.). We took the same approach each time:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Look at how we can use artifacts like logs, traces etc. to build up a body of evidence for a specific failure root cause. Data wrangle it into submission so an LLM can use it.&lt;/li&gt;&lt;li&gt;Capture the skill of analyzing and interpreting said artefacts into a semi-structured markdown file.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This is now our Rocky AI Root Cause Analysis Agent. We did bump into some other learnings along the way, so I dumped them into a nice listicle. 👇&lt;/p&gt;&lt;h2 id=&quot;#1-just-do-what-the-humans-do&quot;&gt;&lt;a href=&quot;##1-just-do-what-the-humans-do&quot;&gt;#1. Just do what the humans do&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Again, this might be blatantly obvious, but we are using AI to &lt;strong&gt;just do things humans can do&lt;/strong&gt;. Example: we literally codified the Wireshark ICMP and PCAP analysis skills of one our engineers into a markdown file that now powers our AI driven ICMP and PCAP analysis. This looks a bit like this:&lt;/p&gt;&lt;div class=&quot;code-block&quot;&gt;&lt;header class=&quot;flex py-2 px-16 items-center justify-center text-[13px] tracking-tight bg-blue-300/20 text&quot;&gt;&lt;div aria-hidden=&quot;true&quot; class=&quot;absolute left-4 flex gap-x-1&quot;&gt;&lt;div class=&quot;h-2.5 w-2.5 rounded-full bg-blue-300 opacity-20&quot;&gt;&lt;/div&gt;&lt;div class=&quot;h-2.5 w-2.5 rounded-full bg-blue-300 opacity-20&quot;&gt;&lt;/div&gt;&lt;div class=&quot;h-2.5 w-2.5 rounded-full bg-blue-300 opacity-20&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class=&quot;font-mono text-gray-300&quot;&gt;icmp-rca-skill.md&lt;/span&gt;&lt;/header&gt;&lt;div class=&quot;overflow-auto w-full flex &quot;&gt;&lt;pre class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;# ICMP Analysis Skill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;## Classifications&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;The root cause can only be classified using the following classifications:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### INFRASTRUCTURE_ERROR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;External issues like network errors, packet loss, host unreachable, DNS failures, firewall blocks, or routing issues. Examples: 100% packet loss, DNS resolution failure, ICMP destination unreachable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### CONFIGURATION_ERROR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;## Artifacts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### ICMP_REQUEST&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Description: ICMP request properties including hostname, target IP, IP family, and ping count. etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;## Common Failure Patterns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### PACKET_LOSS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Symptoms: High packet loss percentage, Packets sent but not received, Packet loss threshold exceeded&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Causes: Network congestion along the route, Firewall dropping ICMP packets, Target host overloaded or rate limiting ICMP, Intermittent network issues&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;Analysis: Check packet loss percentage vs configured thresholds, Examine individual ping results for patterns, Compare results across different monitoring locations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;### DNS_RESOLUTION_FAILURE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color: undefined&quot;&gt;etc.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 id=&quot;#2-data-wrangling-is-still-the-thing&quot;&gt;&lt;a href=&quot;##2-data-wrangling-is-still-the-thing&quot;&gt;#2. Data wrangling is still the thing&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Even with extended context windows and increased quota’s on input tokens, we still do a ton of data wrangling. As mentioned above, Playwright trace files easily go over 100Mb, a network PCAP file parsed to text can also be very large. These are all data sources want the LLM to take into account.&lt;/p&gt;&lt;p&gt;Currently, we solve this problem by pre-parsing, filtering and summarising these large assets in tool calls. The tool returns the key data from these assets back to the LLM.&lt;/p&gt;&lt;h2 id=&quot;#3-model-updates-are-almost-a-free-lunch&quot;&gt;&lt;a href=&quot;##3-model-updates-are-almost-a-free-lunch&quot;&gt;#3. Model updates are almost a free lunch&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Just the last ~6 months, the upgrade from OpenAI GPT-4.1 to GPT-5.1 (let’s not mention the dreadful GPT-5) was night and day: better answers, more reliable tool calls, faster responses, less processing errors, better schema output. You can see similar patterns for the Opus 4.5 to Opus 4.6 and the Gemini upgrades.&lt;/p&gt;&lt;h2 id=&quot;#4-multi-model-is-like-multi-cloud-it-kinda-sucks-&quot;&gt;&lt;a href=&quot;##4-multi-model-is-like-multi-cloud-it-kinda-sucks-&quot;&gt;#4. Multi model is like multi cloud. It kinda sucks.&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;While building our Bring-Your-Own-Model (BYOM) feature, we allowed users to bring Gemini and Anthropic models next to our default OpenAI models. That was a mistake. Turns out that swapping models is quite hard right now if you want to keep some form of quality control and not have dedicated tests, fixtures and code paths.&lt;/p&gt;&lt;p&gt;This is even true with wrapper libraries like the Vercel AI SDK, which we use. In some way it reminds of how Terraform could in theory make your infra “multi cloud”. In practice, it really can’t.&lt;/p&gt;&lt;h2 id=&quot;#5-don-t-always-default-to-chat&quot;&gt;&lt;a href=&quot;##5-don-t-always-default-to-chat&quot;&gt;#5. Don’t always default to chat&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Obviously, chat is the de-facto UI paradigm for LLMs and generative AI. However, in our RCA case, it would be silly to force a user to go to some chat UI and asked Rocky “please analyse this failing check”. We can ask that question for the user, even when they are sleeping and just ship the initial analysis to their inbox. Chat can be a follow up.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;We are totally not done with expanding Rocky AI and adding more tools and features to its RCA skills. Watch this space.&lt;br/&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://feedback.checklyhq.com/changelog/rocky-ai-root-cause-automation-is-now-live&quot; rel=&quot;noreferrer&quot;&gt;Read the changelog here&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://checklyhq.com/product/ai-analysis/&quot; rel=&quot;noreferrer&quot;&gt;Check the product page here&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded></item><item><title><![CDATA[Introducing Rocky AI to General Availability]]></title><description><![CDATA[After months of being available in Beta for our app users, Rocky AI is now generally available to all users and plans. Rocky AI is Checkly’s AI agent that works around the clock, 24/7, to make sure your application’s reliability is optimal. In this first release, Rocky AI ships with the ability to run continual Analysis on test and check failures, giving your teams AI-powered root cause analysis, impact analysis, and more. Since day 1 of the AI craze, Checkly has made it easy to work with your favorite LLMs and coding agents like Claude Code, Cursor, and OpenAI, allowing you to craft and manage your monitoring right from your IDE. Now, we’re bringing that power right into the Checkly workflow with Rocky AI. Root Cause Analysis When a test or monitor fails, Rocky AI analyzes multiple vectors across your application, including logs, traces, and more to understand what exactly caused the failure; and how to best fix it. For large teams with hundreds of monitors across their apps and services, Rocky AI can help engineers understand the context of the check itself, even if they didn’t create it, reducing cognitive overload in the heat of an outage. For individuals and smaller engineering teams, Rocky AI will cut down on hours of back and forth, working to replicate the problem, and other triage works that delay teams from getting a quick fix back in production. User Impact Rocky AI also tries to understand and surface who exactly is impacted during an outage. Are users impacted from logging into the application? Is a core workflow being blocked? Is it a network failure that causes the test to fail, but user impact is actually minimal? Rocky AI can help you get the answers you need, faster than humanly possible, so you can get your application back up and running. Automation For teams with heavy alerting systems, Rocky AI can tap in and automatically send its findings inside any alert, right to your inbox or Slack channel. You'll get highly relevant context to the downtim...]]></description><link>https://www.checklyhq.com/blog/introducing-rocky-ai</link><guid isPermaLink="false">aagzgxoAAEYAtpQF</guid><dc:creator><![CDATA[Dan Giordano]]></dc:creator><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;After months of being available in Beta for our app users, &lt;a target=&quot;_self&quot; href=&quot;http://checklyhq.com/product/ai-analysis/&quot; rel=&quot;noreferrer&quot;&gt;&lt;strong&gt;Rocky AI&lt;/strong&gt;&lt;/a&gt; is now generally available to all users and plans. Rocky AI is Checkly’s AI agent that works around the clock, 24/7, to make sure your application’s reliability is optimal. In this first release, Rocky AI ships with the ability to run continual &lt;a target=&quot;_self&quot; href=&quot;https://www.checklyhq.com/docs/resolve/ai-root-cause-analysis/overview/&quot; rel=&quot;noreferrer&quot;&gt;&lt;strong&gt;Analysis&lt;/strong&gt;&lt;/a&gt; on test and check failures, giving your teams AI-powered root cause analysis, impact analysis, and more.&lt;/p&gt;&lt;p&gt;Since day 1 of the AI craze, Checkly has made it easy to work with your favorite LLMs and coding agents like Claude Code, Cursor, and OpenAI, allowing you to craft and manage your monitoring right from your IDE. Now, we’re bringing that power right into the Checkly workflow with Rocky AI.&lt;/p&gt;&lt;h2 id=&quot;root-cause-analysis&quot;&gt;&lt;a href=&quot;#root-cause-analysis&quot;&gt;Root Cause Analysis&lt;/a&gt;&lt;/h2&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/aag4HlxvIZEnjURm_RCA.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;When a test or monitor fails, Rocky AI analyzes multiple vectors across your application, including logs, traces, and more to understand what exactly caused the failure; and how to best fix it.&lt;/p&gt;&lt;p&gt;For large teams with hundreds of monitors across their apps and services, Rocky AI can help engineers understand the context of the check itself, even if they didn’t create it, reducing cognitive overload in the heat of an outage. For individuals and smaller engineering teams, Rocky AI will cut down on hours of back and forth, working to replicate the problem, and other triage works that delay teams from getting a quick fix back in production.&lt;/p&gt;&lt;h2 id=&quot;user-impact&quot;&gt;&lt;a href=&quot;#user-impact&quot;&gt;User Impact&lt;/a&gt;&lt;/h2&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/aag4H1xvIZEnjURn_UserImpact.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;Rocky AI also tries to understand and surface who exactly is impacted during an outage. Are users impacted from logging into the application? Is a core workflow being blocked? Is it a network failure that causes the test to fail, but user impact is actually minimal? Rocky AI can help you get the answers you need, faster than humanly possible, so you can get your application back up and running.&lt;/p&gt;&lt;h2 id=&quot;automation&quot;&gt;&lt;a href=&quot;#automation&quot;&gt;Automation&lt;/a&gt;&lt;/h2&gt;&lt;p class=&quot;block-img&quot;&gt;&lt;img src=&quot;https://images.prismic.io/checklyhq/aag4HVxvIZEnjURl_RCASlack.png?auto=format,compress&quot;/&gt;&lt;/p&gt;&lt;p&gt;For teams with heavy alerting systems, Rocky AI can tap in and automatically send its findings inside any alert, right to your inbox or Slack channel. You&amp;#x27;ll get highly relevant context to the downtime, directly inside your workflow, allowing you to break out, fix it, and get back to work.&lt;/p&gt;&lt;h2 id=&quot;getting-started&quot;&gt;&lt;a href=&quot;#getting-started&quot;&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Rocky AI Error Analysis is available in Checkly Resolve today. To get started with Rocky AI right now in Checkly, just head over to &lt;a target=&quot;_blank&quot; href=&quot;http://app.checklyhq.com&quot; rel=&quot;noreferrer&quot;&gt;app.checklyhq.com&lt;/a&gt; and click Rocky AI Analysis.&lt;/p&gt;&lt;p&gt;Or read through our &lt;a target=&quot;_self&quot; href=&quot;https://www.checklyhq.com/docs/resolve/ai-root-cause-analysis/overview/&quot; rel=&quot;noreferrer&quot;&gt;documentation&lt;/a&gt; to get a better grasp of Rocky AI&lt;/p&gt;&lt;h2 id=&quot;what-s-next&quot;&gt;&lt;a href=&quot;#what-s-next&quot;&gt;What’s Next&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;With Rocky AI hitting general available with the ability Analyze results, we are only getting started. We will be adding other capabilities and skills to Rocky AI over time, to bring you native AI powered test generation, alert configuring, and more - right inside the Checkly dashboard. If you are a heavy user of LLMs or Agents, then check out Rocky AI or start using Checkly with tools like Claude Code today.&lt;/p&gt;]]&gt;</content:encoded></item></channel></rss>