A web-based tool for scanning websites for Klaviyo and Customer Hub code snippets, built on Cloudflare Workers with D1 database and Queues for parallel processing.
The application runs entirely on Cloudflare Workers:
- Web Dashboard — served by the Worker at
/, shows runs, progress, and results - Dispatcher — triggered by "Run Scan" button, pushes URLs to a Cloudflare Queue
- Scanner (queue consumer) — processes URLs in parallel batches, checks for snippets, writes results to D1
- Cron Trigger — runs every minute, detects completed runs and sends email notifications via Resend
workers/ # Cloudflare Workers project
├── src/
│ ├── index.ts # Main router (fetch, queue, scheduled handlers)
│ ├── dashboard.ts # HTML/CSS/JS for the web dashboard
│ ├── dispatcher.ts # Scan run dispatcher (pushes to queue)
│ ├── scanner.ts # Queue consumer (fetches URLs, checks snippets)
│ ├── cron.ts # Completion detection + email notification
│ ├── snippets.ts # Snippet definitions (shared constants)
│ └── types.ts # TypeScript type definitions
├── scripts/
│ └── import-urls.ts # Script to bulk-import URLs from sites.txt
├── schema.sql # D1 database schema
├── wrangler.toml # Cloudflare Workers configuration
├── package.json
└── tsconfig.json
- urls — master list of URLs to scan (id, url, created_at)
- runs — scan runs (id, status, total_urls, completed_urls, started/completed timestamps, notification_sent)
- results — per-URL per-run results (9 snippet columns + error + checked_at)
klaviyo-email-marketing-smscustomerhubcustomer-hub-datawindow.customerHub<a href="#k-hub"node.href="#k-hub"customer-hub-replace-linksfunction replaceAccountLinks()klaviyo
GET /— Dashboard HTMLGET /api/runs— List all runs with URL countPOST /api/run— Start a new scan runGET /api/results/:runId— Get paginated results + stats for a runGET /api/status?runId=...— Get status of a specific runPOST /api/urls/upload— Bulk upload URLs (JSON body:{urls: [...]})POST /api/cron/trigger— Manually trigger cron handler (for local dev)
Local dev uses wrangler dev with Miniflare for simulated D1 and Queues.
cd workers
npx wrangler d1 execute snippet-checker-db --local --file=./schema.sql # Init DB
npx wrangler dev --port 5000 --local --ip 0.0.0.0 # Start dev serverwrangler login— authenticate with Cloudflarewrangler d1 create snippet-checker-db— create the D1 database- Update
database_idinwrangler.tomlwith the real ID wrangler d1 execute snippet-checker-db --remote --file=./schema.sql— run migrationswrangler secret put RESEND_API_KEY— set email API keywrangler secret put NOTIFICATION_EMAIL— set notification emailwrangler deploy— deploy the Worker
wrangler— Cloudflare CLI for dev/deploy@cloudflare/workers-types— TypeScript typestypescript— TypeScript compiler
- Start application:
cd workers && npx wrangler dev --port 5000 --local --ip 0.0.0.0(webview)
- Node.js 20 (Workers development)