Build an AI Website Monitor with TypeScript and Agent Browser A developer at Telnyx published Watchdog, an open-source TypeScript example that uses a Telnyx Edge Stateful Actor and the beta Agent Browser to monitor websites for experience-level changes rather than just HTTP 200 responses. The system captures a healthy baseline, runs a real Chromium session on a daily schedule to observe pages and interact with forms, then sends an SMS via Telnyx Messaging when a verdict flips between healthy and broken. Each watched hostname maps to its own durable actor with independent state, scheduling, and incident history. An uptime check can tell you that a page returned HTTP 200 . It cannot tell you that the price changed unexpectedly, a form stopped submitting, or a client-side deployment removed an important field. Watchdog https://github.com/team-telnyx/telnyx-code-examples/tree/main/watchdog is an open-source TypeScript example that checks the experience, not only the response code. It remembers a healthy baseline, wakes on a schedule, drives a real browser through the page, records evidence, and sends an SMS when the result changes. The application combines a Telnyx Edge Stateful Actor, Agent Browser, SQL, KV, AI Inference, and Messaging. This tutorial explains how those pieces fit together and why its retry rules matter. Beta notice: Telnyx Agent Browser is currently in beta. Request shapes, actions, and error behavior may change. Check the current Agent Browser documentation https://developers.telnyx.com/docs/agent-browser before using this pattern in production. One actor owns one watched hostname. Its state includes: The first scheduled run captures the baseline. Later runs: finally block. The verdict is either healthy or broken with a reason. A broken verdict opens or updates an incident. A later healthy run closes that incident with before-and-after evidence. The actor identity comes from the target hostname: export function watchId targetUrl: string : string { return new URL targetUrl .hostname } const actor = env.WATCHDOG.idFromName watchId targetUrl Two URLs on the same hostname belong to the same watchdog. A different hostname gets a separate actor with independent state, scheduling, and incident history. This makes the watched property a durable entity instead of a row that a stateless cron task must reconstruct on every run. When a watch is armed, the actor stores its configuration and schedules both the first check and the recurring daily check: js const dailyId = await this.every 86400, "runCheck", { reason: "scheduled" }, { id: daily-${ownerId} }, await this.schedule 5, "runCheck", { reason: "first", run key: firstRunKey }, { id: first-${ownerId} }, The first run occurs shortly after setup. Subsequent checks run daily. The actor calls the Agent Browser REST API to create a short-lived Chromium session. The request restricts navigation to the watched hostname and applies hard lifetime limits: { "policy": { "allowed domains": "shop.example.com" }, "limits": { "lifetime s": 900, "idle timeout s": 120 }, "idempotency key": "2026-11-06" } The actor polls the session until it becomes ready. A session returned by an idempotent replay may already be closed, failed, or expired, so the code checks for terminal states and creates a fresh session when needed. Agent Browser provides isolated sessions plus structured actions for navigation, observation, interaction, and screenshots. The official Agent Browser overview https://developers.telnyx.com/docs/agent-browser describes the browser as short-lived and isolated, with semantic observations designed for model tool use. After navigation, an observe action returns an observation id , a text representation of the page, and element refs. The model works with those refs rather than pixel coordinates. The watchdog asks the configured inference model to identify four elements: It then performs fill and click actions using both the current observation ID and the selected ref. The Agent Browser actions documentation https://developers.telnyx.com/docs/agent-browser/actions requires observation id for ref-based interactions and documents the available action types. The model does not decide whether the HTTP request succeeded. It helps map the structured observation to the page elements the deterministic workflow needs. The first successful run stores the observed price and form labels as the baseline: interface Baseline { price text: string form labels: string } Later runs compare the pre-submit observation with that baseline. The post-submit observation has a different purpose: it proves whether the interaction reached the expected success state. Keeping those observations separate avoids a subtle mistake. A form submission may navigate or rerender the page, so the final page is not necessarily the correct source for pricing comparison. The Stateful Actor owns the current lifecycle, while WATCHDOG DB stores an audit-friendly ledger. The runs table records values including: The incidents table records the first broken time, reason, evidence artifact IDs, and open or closed status. Scheduled runs use the UTC date as their stable run key. Before starting, the actor checks whether that key already has a verdict: js const prior = await this.rows<{ verdict: string | null } "SELECT verdict FROM runs WHERE run key = ?", runKey, if prior 0 ?.verdict && reason === "scheduled" || reason === "first" return That guard makes a restarted or replayed scheduled task a no-op instead of a duplicate browser run or duplicate incident. KV holds the small indexes needed to route incoming commands: php watch/