A powerful, serverless status page application built with TypeScript and React, running on Cloudflare Workers. Monitor your websites and APIs with automated health checks, historical uptime data, and instant notifications via Slack or Discord.
π Live Demo
- Features
- Prerequisites
- Quick Start
- Configuration
- Local Development
- Deployment
- Advanced Features
- Workers KV Free Tier
- Known Issues
- Contributing
- License
- Acknowledgments
- π¦ TypeScript First - Fully typed for enhanced developer experience
- β‘ Serverless Architecture - Built on Cloudflare Workers for global edge deployment
- π Historical Data - Track uptime with configurable history (default: 90 days)
- π Smart Notifications - Instant alerts via Slack or Discord webhooks
- π Response Time Monitoring - Collect and display response time metrics
- π Remote CSV Monitors - Import monitor configurations from Google Sheets
- π Unlimited Monitors - No artificial limits, even on Workers KV free tier
- β»οΈ Auto Cleanup - Automatic garbage collection for KV storage optimization
- π¨ Modern UI - React-based interface with Tailwind CSS and SSR via Vike
- βοΈ CRON Scheduling - Automated health checks at customizable intervals
- Node.js (v20 or higher) and pnpm package manager
- Cloudflare Workers Account
- Workers domain configured
- Workers Bundled subscription ($5/month) or Free tier (see limitations)
- Cloudflare API Token with
Edit Cloudflare Workerspermissions- Create at: Cloudflare Dashboard > My Profile > API Tokens
- Use the "Edit Cloudflare Workers" template
- Slack Webhook URL - For Slack notifications (setup guide)
- Discord Webhook URL - For Discord notifications (setup guide)
Click the "Use this template" button at the top of this repository to create your own copy.
Create a KV namespace in your Cloudflare account:
- Go to Cloudflare Dashboard > Workers & Pages > KV
- Click "Create a namespace"
- Name it
KV_STORE(or any name you prefer) - Copy the namespace ID
- Update wrangler.jsonc:
Navigate to your repository Settings > Secrets and variables > Actions and add:
| Secret Name | Required | Description |
|---|---|---|
CLOUDFLARE_ACCOUNT_ID |
β | Your Cloudflare account ID (find it here) |
CLOUDFLARE_API_TOKEN |
β | API token with Workers edit permissions |
SECRET_SLACK_WEBHOOK_URL |
β | Slack webhook for notifications |
SECRET_DISCORD_WEBHOOK_URL |
β | Discord webhook for notifications |
Edit src/config.ts to customize your status page:
export const config: Config = {
settings: {
title: 'My Status Page',
url: 'https://status.example.com/',
displayDays: 90,
collectResponseTimes: true,
},
monitors: [
{
id: 'example-website',
url: 'https://example.com/',
name: 'Example Website',
followRedirect: true,
},
// Add more monitors here
],
}Push your changes to the master branch:
git add .
git commit -m "Configure status page"
git push origin masterGitHub Actions will automatically build and deploy your status page! π
- Go to Cloudflare Dashboard > Workers & Pages
- Select your worker
- Go to Settings > Triggers > Routes
- Add a custom domain or route
Each monitor in src/config.ts supports the following options:
| Option | Type | Required | Description |
|---|---|---|---|
id |
string |
β | Unique identifier for the monitor |
url |
string |
β | URL to monitor |
name |
string |
β | Display name for the monitor |
followRedirect |
boolean |
β | Whether to follow HTTP redirects |
| Setting | Type | Default | Description |
|---|---|---|---|
title |
string |
- | Status page title |
url |
string |
- | Public URL of your status page |
displayDays |
number |
90 |
Number of days to display history |
collectResponseTimes |
boolean |
true |
Whether to collect response times |
Edit the cron schedule in wrangler.jsonc:
"env": {
"production": {
"triggers": {
"crons": [
"*/30 * * * *" // Check every 30 minutes
]
}
}
}Use crontab.guru to create custom schedules.
-
Install pnpm (if not already installed):
npm install -g pnpm
-
Clone and install dependencies:
git clone https://github.com/your-username/cf-workers-status-page-typescript.git cd cf-workers-status-page-typescript pnpm install -
Authenticate with Cloudflare:
npx wrangler login
-
Create KV namespace (if not already created):
npx wrangler kv:namespace create KV_STORE
Copy the namespace ID to wrangler.jsonc.
| Command | Description | Duration |
|---|---|---|
pnpm install |
Install dependencies | ~16s |
pnpm run build |
Build the project | ~10s |
pnpm run preview |
Build and preview locally at http://localhost:3000 | ~15s startup |
pnpm run preview:production |
Preview in production mode | ~15s startup |
pnpm run deploy |
Deploy to Cloudflare Workers | ~30s |
pnpm run wrangler:types |
Generate TypeScript types from Wrangler | ~3s |
- β
Use
pnpm run preview- This uses Wrangler dev mode which is fully functional - Build required - Changes require a full build to be reflected
- No hot reload - Manual rebuild and restart needed for changes
The Express-based local dev server (dev-server/index.ts) has been removed. It depended on the express devDependency, which had a reported security vulnerability, and was already non-functional due to an incompatibility with path-to-regexp. Use pnpm run preview (Wrangler dev mode) for local development.
React Version Synchronization: This project enforces that react and react-dom versions must always match. A preinstall hook automatically validates this before package installation to prevent version mismatches that could cause build or runtime issues.
cf-workers-status-page-typescript/
βββ src/
β βββ config.ts # Main configuration file
β βββ worker/
β β βββ index.ts # Worker entry point
β β βββ cron/ # Scheduled monitoring logic
β β βββ ssr/ # Server-side rendering
β βββ pages/ # React page components
β βββ components/ # Reusable React components
βββ wrangler.jsonc # Cloudflare Worker config
βββ package.json # Dependencies and scripts
βββ tsconfig.json # TypeScript configuration
The project uses GitHub Actions for automatic deployment:
- Push to the
masterbranch - GitHub Actions automatically builds and deploys
- Check deployment status in the Actions tab
pnpm run deployEnsure you have the following configured:
- Cloudflare authentication (via
wrangler login) - Correct account ID in
wrangler.jsoncor environment variables - KV namespace created and configured
You can import monitor configurations from a remote CSV file (e.g., Google Sheets):
- Create a Google Sheet using this template
- Publish it to the web: File > Share > Publish to web
- Select the specific sheet and choose Comma-separated values (.csv)
- Copy the URL and add it to src/config.ts:
monitorsCsvUrl: 'https://docs.google.com/spreadsheets/d/e/YOUR_SHEET_ID/pub?output=csv' - Uncomment the CSV update cron trigger in wrangler.jsonc
Enable response time tracking in src/config.ts:
settings: {
collectResponseTimes: true,
}Response times are displayed on the status page for each monitor.
Add webhook URLs as secrets in GitHub repository settings or Cloudflare Workers environment variables:
- Slack:
SECRET_SLACK_WEBHOOK_URL - Discord:
SECRET_DISCORD_WEBHOOK_URL
Notifications are sent when a monitor's status changes (up
The Cloudflare Workers Free plan includes limited KV operations:
- Read operations: 100,000 per day
- Write operations: 1,000 per day
- Storage: 1 GB
For free tier users, adjust the monitoring frequency:
-
Edit wrangler.jsonc:
"crons": ["*/2 * * * *"] // Check every 2 minutes instead of 30
-
Consider reducing the number of monitors or
displayDaysin config
The default 30-minute interval works well with the Bundled plan ($5/month).
Reference: Cloudflare Workers KV Free Tier Announcement
- Issue: Notifications arrive instantly, but status page updates may lag by a few seconds
- Cause: CRON Triggers run on underutilized machines
- Impact: Minimal; typically resolves within seconds
- Issue: Status page shows "No Data" immediately after deployment
- Cause: CRON Triggers take a few minutes to initialize and run for the first time
- Solution: Wait 2-5 minutes after deployment for first data collection
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
Please ensure your code:
- Follows the existing TypeScript style
- Includes appropriate type definitions
- Has been tested locally with
pnpm run preview - Doesn't break existing functionality
Found a bug? Please open an issue with:
- A clear description of the problem
- Steps to reproduce
- Expected vs actual behavior
- Your environment (Node version, OS, etc.)
This project is licensed under the MIT License - see below for details:
MIT License
Copyright (c) 2026 Matthew Lew
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This project builds upon the excellent work of:
- yunsii/cf-worker-status-page-pro - Enhanced status page implementation
- eidam/cf-workers-status-page - Original inspiration and concept
- Vike - SSR framework for React
- Cloudflare Workers - Serverless platform
Special thanks to the open-source community for making projects like this possible! π
Made with β€οΈ using Cloudflare Workers, React, and TypeScript