
Atalaya
Monitor endpoints from Cloudflare regions and publish an uptime status page.
Atalaya is a self-hosted Better Stack/Pingdom alternative built on Cloudflare (D1, Durable Objects, Workers). Free tier eligible within limits. Inspect the source and license in the linked repository.
Source & license
Upstream license: Apache-2.0
License TL;DR
You can use, change and sell it, including in closed-source products. When sharing copies, include the license, keep required notices and mark changed files. It includes a contributor patent grant with conditions, but no trademark permission or warranty.
Explain Apache 2.0 in plain English →Summary of the main license. Separate packages and assets can have different terms.
Inspect repository ↗Read this project’s actual license ↗Repository owner
See the upstream repository for the original creator and contributors.
Maintain this project? Maintainer verification →Cloudflare hosting
Free tier eligible within limits
The documented Atalaya deployment can use Cloudflare Free allowances for a small workload under the request, CPU and service-specific quotas below. This is conditional eligibility, not a measured zero-cost deployment; optional features, domains and external providers can add costs.
Hosting requirements
- Workers Free allows 100,000 requests per day shared across the account and 10 ms CPU per invocation; measure CPU-heavy authentication, parsing and rendering before assuming it fits.
- Keep aggregate D1 use below 5 million rows read/day, 100,000 rows written/day and 5 GB total storage; a request can touch many rows.
- Use the configured SQLite Durable Object classes within 100,000 requests/day, 13,000 GB-s duration/day, 5 million SQL rows read/day, 100,000 written/day and 5 GB storage; active sockets consume duration.
- Use a small personal or team workload; domain registration and optional third-party providers are separate costs. Provision your own IDs, secrets and migrations.
Sources checked 01/10/2026
Repository snapshot: 5437d1c. Hosting eligibility reflects the deployment documentation and listed assumptions.
- uptimerobot ↗
Atalaya (Spanish for watchtower) is an uptime & status page monitoring service running on Cloudflare Workers and Durable Objects allowing checks from multiple regions.
- better-stack ↗
Atalaya (Spanish for watchtower) is an uptime & status page monitoring service running on Cloudflare Workers and Durable Objects allowing checks from multiple regions.
- pingdom ↗
Atalaya (Spanish for watchtower) is an uptime & status page monitoring service running on Cloudflare Workers and Durable Objects allowing checks from multiple regions.
- workers ↗
name = "atalaya" main = "src/index.ts" compatibility_date = "2026-07-06" compatibility_flags = ["nodejs_compat"] workers_dev = false [cache] enabled = true [assets] directory = "./status-page/dist/client/" binding = "ASSETS" run_worker_first = true [triggers] crons = ["* * * * *", "0 * * * *"] [[d1_databases]] binding = "DB" database_name = "atalaya" database_id = "xxxxxxxx-yyyy-xxxx-iiii-jjjjjjjjjjjj" migrations_dir = "./migrations" [[durable_objects.bindings]] name = "REGIONAL_CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Mo
- d1 ↗
worker_first = true [triggers] crons = ["* * * * *", "0 * * * *"] [[d1_databases]] binding = "DB" database_name = "atalaya" database_id = "xxxxxxxx-yyyy-xxxx-iiii-jjjjjjjjjjjj" migrations_dir = "./migrations" [[durable_objects.bindings]] name = "REGIONAL_CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Monitor" default_retries: 2 default_retry_delay_ms: 1000 default_timeout_ms: 5000 default_failure_threshold: 2 alerts: - name: "telegram" type: webhook url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" method: POST headers: Content-Ty
- durable-objects ↗
CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Monitor" default_retries: 2 default_retry_delay_ms: 1000 default_timeout_ms: 5000 default_failure_threshold: 2 alerts: - name: "telegram" type: webhook url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" method: POST headers: Content-Type: application/json body_template: | { "chat_id": "${TELEGRAM_CHAT_ID}", "text": "{{monitor.name}} transitioned from status {{status.previous}} to status {{status.current}} {{check.error}}" } - name: "default" type:
- free-tier-eligible ↗
name = "atalaya" main = "src/index.ts" compatibility_date = "2026-07-06" compatibility_flags = ["nodejs_compat"] workers_dev = false [cache] enabled = true [assets] directory = "./status-page/dist/client/" binding = "ASSETS" run_worker_first = true [triggers] crons = ["* * * * *", "0 * * * *"] [[d1_databases]] binding = "DB" database_name = "atalaya" database_id = "xxxxxxxx-yyyy-xxxx-iiii-jjjjjjjjjjjj" migrations_dir = "./migrations" [[durable_objects.bindings]] name = "REGIONAL_CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Mo
- free-tier-eligible ↗
worker_first = true [triggers] crons = ["* * * * *", "0 * * * *"] [[d1_databases]] binding = "DB" database_name = "atalaya" database_id = "xxxxxxxx-yyyy-xxxx-iiii-jjjjjjjjjjjj" migrations_dir = "./migrations" [[durable_objects.bindings]] name = "REGIONAL_CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Monitor" default_retries: 2 default_retry_delay_ms: 1000 default_timeout_ms: 5000 default_failure_threshold: 2 alerts: - name: "telegram" type: webhook url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" method: POST headers: Content-Ty
- free-tier-eligible ↗
CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Monitor" default_retries: 2 default_retry_delay_ms: 1000 default_timeout_ms: 5000 default_failure_threshold: 2 alerts: - name: "telegram" type: webhook url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" method: POST headers: Content-Type: application/json body_template: | { "chat_id": "${TELEGRAM_CHAT_ID}", "text": "{{monitor.name}} transitioned from status {{status.previous}} to status {{status.current}} {{check.error}}" } - name: "default" type:
- free-tier-eligible ↗
up>1, 2, 3, 4</sup> | Duration | CPU time | | --- | --- | --- | --- | | **Free** | 100,000 per day | No charge for duration | 10 milliseconds of CPU time per invocation | | **Standard** | 10 million included per month <br> +$0.30 per additional million | No charge or limit for duration | 30 million CPU milliseconds included per month<br> +$0.02 per additional million CPU milliseconds<br><br> Max of [5 minutes of CPU time](https://developers.cloudflare.com/workers/platform/limits/#account-plan-limits) per invocation (default: 30 seconds)<br> Max of 15 minutes of CPU time per [Cron Trigger](https://developers.cloudflare.com/workers/configuration/cron-triggers/) or [Queue Consumer](https://developers.cloudflare.co
- free-tier-eligible ↗
oudflare.com/workers/platform/pricing/#workers) | | --- | --- | --- | | Rows read | 5 million / day | First 25 billion / month included + $0.001 / million rows | | Rows written | 100,000 / day | First 50 million / month included + $1.00 / million rows | | Storage (per GB stored) | 5 GB (total) | First 5 GB included + $0.75 / GB-mo | Track your D1 usage To accurately track your usage, use the [meta object](https://developers.cloudflare.com/d1/worker-api/return-object/), [GraphQL Analytics API](https://developers.cloudflare.com/d1/observability/metrics-analytics/#query-via-the-graphql-api), or the [Cloudflare dashboard ↗︎](https://dash.cloudflare.com/?to=/:account/workers/d1/). Select your D1 database, then vie
- free-tier-eligible ↗
jects are available both on Workers Free and Workers Paid plans. - **Workers Free plan**: Only Durable Objects with [SQLite storage backend](https://developers.cloudflare.com/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) are available. - **Workers Paid plan**: Durable Objects with the SQLite storage backend are available. The [key-value storage backend](https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/#storage-backends) is only available to accounts that already have a key-value-backed namespace. If you wish to downgrade from a Workers Paid plan to a Workers Free plan, you must first ensure that you have deleted all Durable Object namespaces with the key-value storage backend. On Workers Free plan: - If you exceed any one of the free tier limits, further operations of that type will fail with an error. - Daily free limits reset at 00:00 UTC. ## Compute billing Durable Objects are billed for compute duration (wall-clock time) while the Durable Object is actively running or is idle in memory but unable to [hibernate](https://developers.cloudflare.com/durable-objects/concepts/durable-object-lifecycle/). Durable Objects that are idle and eligible for hibernation are not billed for duration, even before the runtime has hibernated them. Requests to a D
- free-tier-eligible ↗
billed accordingly. | | Free plan | Paid plan | | --- | --- | --- | | Requests | 100,000 / day | 1 million / month, + $0.15/million<br> Includes HTTP requests, RPC sessions<sup>1</sup>, WebSocket messages<sup>2</sup>, and alarm invocations | | Duration<sup>3</sup> | 13,000 GB-s / day | 400,000 GB-s / month, + $12.50/million GB-s<sup>4,5</sup> | <details> <summary> Footnotes </summary> <sup>1</sup> Each <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/lifecycle/">RPC session</a> is billed as one request to your Durable Object. Every <a href="https://developers.cloudflare.com/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/">RPC method call</a> on a <a href="https://developers.cloudflare.com/durable-objects/">Durable Objects stub</a> is its own RPC session and therefore a single billed request. RPC method calls can return objects (stubs) extending <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/lifecycle/#lifetimes-memory-and-resource-management"><code>RpcTarget</code></a> and invo
- free-tier-eligible ↗
/). | | Workers Free plan | Workers Paid plan | | --- | --- | --- | | Rows reads <sup>1,2</sup> | 5 million / day | First 25 billion / month included + $0.001 / million rows | | Rows written <sup>1,2,3,4</sup> | 100,000 / day | First 50 million / month included + $1.00 / million rows | | SQL Stored data <sup>5</sup> | 5 GB (total) | 5 GB-month, + $0.20/ GB-month | <details> <summary> Footnotes </summary> <sup>1</sup> Rows read and rows written included limits and rates match <a href="https://developers.cloudflare.com/d1/platform/pricing/">D1 pricing</a>, Cloudflare's serverless SQL database. <sup>2</sup> Key-value methods like <code>get()</code>, <code>put()</code>, <code>delete()</code>, or <code>list(
- Apache-2.0 ↗
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to ca
- architecture ↗
name = "atalaya" main = "src/index.ts" compatibility_date = "2026-07-06" compatibility_flags = ["nodejs_compat"] workers_dev = false [cache] enabled = true [assets] directory = "./status-page/dist/client/" binding = "ASSETS" run_worker_first = true [triggers] crons = ["* * * * *", "0 * * * *"] [[d1_databases]] binding = "DB" database_name = "atalaya" database_id = "xxxxxxxx-yyyy-xxxx-iiii-jjjjjjjjjjjj" migrations_dir = "./migrations" [[durable_objects.bindings]] name = "REGIONAL_CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Mo
- architecture ↗
worker_first = true [triggers] crons = ["* * * * *", "0 * * * *"] [[d1_databases]] binding = "DB" database_name = "atalaya" database_id = "xxxxxxxx-yyyy-xxxx-iiii-jjjjjjjjjjjj" migrations_dir = "./migrations" [[durable_objects.bindings]] name = "REGIONAL_CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Monitor" default_retries: 2 default_retry_delay_ms: 1000 default_timeout_ms: 5000 default_failure_threshold: 2 alerts: - name: "telegram" type: webhook url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" method: POST headers: Content-Ty
- architecture ↗
CHECKER_DO" class_name = "RegionalChecker" [[migrations]] tag = "v1" new_sqlite_classes = ["RegionalChecker"] [vars] MONITORS_CONFIG = """ settings: title: "Atalaya Uptime Monitor" default_retries: 2 default_retry_delay_ms: 1000 default_timeout_ms: 5000 default_failure_threshold: 2 alerts: - name: "telegram" type: webhook url: "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" method: POST headers: Content-Type: application/json body_template: | { "chat_id": "${TELEGRAM_CHAT_ID}", "text": "{{monitor.name}} transitioned from status {{status.previous}} to status {{status.current}} {{check.error}}" } - name: "default" type:
Documented public demo screenshot · dcarrillo/atalaya repository contributors; screenshot captured by Cloudsteading ↗. Depicts the upstream project. We have not deployed and tested a fresh installation here.
What it can replace
Compare the workflow you need. These mappings describe overlap; full feature parity requires a separate comparison.
Endpoint availability checking, regional checks and publishing a status page; full incident management, on-call escalation and synthetic-browser parity are excluded.
See supporting source ↗Endpoint availability checking, regional checks and publishing a status page; full incident management, on-call escalation and synthetic-browser parity are excluded.
See supporting source ↗Endpoint availability checking, regional checks and publishing a status page; full incident management, on-call escalation and synthetic-browser parity are excluded.
See supporting source ↗How it works
The shape of Atalaya on Cloudflare, and how it stacks up against the rented tools it replaces.
Architecture
Services observed in deployment configuration. Routes, jobs and runtime behavior still need verification.
View upstream source ↗Configuration and workflow sources
Reviewed commit 5437d1c4357d. Files were read as data; upstream applications and CI jobs were not executed.
Partial source coverage: 3 files outside collection bounds; 0 collection or parsing issues. Dynamic imports and generated entrypoints may need manual review.
Deployment configuration · 1 files
Cloudflare Workers · example/template, excluded from overview · compatibility 2026-07-06
atalaya · default
Entrypoint: src/index.ts
Static assets: ./status-page/dist/client/ · Worker first: true
Cron triggers (UTC): * * * * * · 0 * * * *
Configured route patterns: custom.domain.com
DB→ D1REGIONAL_CHECKER_DO→ Durable Objects · class RegionalCheckerASSETS→ Static assets
Named environments are separate deployments. Bindings are shown only where declared. Configured routes are URL patterns, not verified application endpoints.
Runtime source · handlers, binding usage and workflow steps
Observed TypeScript/JavaScript declarations from Worker entrypoints and resolved relative imports. Calls and workflow steps may run conditionally; their listed order is not a proven end-to-end request flow. Router declarations may be mounted under a prefix or may not be registered. This shows code wiring, not a successful deployment or runtime test. Dynamic wiring, aliases and generated code may not resolve.
- L19 · fetch handler exported · references ASSETS, STATUS_PUBLIC · calls checkAuth, env.ASSETS.fetch, astroMod.default.fetch, responseWithCache.headers.set, console.error, JSON.stringify, String
- L62 · scheduled handler exported · references MONITORS_CONFIG, DB · calls handleAggregation, interpolateSecrets, parseConfig, prepareChecks, console.warn, JSON.stringify, executeAllChecks, getMonitorStates, processResults, writeCheckResults, updateMonitorStates, Promise.all, actions.alerts.map, sendWebhook, recordAlert, console.info, console.error, String
- L115 · executeAllChecks calls (conditional paths may differ): checks.map, executeCheck, Promise.all
- L120 · executeCheck calls (conditional paths may differ): console.info, JSON.stringify, env.REGIONAL_CHECKER_DO.idFromName, env.REGIONAL_CHECKER_DO.get, typedStub.runCheck, typedStub.kill, console.error, String, console.warn, executeLocalCheck
- L178 · executeLocalCheck calls (conditional paths may differ): console.info, JSON.stringify, executeHttpCheck, executeTcpCheck, executeDnsCheck
- L195 · sendWebhook calls (conditional paths may differ): formatWebhookPayload, console.error, JSON.stringify, isBlockedURL, fetch, String
Environment references: env.ASSETS · env.STATUS_PUBLIC · env.MONITORS_CONFIG · env.DB · env.REGIONAL_CHECKER_DO
- L16 · timingSafeCompare calls (conditional paths may differ): Promise.all, crypto.subtle.digest, encoder.encode
- L33 · checkAuth calls (conditional paths may differ): request.headers.get, unauthorizedResponse, authHeader.slice, atob, credentials.indexOf, credentials.slice, Promise.all, timingSafeCompare
Environment references: env.STATUS_PUBLIC · env.STATUS_USERNAME · env.STATUS_PASSWORD
- L7 · chunkArray calls (conditional paths may differ): chunks.push, array.slice
- L26 · handleAggregation calls (conditional paths may differ): Math.floor, Date.now, aggregateHour, deleteOldRawData, deleteOldHourlyData, console.info, JSON.stringify, toISOString
- L43 · aggregateHour calls (conditional paths may differ): all, bind, database.prepare, result.results.map, stmt.bind, Math.round, chunkArray, database.batch
- L101 · deleteOldRawData calls (conditional paths may differ): run, bind, database.prepare
- L106 · deleteOldHourlyData calls (conditional paths may differ): run, bind, database.prepare
Environment references: env.DB
- L8 · executeDnsCheck calls (conditional paths may differ): Date.now, encodeURIComponent, setTimeout, controller.abort, fetch, clearTimeout, sleep, response.json, expectedValues.every, resolvedValues.includes, expectedValues.join, resolvedValues.join
- L9 · executeHttpCheck calls (conditional paths may differ): Date.now, isBlockedURL, setTimeout, controller.abort, fetch, clearTimeout, response.text, errorMessages.push, check.expectedBodyContains.trim, bodyText.includes, errorMessages.join, sleep
- L5 · executeTcpCheck calls (conditional paths may differ): Date.now, check.target.split, Number.parseInt, Number.isNaN, connect, setTimeout, reject, Promise.race, clearTimeout, socket.close, sleep
- L5 · chunkArray calls (conditional paths may differ): chunks.push, array.slice
- L14 · getMonitorStates calls (conditional paths may differ): all, bind, database.prepare
- L25 · writeCheckResults calls (conditional paths may differ): database.prepare, writes.map, stmt.bind, chunkArray, database.batch
- L44 · updateMonitorStates calls (conditional paths may differ): database.prepare, updates.map, stmt.bind, chunkArray, database.batch
- L77 · recordAlert calls (conditional paths may differ): run, bind, database.prepare, Math.floor, Date.now
- L1 · interpolateSecrets calls (conditional paths may differ): configYaml.replaceAll
- L1 · sleep calls (conditional paths may differ): setTimeout
- L7 · interpolateEnv calls (conditional paths may differ): content.replaceAll
- L14 · applyDefaults calls (conditional paths may differ): JSON.stringify, alerts.push, map, isValidRegion, console.warn, Array.isArray, m.maintenance.filter, Date.parse, isNaN, w.start.endsWith, w.end.endsWith, String
- L141 · parseConfig calls (conditional paths may differ): interpolateEnv, yaml.load, applyDefaults
- L4 · prepareChecks calls (conditional paths may differ): config.monitors.map, Object.keys, String
- L12 · processResults calls (conditional paths may differ): monitorMap.set, stateMap.set, Math.floor, Date.now, monitorMap.get, isInMaintenance, stateMap.get, actions.dbWrites.push, actions.stateUpdates.push, actions.alerts.push
- L7 · jsonEscape calls (conditional paths may differ): JSON.stringify, escaped.slice
- L16 · resolveKey calls (conditional paths may differ): key.trim, jsonEscape, statusEmoji, String, resolvers.get, resolver
- L40 · renderTemplate calls (conditional paths may differ): template.replaceAll, resolveKey
- L53 · formatWebhookPayload calls (conditional paths may differ): config.alerts.find, config.monitors.find, invertStatus, toISOString, renderTemplate
Build and deployment pipeline · 1 GitHub Actions workflows
Repository CI declarations, separate from runtime request processing. Job dependencies and conditions are shown as written; long commands are shortened with an ellipsis; a workflow file does not prove a recent successful run.
Triggers: push, pull_request
test · no job dependencies declared
- actions/checkout@v6
actions/checkout@v6 - Install pnpm
pnpm/action-setup@v6 - Set up Node.js ${{ matrix.node-version }}
actions/setup-node@v6 - Install dependencies
pnpm install --frozen-lockfile - Run linters and type checking
pnpm check pnpm check:pages - Build status page
pnpm build:pages - Run worker tests
pnpm test - Run status-page tests
pnpm test:pages
deploy: pnpm --filter=atalaya-prod-status-page run build && wrangler deploybuild:pages: pnpm --filter=atalaya-prod-status-page run build
build: astro builddeploy: echo 'Deploy from root: pnpm run deploy'
Repository README
View original on GitHub ↗Full upstream document by @dcarrillo · README.md · snapshot 5437d1c
Atalaya Uptime Monitor
Atalaya (Spanish for watchtower) is an uptime & status page monitoring service running on Cloudflare Workers and Durable Objects allowing checks from multiple regions.
It runs entirely on Cloudflare's free tier, so you get a self-hosted uptime monitor and status page without paying for servers. It's aimed at hobbyists who want control over their monitoring and don't mind living inside Cloudflare's ecosystem.
Live example.
:warning: 99% of the code has been generated by an AI agent under human supervision, bearing in mind that I haven't used TypeScript before. You have been warned!
🏴☠️
|
_ _|_ _
|;|_|;|_|;|
\\. . /
\\: . /
||: |
||:. |
||: .|
||: , |
||: |
||: . |
_||_ |
__ ----~ ~`---,
__ ,--~' ~~----____
Features
- HTTP/HTTPs, TCP, and DNS monitoring.
- Regional monitoring from specific Cloudflare locations.
- Configurable retries with immediate retry on failure.
- Configurable failure thresholds before alerting.
- Custom alert templates for notifications (currently only webhooks are supported).
- Historical data stored in Cloudflare D1.
- Status page built with Astro 6 SSR, served by the same Worker via Static Assets.
- 90-day uptime history with daily bars.
- Response time charts (uPlot) with downtime bands.
- Basic auth or public access modes.
- Dark/light mode.
- Custom banner image support with optional clickable link.
Documentation
Read the docs for setup, configuration, alerts, and more.
Development
# Run worker locally
wrangler dev --test-scheduled
# Run status page locally
pnpm dev:pages
# Trigger cron manually
curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*"
Testing
# First build the status page
pnpm build:pages
# Worker tests
pnpm test
# Status page unit tests
pnpm test:pages
# Type checking and linting
pnpm check # worker (typecheck + lint + format)
pnpm check:pages # pages (astro check + tsc + lint)
TODO
- Add support for TLS checks (certificate validity, expiration). Apparently, the Workers API does not support certificate data access, even at the socket level. An external service may be required.
- Refine the status page to look... well... less AI-generated.
- Per-monitor maintenance windows
- Initial support for incident management (manual status overrides, incident timeline).
- Branded status page (simple custom banner).
- Add support for notifications other than webhooks.
Frequently asked about Atalaya
What is Atalaya?+
Atalaya is a self-hosted Better Stack/Pingdom alternative built on the Cloudflare developer platform. Monitor endpoints from Cloudflare regions and publish an uptime status page.
What does Atalaya replace?+
Atalaya is listed as an alternative to Better Stack, Pingdom, UptimeRobot. Compare the features and tradeoffs before migrating.
What Cloudflare primitives does Atalaya use?+
Atalaya is built on D1, Durable Objects, Workers.
How much does Atalaya cost to run?+
The documented Atalaya deployment can use Cloudflare Free allowances for a small workload under the request, CPU and service-specific quotas below. This is conditional eligibility, not a measured zero-cost deployment; optional features, domains and external providers can add costs. Workers Free allows 100,000 requests per day shared across the account and 10 ms CPU per invocation; measure CPU-heavy authentication, parsing and rendering before assuming it fits. Keep aggregate D1 use below 5 million rows read/day, 100,000 rows written/day and 5 GB total storage; a request can touch many rows. Use the configured SQLite Durable Object classes within 100,000 requests/day, 13,000 GB-s duration/day, 5 million SQL rows read/day, 100,000 written/day and 5 GB storage; active sockets consume duration. Use a small personal or team workload; domain registration and optional third-party providers are separate costs. Provision your own IDs, secrets and migrations. Check current Cloudflare pricing before deploying.
Is Atalaya open source?+
The upstream repository declares the Apache-2.0 license. Read its terms at https://raw.githubusercontent.com/dcarrillo/atalaya/5437d1c4357de76f045261aa04974c91c0895ca5/LICENSE. Source code and contributor credit are available at https://github.com/dcarrillo/atalaya.



Discussion · 0
sign in to comment →