Case Study 07 · Marketing Operations
One dashboard-controlled Cloudflare Worker that replaced a fleet of roughly forty near-identical automation flows, one per lead campaign, each carrying its own hardcoded caller list, rotation counter, and Discord notification map that had to be edited by hand every time something changed.
The Problem
Every Facebook lead form fed its own tab in a central spreadsheet, and every tab had its own dedicated automation flow: a trigger, phone and grade formatting, a caller-rotation step, record creation across two CRM bases, a repeat-signup check, a mailing list sync, and a Discord notification. Multiplied across campaigns, general trial classes, subject-specific classes, writing programs, book promotions, this became a fleet of roughly forty tabs that all had to be maintained one at a time.
The list of closers who receive leads was hardcoded inside every flow in three separate places: a rotation array, and a closer-to-Discord-ID lookup map duplicated across two independent notification branches. Adding a closer, removing one, or pausing someone for a week meant repeating the same three edits across every rotating flow. If one Discord map was missed while the rotation array was updated, a lead would be assigned to the new person and recorded in the database with nobody pinged to call it, a failure invisible until someone noticed silence.
Before
After
The Lead Journey
A single Apps Script watches the entire spreadsheet across all tabs and posts new rows to the worker's ingest endpoint. From there, one pipeline runs the same six steps for every lead, regardless of which campaign it came from.
01
Detect
02
Normalise
03
Match
04
Decide Owner
05
Sync Systems
06
Notify
The Architecture
The entire fleet of flows collapsed into a single Cloudflare Worker governed by one self-serve dashboard, with every previously-hardcoded value turned into editable configuration stored in a database. One Apps Script watches all tabs, with a five-minute timed sweep as a safety net. New tabs need zero setup.
The worker resolves an incoming tab to a configured source. Matching is exact first, then longest-prefix, so a source saved under a form's base name automatically catches every future Meta re-version suffix without any change. Unknown tabs surface in the dashboard as unconfigured. Paused sources log their arrivals without processing them, so nothing is invisible.
Fields are read by header name rather than column position, so a form with an extra question no longer shifts every downstream mapping. Phone numbers are normalised to local format, year levels to a standard form, before anything else touches the record.
The family is looked up in the contact master by email OR phone, with tolerant last-digits matching. A parent enquiring with a new phone number but the same email is still found, protecting the one-row-per-family rule that phone-only matching had been quietly violating.
The caller is decided a single time, then written to every destination: the campaign's intake table, the central all-leads table, the CRM, and the Discord mention all carry the same name by construction. The class of bug where the tables said one closer and Discord pinged another is structurally impossible.
For an active source, the pipeline runs the repeat-signup check and stamps history onto the record, upserts the CRM contact with tags merged and never duplicated, upserts and tags the contact in the mailing platform, and posts to the campaign's Discord channel with a prominent warning block if the family has signed up before or already received a free class.
The Ownership Fix
The most painful symptom surfaced on a team call: two closers were sometimes chasing the same family. A parent might sign up for a trial class twice, rotating to two different closers. Worse, a parent already being worked as a WhatsApp lead, someone the closer had called and built rapport with, would later click a Facebook ad and get re-rolled to a colleague by an automation blind to existing ownership.
The fix became a per-source toggle: keep the existing owner on repeat contact. When enabled, the worker checks the matched CRM contact before rotating. If the recorded owner is an active closer in the registry, that closer keeps the lead, no re-roll, no overwrite, the rotation counter isn't even consumed, and the Discord ping goes to the existing owner with the repeat warning attached so they know their parent has re-engaged.
The check is deliberately conditional on the owner being active. A contact owned by a closer who has since left the team is treated as unowned and re-enters the live rotation. When a closer departs, toggling them off in the registry is the entire offboarding process, their historical records stay untouched, and their families are naturally reassigned as they next make contact.
Every occurrence is visible in the log as "kept existing owner". The exact scenario the closer raised, her WhatsApp parent re-routed to a colleague by a trial-class ad, is resolved by design, not by a one-off patch.
The Dashboard
A single password-protected page, in the business's own branding, with four sections covering everything that used to require opening the automation platform and editing flows one by one.
Closers registry
Name, Discord ID, sort order, active toggle. Adding a closer once here makes them available to every lead source. Toggling someone off removes them from all rotations instantly. The header shows live state: next caller, active pool, counter position.
Sources, one per campaign
An unconfigured tab appears as a clickable button in a banner. One click opens a prefilled form reading the tab's actual column headers, presented as dropdowns with the correct picks auto-detected. A duplicate button clones a configured campaign, and a test-channel button verifies the Discord bot can post before going live.
Live log
Every lead that has ever hit the worker, newest first, with status (ok, paused, error, unconfigured), extracted contact details, assigned caller, and diagnostic notes such as "kept existing owner" or "repeat warning shown". Failures preserve the raw row for replay.
Settings
The shared rotation counter is adjustable, so the next lead can be steered to a specific closer, and the grade year is bumped once at annual rollover instead of edited inside dozens of code steps.
Auto-filled source creation
Every logged lead carries its header row, so the source-creation form reads real columns and pre-selects the right fields, validated against real form exports. Subject-specific forms without a class question use a fixed-value option typed once, flowing into every table, the CRM, and Discord automatically.
Everything editable per source
Field maps, record tags, mailing list and tag, Discord channel and title line, repeat-check and keep-owner toggles, all live on the same page a non-developer can operate, with no flow cloning, no trigger wiring, and no code.
Safety and Migration Design
The system was designed to be additive until proven. Deploying the worker changed nothing. Connecting the spreadsheet changed nothing. The first configured source shipped paused, so early leads were merely logged. Go-live was per-source: activate one campaign alongside its still-running legacy flow, compare the two systems' outputs on real leads side by side, then retire the old flow, repeated tab by tab, with the ability to pause any source instantly if something looked wrong.
The watcher script never advances its row pointer unless the worker accepts the batch. If the worker is briefly unreachable, leads wait, they do not disappear.
All credentials moved into the platform's encrypted secret store, replacing plain text values that previously travelled with every flow export shared for debugging.
Built separately from the business's existing messaging infrastructure, so lead-allocation iteration can never take down time-critical SMS reminders running elsewhere.
Reusability
A new form's first lead surfaces its tab in the dashboard automatically. One click, a glance at five auto-detected dropdowns, a tag and a title, and the campaign is live. No flow cloning, no trigger wiring, no code. The forty-tab spreadsheet went from a liability, forty triggers to maintain by hand, to an irrelevant detail: one script watches everything.
The pattern that made this work is worth naming: turn every hardcoded value into data, then put the data behind a door the operator can open. Callers, tags, channels, field mappings, table destinations, message titles, ownership rules, none of these are code decisions, they are business decisions that change weekly. The moment they moved from flow definitions into a database with a dashboard, the person who makes those decisions could also implement them instantly, without a developer in the loop.
Technical Stack
| Component | Technology | Purpose | Cost |
|---|---|---|---|
| Backend and dashboard | Cloudflare Worker (single JS file, no framework) | All logic, ingest endpoint, and the four-section operations dashboard | Free |
| State and configuration | Cloudflare D1 (SQLite) | Closer registry, source configuration, shared rotation counter, live log | Free |
| Spreadsheet watcher | Google Apps Script, one script for all tabs | Detects new rows across every tab, posts to the ingest endpoint on change plus a 5-minute sweep | Free |
| Campaign intake and central CRM | Airtable REST API, two bases | Per-campaign intake records and the central all-leads table, both stamped with the same decided caller | Existing |
| Contact master and ownership | CRM contact base, email-or-phone matching | One-row-per-family lookup, upsert with merged tags, existing-owner check for the keep-owner rule | Existing |
| Mailing list sync | Mailchimp API | Upsert and tag the contact on every lead, kept in step with the CRM | Existing |
| Team notification | Discord Bot API | Per-campaign channel routing, closer mention, and repeat-signup warning block | Existing |
Result
Rotation changes went from dozens of edits across the flow fleet to one dashboard action, taking effect on the very next lead across every campaign simultaneously. The silent-failure mode, rotation updated but the notification map forgotten, no longer exists, because there is no second place for the truth to live.
Duplicate assignments stopped by design. With the keep-owner rule enabled, a family already owned by an active closer stays with that closer across repeat signups and across lead types, because every source consults the same contact master. Contact duplication closed, since email-or-phone matching finds a family even when one identifier changes. New campaigns onboard in under a minute, and nothing disappears anymore: every lead, processed, paused, unconfigured, or errored, is logged with its raw payload.
The system earned trust by being useless at first: it shipped paused, logged everything, touched nothing, and ran side by side with the legacy flows until outputs matched on real leads. And the most valuable feature in the system did not come from an architecture review. It came from a salesperson saying, in plain words, "if it's already assigned to me, just keep it that way."