Tag: cloudflare-workers

Building serverless applications with Cloudflare Workers, D1, R2, and the edge computing platform.

  • ContentShield Pro: Building a Forensic Watermarking SaaS on Cloudflare Workers

    ContentShield Pro is a forensic watermarking SaaS I built entirely on the Cloudflare stack — no servers, no containers, no infrastructure bills — designed to answer a single question when content leaks: whose copy was it?

    That question sounds simple. The engineering behind answering it reliably is not. Most people think of watermarking as the visible stamp a stock photo agency burns into a preview image. Forensic watermarking is the opposite — the mark is invisible, unique per recipient, and designed to survive reasonable transformations like screenshots, reformatting, or re-encoding. When a document surfaces somewhere it shouldn’t, you don’t need anyone to confess. You detect the embedded fingerprint and trace it back to the specific copy you issued.

    The Architecture: Workers, D1, R2

    The entire system runs on three Cloudflare primitives. Workers handle the API layer — three endpoints do all the work. POST /watermark accepts a content payload and a recipient list, generates N uniquely watermarked versions, and returns them with their fingerprint identifiers. GET /verify accepts any copy of the content — clean or suspected leak — and extracts the embedded fingerprint. GET /trace resolves that fingerprint against the recipient mapping stored in D1 and returns the full record: who received it, when, and via which distribution channel.

    D1 is the relational backbone — it stores the watermark-to-recipient table, the distribution logs, and the webhook configurations for each client account. R2 holds the watermarked content files themselves, which can run large for image-heavy assets. The combination means I’m storing structured query data in D1 where I need joins and lookups, and binary content in R2 where I need object storage. Workers AI handles image processing at inference time. Total infrastructure cost for a system serving multiple clients: $0 per month on the Cloudflare free tier, with costs entering only at serious enterprise scale.

    Two Techniques: Text and Image

    Text watermarking in ContentShield Pro uses Unicode zero-width character sequences. Zero-width joiners, zero-width non-joiners, and zero-width spaces are invisible in rendered text but detectable programmatically. Combined with selective homoglyph substitution — replacing certain Latin characters with visually identical Unicode equivalents — each copy gets a unique binary fingerprint encoded into the character stream. A 2,000-word document can carry a 32-bit fingerprint with no visible change to any reader. The sequence is deterministic given the recipient ID, so verification doesn’t require database lookup on every character — the Worker checks the pattern against the expected encoding for any known recipient, then queries D1 only to resolve the match to a human record.

    Image watermarking uses LSB steganography in the alpha channel. The least significant bit of each pixel’s alpha value carries one bit of the fingerprint — across a 1920×1080 image, that’s 2,073,600 available carrier bits for a mark that needs fewer than 64. Workers AI handles the pixel-level processing. The mark is robust against JPEG recompression at quality settings above 85 and survives standard screenshot crops as long as the marked region is preserved. Below that threshold, the mark degrades — which is a known limitation I document in the client-facing technical spec.

    The Webhook-Based Leak Alert System

    ContentShield Pro isn’t purely reactive. When a client submits a suspected leak to /verify, the Worker extracts the fingerprint, queries D1 to resolve the recipient, and immediately fires a webhook to the client’s configured endpoint — with the full trace report as the payload. That report includes the recipient record, the distribution timestamp, the fingerprint confidence score, and a forensic hash of the submitted content for chain-of-custody documentation. The client’s incident response workflow receives a structured JSON payload the moment the trace completes, typically within 400 milliseconds of the /verify request.

    The SaaS economics here are worth stating plainly. When your infrastructure cost is near-zero — because Cloudflare Workers runs at the edge with no server provisioning — the gross margin on usage revenue is extremely high. The variable costs are D1 writes per watermarked copy generated and Workers AI inference per image processed. Text watermarking at scale costs fractions of a cent per document. That margin structure is only possible because the entire product runs on Cloudflare’s edge infrastructure — the same stack I’ve used to run 60+ Workers at $0/month across my personal and professional projects.

    What Transfers

    The forensic audit trail design principle in ContentShield Pro — every operation produces a traceable artifact — is not specific to content protection. It applies directly to AI systems in any regulated environment. Every inference a model makes should be logged: the input, the output, the model version, the timestamp, and the confidence score. Every process action an automation takes should produce a record that can be examined after the fact. The 17+ AI and automation projects I ran at Lockheed Martin all had this in common: the ones that survived audit scrutiny were the ones where every step of the pipeline was traceable. The ones that didn’t were the ones where someone assumed the output was trustworthy without capturing the evidence that would prove it.

    Forensic design isn’t about distrust — it’s about building systems that can prove their own correctness after the fact, to an audience that wasn’t in the room when you built them.

    Building something at the intersection of AI, edge computing, and behavioral science? Let’s connect.

  • OSINT at the Edge: Building a Threat Monitoring System with Cloudflare Workers

    Running meaningful threat intelligence monitoring at any scale — certificate transparency logs, domain registration alerts, threat feed normalization — costs either a commercial subscription in the thousands of dollars per month or custom infrastructure that requires active maintenance, unless you build it on Cloudflare Workers, where the entire stack runs at $0.

    I’ve covered the Digital Sentinel system overview in a previous post. This one goes deeper — into the specific data sources, the edge architecture that connects them, and the numbers that came out of running it in production against real client scope.

    Certificate Transparency: Every Certificate, Indexed in Public

    Every SSL/TLS certificate issued by a trusted Certificate Authority gets logged to public Certificate Transparency logs — crt.sh, Google Aviator, Cloudflare Nimbus, and others. This is a regulatory requirement, and it means that if someone registers a typosquatting domain and immediately obtains an HTTPS certificate for it, that certificate appears in the CT logs within minutes of issuance. Most organizations don’t have a system watching those logs for their own name patterns. They find out about impersonation domains when a customer calls.

    A Cron Trigger Worker polls the crt.sh JSON API on an hourly schedule. The worker queries for certificates issued to domains matching configurable pattern sets — brand name variants, common typosquats, executive name combinations — and filters the response against a D1 database of previously seen certificate IDs. New matches are written to D1 with full certificate metadata: issuing CA, subject alternative names, issuance timestamp, and the registrant domain. The total runtime per execution is under 800 milliseconds for a scope of approximately 40 pattern variants. Cloudflare’s free-tier Cron Triggers handle this without any cost.

    Threat Feeds: Normalization Is the Actual Work

    AlienVault OTX and AbuseIPDB both offer free API tiers with meaningful data volumes. The operational problem isn’t access — it’s normalization. OTX returns indicators in a pulse-based format with nested JSON. AbuseIPDB returns scored IP addresses with abuse category codes. Neither format matches the other, and neither maps cleanly to a schema you’d want to query for alerting logic.

    A second Worker fetches and normalizes both feeds every four hours. It extracts indicators — IPs, domains, hashes, URLs — maps them to a unified schema with source, confidence score, indicator type, and first-seen timestamp, then deduplicates against D1 before writing. Deduplication runs against a composite key of indicator value plus source, because the same IP might appear in both feeds with different confidence scores — and that delta is itself a signal worth preserving.

    Rate-limit state is tracked in KV, not D1. KV’s per-key TTL makes it the right store for ephemeral rate-window tracking — writing a counter to D1 for something that expires in 15 minutes is the wrong tool. This distinction between KV for transient state and D1 for durable records runs through every part of the architecture.

    RDAP Domain Monitoring: The WHOIS Replacement That Actually Has an API

    WHOIS is largely broken for programmatic use — rate limiting, inconsistent formatting, and increasingly redacted registrant data make it unreliable. RDAP, the Registration Data Access Protocol, is the IANA-standardized replacement. It returns structured JSON, it’s queried via HTTPS, and it works inside a Workers environment without requiring a separate proxy layer.

    The domain monitoring Worker queries RDAP endpoints for newly registered domains matching typosquat patterns — character substitutions, homoglyph variants, hyphenated versions, TLD variations — and stores registration records in D1. In the first month of running this against a client’s brand scope, the system identified three domains that had been registered with clear impersonation intent: two used homoglyph substitutions in the brand name, one combined the brand name with a plausible-sounding financial suffix. None had been caught by any other monitoring the client had in place.

    The Alerting Pipeline: From Detection to Discord in Under 90 Seconds

    All three monitors — CT logs, threat feeds, and RDAP — write findings to a shared D1 table with a processed flag. A fourth Worker, AlertDispatch, runs on a two-minute Cron Trigger, queries for unprocessed records, enriches each finding with contextual data from KV, formats a Discord embed with severity color coding and direct links to supporting sources, and POSTs to a configured webhook. End-to-end alert latency from detection event to Discord notification runs under 90 seconds in normal operation.

    The system currently processes approximately 47,000 CT log entries daily across active client scope. The false positive rate — certificates that match patterns but aren’t actual threats — runs at about 4%, which is low enough that analysts review every alert rather than implementing suppression rules. Keeping the false positive rate manageable required iterative refinement of the pattern matching logic over the first six weeks; the initial version was closer to 18%.

    What Transfers

    The architectural pattern here — scheduled edge Workers feeding a central D1 store, KV for rate control and transient state, a dispatch Worker for enrichment and notification — applies to any event-driven monitoring use case that doesn’t require persistent server processes. Price monitoring, compliance change detection, API health surveillance, social mention tracking: the structure is the same. The zero-cost operation isn’t incidental to the design. It’s the reason this architecture is worth understanding — it puts monitoring capability that used to require dedicated infrastructure into a pattern any developer can deploy and maintain solo. That’s the broader lesson from running 60+ Cloudflare Workers in production: the constraint that keeps most teams from building this kind of tooling isn’t technical complexity. It’s the assumption that it requires budget they don’t have.

    Building something at the intersection of AI, edge computing, and behavioral science? Let’s connect.

  • Durable Objects vs. D1: Choosing the Right State Layer for Your Cloudflare App

    I have 60 Cloudflare Workers in production and I’ve made the wrong choice between Durable Objects and D1 exactly once — it cost me two days of refactoring, which is cheap tuition for a lesson that now shapes every architectural decision I make on the edge. The confusion is understandable: both technologies persist state, both live at the edge, and both are positioned as solutions to the “stateless Worker” problem. But they solve fundamentally different problems, and choosing the wrong one doesn’t just make your code awkward — it makes your cost model and your correctness guarantees both wrong.

    What D1 Actually Is

    D1 is SQLite at the edge — a relational database you query with standard SQL, replicated globally by Cloudflare, accessed via a binding in your Worker. It behaves like a database because it is a database. You write a query, you get rows back, you have transactions, foreign keys, indexes, and all the relational primitives you’d expect. The replication model means reads can be served from the nearest replica and writes go to the primary with propagation to replicas on a short delay — which is the standard read-your-writes trade-off that any distributed database makes. D1 is the right tool for any workload that looks like a database workload: multi-tenant CRUD applications, analytics queries over structured records, any situation where you have a schema and you want to query it with SQL. In my fleet, FinRec — the personal finance PWA I built and described in detail in my post on building a finance PWA on Cloudflare Workers — runs entirely on D1. Every transaction record, every account, every budget category lives in a D1 database with a proper schema. The queries are straightforward SQL: SELECT transactions WHERE account_id = ? AND date > ? ORDER BY date DESC. D1 handles that workload with sub-10ms query times and no coordination complexity whatsoever.

    What Durable Objects Actually Are

    A Durable Object is not a database — it’s a stateful actor. A single instance of a Durable Object exists at exactly one location in Cloudflare’s network at any given time, and all requests to that object are serialized through that single instance. That serialization guarantee is the entire point: it means you can do things that are impossible with a replicated database, like maintaining an exactly-once counter, coordinating real-time state between multiple WebSocket connections, or enforcing a rate limit that is globally consistent rather than per-region consistent. The storage that a Durable Object has access to is key-value storage local to that instance — fast, strongly consistent, but not SQL, not queryable in aggregate, and not shareable across object instances. You don’t query a Durable Object the way you query D1; you send it a message and it responds, maintaining its own internal state between messages. In my fleet, the career intelligence dashboard at jobs.groundedintelligences.com uses Durable Objects for rate limiting inbound API calls — each rate limiter is a Durable Object instance keyed to a specific API client, and because all requests from that client route to the same object instance, the counter is always accurate with no race conditions. The OSINT monitoring system in my fleet uses KV for caching external feed responses and D1 for structured event storage — cert transparency log entries, threat feed matches, and alert history all go into D1 with timestamps and source metadata, making them queryable for trend analysis and auditing.

    The Key Distinction and the Cost Reality

    The cleanest mental model for choosing between them: D1 is a database you query; a Durable Object is a stateful actor you message. If your use case involves retrieving or storing structured records that multiple users or processes access independently, you want D1. If your use case involves coordinating state across concurrent requests where order and consistency matter at the request level — not just the transaction level — you want Durable Objects. The cost difference reinforces this. D1 charges per query at very low rates — roughly $0.001 per million read queries on the paid plan, with generous free tier allocations. Durable Objects charge per incoming request and per second of active duration — which means a long-running WebSocket connection or a frequently-polled coordination object accumulates duration costs that a D1 query workload never would. For short-lived stateful operations like rate limiting or session coordination, Durable Objects are cost-effective. For always-on, high-request-volume coordination, the duration billing adds up in ways that aren’t immediately obvious when you’re designing the system.

    The Mistake Most Builders Make

    The most common error I see in Cloudflare architecture discussions is reaching for Durable Objects when D1 would be correct, because Durable Objects sound more powerful and technically interesting. They are more complex — which is not the same thing as more powerful for every problem. If you need to store and retrieve user records for a SaaS application, Durable Objects give you single-instance serialization and key-value storage for a problem that just needs a relational database. You’ll end up implementing your own query layer on top of Durable Object storage, fighting the absence of joins and indexes, and paying duration costs for object instances that are essentially just holding data that D1 would serve faster. This was the mistake I made in the project that cost me two days of refactoring — I used Durable Objects for structured data storage because I was experimenting with the technology, and I spent those two days rewriting to D1 once the query requirements became clear. The technology is genuinely impressive and there are workloads it handles better than anything else — real-time collaborative editing, game state, presence systems, exactly-once processing pipelines. Those are real use cases. Storing user profile records is not one of them.

    What Transfers

    The stateful actor versus relational database distinction exists in every distributed system — this is not a Cloudflare-specific decision. Erlang has had the actor model since the 1980s. Akka brings it to the JVM. Orleans brings it to .NET. Every implementation of the actor pattern makes the same trade-off: strong per-actor consistency and message serialization, at the cost of aggregate queryability and shared state. The relational database makes the opposite trade-off: powerful query capabilities and shared state, at the cost of per-record coordination guarantees. Understanding which trade-off your workload actually requires is the architectural judgment call — and it’s easier to make clearly when you’re not choosing between two products on a pricing page but instead asking the underlying question: do I need to query this data, or do I need to coordinate around it?

    Building something at the intersection of AI, edge computing, and behavioral science? Let’s connect.

  • How I Built and Run a 60-Worker Cloudflare Fleet on $0/Month

    I run 60 production Cloudflare Workers for $0 per month — the only thing I pay is roughly $12 a year for a domain name. That’s not a development environment or a hobby experiment; that’s a fleet of real applications handling authentication, SQL queries, OSINT monitoring, AI inference, and job-matching logic, all running at the edge with no servers to manage and no cloud bill showing up at the end of the month.

    What the Free Tier Actually Gives You

    Cloudflare’s free tier is generous in ways that most people don’t fully appreciate until they map their workloads against the actual limits. Each Worker gets 100,000 requests per day — not per account, per worker — before you hit any throttle. D1, Cloudflare’s SQLite-at-the-edge product, gives you 5GB of storage and 25 million reads per day at no cost. KV gives you 100,000 reads per day. R2 gives you 10GB of object storage, 1 million Class A operations, and 10 million Class B operations monthly. Workers AI gives you 10,000 neurons per day on the free plan — enough to run real inference tasks at modest volume. Stack those together and you have a full-stack compute and storage platform that would run $200 to $400 a month on AWS if you tried to replicate it with Lambda, RDS, ElastiCache, and S3.

    The Architecture That Makes It Work

    The design principle behind the fleet is stateless compute paired with durable storage — the Worker itself holds no state between requests, which means cold starts are measured in microseconds rather than seconds, and horizontal scaling is automatic. Workers handle request routing, business logic, authentication, and API composition. D1 handles anything that needs relational structure and SQL queries. KV handles read-heavy caching where eventual consistency is acceptable — configuration values, session tokens, rate-limit counters. R2 holds files, exports, and anything that would otherwise require a file system. Workers AI sits at the inference layer, running models like LLaMA 3 without me spinning up a GPU instance. The whole architecture collapses the traditional web stack into a single deploy surface with one CLI command.

    Three Workers That Show the Range

    FinRec is my personal finance PWA — it runs entirely on Workers and D1, with a React front end served from Workers’ static asset hosting and a SQL backend running on D1. Every transaction, category, and account record lives in a D1 database. I wrote about the full build process in detail in this post on building FinRec. The application handles multi-user data with row-level scoping in SQL, processes hundreds of transactions without latency issues, and costs nothing beyond the domain. Digital Sentinel is my OSINT monitoring system — it uses Cron Triggers to run scheduled jobs every 15 minutes, polling certificate transparency logs and threat intelligence feeds, then routing alerts to a Discord webhook when it finds something worth flagging. There’s no always-on server; the Cron Trigger fires the Worker on schedule, the Worker runs its checks, and then it’s gone until the next cycle. I covered the full architecture in my post on building the OSINT monitoring system. The third is daniel-job-search, the career intelligence dashboard running at jobs.groundedintelligences.com — it uses Workers AI to run job-matching inference against my criteria, scoring inbound postings and surfacing the highest-signal opportunities. The AI layer runs on LLaMA 3 via Workers AI, the results are stored in D1, and the front end is a PWA served from the same Worker.

    The Deployment Workflow

    Every worker in the fleet deploys from a wrangler.toml file that specifies the worker name, the account ID, any KV namespace bindings, D1 database bindings, and R2 bucket bindings. Wrangler CLI handles the rest — one command, wrangler deploy, pushes the compiled Worker to Cloudflare’s edge network and it’s live globally within about 15 seconds. There’s no container to build, no cluster to update, no load balancer to reconfigure. The development loop is tight: wrangler dev runs a local emulator that mirrors the production environment closely enough that production surprises are rare. When I need to rotate a secret, wrangler secret put writes it to Cloudflare’s secret store without it ever appearing in my codebase or environment files. Across 60 workers, this workflow stays manageable because each worker is a small, focused piece of logic — nothing in the fleet exceeds about 400 lines of TypeScript.

    What Transfers

    The architecture principles here are not Cloudflare-specific — they’re the underlying logic of serverless-first design applied to any provider. Stateless compute paired with durable storage is a pattern that works on AWS Lambda with DynamoDB, on Fastly Compute with Upstash, or on any platform that separates the execution layer from the persistence layer. The key insight is that infrastructure ownership is the most expensive part of running software — not in dollar terms, but in cognitive overhead, operational burden, and the time you spend keeping things running instead of building. When you design systems where you own the code and the platform owns the infrastructure, you get back the mental bandwidth to actually work on the problem. The $0/month bill is a side effect of that design choice, not the goal. The goal is a system that does real work, stays maintainable, and doesn’t require a 2 AM pager rotation to keep alive.

    Where the $0 fleet stops working: media

    The one workload this architecture will not absorb is media at volume. Cloudflare explicitly prohibits streaming video on Free, Pro and Business plans — you are expected to move to Cloudflare Stream or Enterprise — and once you are storing tens of gigabytes and serving them repeatedly, the free tier stops being the right answer regardless of how the compute is structured.

    I recently split a media pipeline along exactly this line: the control plane — D1 index, Workers AI tagging, the ranking API — stayed on Cloudflare, and the data plane — 41 GB of originals, rendered variants and video — moved to bunny.net. Storage runs about $0.01–$0.02/GB and bandwidth $0.005/GB in North America and Europe, with no free tier to age out of and no per-plan content restrictions to trip over. The interesting part is that the split is architecturally cleaner than the monolith was: metadata and logic in one place, bytes in another, and the boundary is a signed URL.

    The bunny.net link above is an affiliate link — I earn a commission if you sign up, at no additional cost to you. I pay for the service myself and would recommend it regardless.

    Building something at the intersection of AI, edge computing, and behavioral science? Let’s connect.

  • Building an OSINT Monitoring System on the Edge with Cloudflare Workers

    Building an OSINT Monitoring System on the Edge with Cloudflare Workers

    One of the less visible but most practical systems in my Cloudflare Workers fleet is Digital Sentinel — a set of OSINT (Open Source Intelligence) monitoring pipelines that scan certificate transparency logs, threat intelligence feeds, and domain registration activity, then fire automated chat alerts when something interesting shows up.

    What It Monitors

    The system pulls from multiple sources: certificate-transparency logs (catching new SSL certificates issued for domains I care about), threat-intelligence feeds for SEO and competitive-intelligence signals, URL-analysis services for malicious-URL detection, and additional threat-intelligence feeds for enrichment. Each source has its own dedicated Worker that runs on a cron schedule, queries the API, diffs against the last known state in D1, and posts alerts for anything new.

    The Architecture Pattern

    Each monitoring pipeline follows the same pattern: a cron-triggered Worker fetches data from an external API, compares it against a D1 table of previously seen items (deduplication by hash), persists new items, and sends a formatted automated chat alert for anything that crosses a threshold. The pattern is simple enough to replicate for any data source in about 30 minutes.

    What makes this interesting as an engineering exercise is the constraint set. Cloudflare Workers have a 30-second execution limit on cron triggers, so the pipelines have to be efficient — no long-running batch jobs, no streaming connections. D1’s SQLite engine handles the state management cleanly, and the Workers runtime’s built-in fetch makes external API calls trivial.

    Why This Matters

    For personal security monitoring, this system provides continuous visibility into certificate issuance, domain impersonation attempts, and threat-intel signals that would otherwise require a paid SIEM or manual checking. For my portfolio, it demonstrates the ability to build event-driven monitoring systems on modern edge infrastructure — the same pattern that scales to enterprise OSINT, brand protection, and security operations.

    The full system runs alongside 60+ other Workers in my Cloudflare fleet, all orchestrated by a meta-orchestrator that monitors the health of the entire platform and self-heals when individual Workers encounter issues.

    See more on my Projects page, or get in touch to discuss edge-native monitoring architectures.

  • Building a Personal Finance PWA on Cloudflare Workers

    Building a Personal Finance PWA on Cloudflare Workers

    One of the engineering projects I’m most proud of is FinRec — a full-featured personal finance progressive web app running entirely on Cloudflare Workers with D1 as the database layer. No traditional server. No monthly hosting bill beyond Cloudflare’s generous free tier. Just edge-deployed JavaScript serving a complete financial dashboard.

    The Architecture

    FinRec is built as a single Cloudflare Worker that serves both the PWA frontend and the API backend. The frontend is a service-worker-cached progressive web app with offline support, installable on any device. The backend routes API calls to a D1 SQLite database that stores net-worth snapshots, a normalized ledger, a document ingestion queue, and health-monitoring data.

    The key insight was treating the Worker as a full application server. A single fetch handler routes between static assets (/sw.js, /manifest.json), the login page, the main SPA shell, and a dozen API endpoints — all from one deployment artifact.

    What It Does

    The dashboard has four tabs: Overview (net worth tracking with daily snapshots, asset/liability breakdown, orchestrator health monitoring), Ledger (full transaction history with month/type/search filtering), Documents (an AI-powered document ingestion queue that classifies uploaded financial documents, extracts vendor/amount/date, and flags items needing review), and Advisor (a CFO-level financial briefing generator that produces weekly reports and saves them to Google Drive).

    The Supporting Fleet

    FinRec doesn’t operate alone. It’s the dashboard layer for a larger fleet of 60+ Cloudflare Workers that handle data ingestion, classification, and orchestration. These include OAuth 2.0 token capture workers, cron-triggered financial data sync pipelines, Gmail and Google Drive ingest workers, a transaction classifier/trainer, a document processor, ledger normalizer, and a meta-orchestrator that monitors the health of the entire system.

    Why Cloudflare Workers

    The edge deployment model means every API call resolves at the nearest Cloudflare data center. D1’s SQLite-on-the-edge gives me ACID transactions without managing a database server. R2 provides S3-compatible object storage for document uploads. And the whole thing costs effectively nothing to operate at personal scale.

    For engineers evaluating where to host side projects and internal tools, I’d argue that Cloudflare Workers + D1 + R2 is the most underappreciated full-stack platform available today. The developer experience is excellent, the deployment model eliminates infrastructure management, and the performance characteristics are hard to beat.

    This is one project in a larger portfolio. See the full list on my Projects page.