I build the connective tissue between CRMs, databases and outreach systems — the syncs, pipelines and background jobs that move your data without anyone touching a spreadsheet.
A typical build — running on a schedule, unattended.
Two systems hold the same records and neither agrees with the other. I build the sync that settles it, with the edge cases handled and a log you can read.
It worked at 200 rows. At 20,000 it's slow, fragile and one accidental sort away from a bad afternoon. I move it to a real backend without losing the workflow your team already knows.
Someone manually enrolling contacts, checking suppression lists, copying sequence names between tools. That's a job for a scheduled function, not a person.
When a contact moves to a new company, they become a warm lead at a cold account — but only for a few weeks. I built the detection and the automatic enrollment behind it: monitor the contact set for role changes, verify the move, and drop the person into the right sequence without anyone watching a feed.
A structured database of prospects built from enrichment APIs rather than bought lists — profiles resolved and deduplicated, firmographics attached, and lookalike sets derived from accounts that already closed. Includes total-addressable-market analysis to size a segment before anyone spends on it.
Most automation fails silently — an API runs out of credits, a sync stops, and nobody notices for a week. I consolidated scattered alerts into a single channel and built a credit-usage dashboard that posts to Slack before the balance runs out, so the failure arrives as a warning rather than a missing month of data.
Once you have a dozen background functions, you need to know what runs when, what depends on what, and how to switch one off without redeploying. I build that as a managed trigger table — the schedule becomes data you can edit, not code you have to touch.
Booking events captured at the source, enriched with firmographic data, and sent back to Google Ads and Meta as conversions with a value attached — so the platforms optimise toward the leads worth having instead of counting every form fill the same.
An operations system that lived in linked Google Sheets, rebuilt on a real backend — deal data synced from the CRM, hours pulled from time tracking, and derived views that used to be recalculated by hand each morning now computed on a schedule.
Alongside project work, I handle a standing queue for a consultancy serving nonprofit and B2B clients — CRM builds, data cleanups and workflow automation, delivered ticket by ticket over several years.
Built out the pipelines a fundraising team actually runs on — solicitation, pledged, donated, and acknowledgement stages — each with its own automation and reporting, replacing an inconsistent setup where gifts were tracked differently depending on who entered them.
Events, programs and outreach modules that had accumulated unused fields, dead workflows and duplicate records — audited, simplified and documented so the team could find what they needed without asking someone.
Annual campaign follow-up broken into phases with dependent deadlines, so each stage unlocks when the previous one completes rather than relying on someone remembering the sequence. Same pattern applied to recurring donor engagement tasks.
Signature workflows with fields pre-filled from existing records, and intake forms that write directly into the CRM instead of arriving as email to be retyped.
Project management systems are good at holding work and bad at reporting on it. I move that data out on a schedule — into spreadsheets or a database — and push structured records back in, so status reporting stops being a manual export.
A ticket is rarely "add a field". It's usually a process someone has been holding together from memory. These are ten of them, described without client names.
A pledge is a promise with a date on it, and the date is the part that gets lost. I split solicitation, pledges and received donations into separate pipelines that hand records to each other: commit to a pledge and the record is created with donor, family, campaign and solicitor already carried across. A week before the expected date it moves itself to reminder needed and a task lands on the solicitor. Thirty days past it with no payment, it's marked lapsed rather than sitting at 80% forever.
Outreach staff were tracking relationships in task notes, so the history disappeared the moment a task was closed. I built a separate module for things that actually happened — a meal, a call, an event attended, a class — linked to the person, the household, the case manager and the event it came from. Tasks stayed what they are: future actions. Each case manager got a caseload view filtered to their own people and a next-seven-days follow-up list, so the contact record became the only screen they need open.
Family registration arrived as a form and left as retyping — a household, a parent, one record per child, and an enrolment to open. I mapped a single submission with a repeating child section onto all four, matched returning families on email so they update instead of duplicating, and gated the enrolment: it can't advance to registered until every child attached to it has verified forms. One child or five, the rule is the same.
The numbers existed, but every figure was rolling, so nobody could tell whether this week was better than last. I rebuilt the reporting around fixed periods — one snapshot tab per department, one trend view for the company — around metrics that are actually decisions: quoting turnaround in days, quote-to-job conversion, percentage of enquiries followed up, revenue per team day attended, and an aging view of invoices more than thirty days due.
Years of additions had left automations referencing deleted fields, two rules writing to the same one, and a scheduling job creating a duplicate record every time it fired. I audited every automation across three solutions, removed the broken and the redundant, and made the record-creating ones check for an existing link first — update if it's there, create if it isn't. Then I tested the assignment-to-report-to-project chain end to end and documented what remained in a sheet the client can actually read.
Quotes that go quiet clog a pipeline and turn every conversion number into a lie. Now a sales record with its follow-ups done and no movement for 24 hours, or a repair sitting at terms sent for 72, copies itself into a nurture board with the client, address and a link back to the original, and leaves the pipeline. The nurture board tracks the last visit, call and seasonal email and calculates who's due next — so dormant accounts get a touchpoint instead of a reminder nobody opens.
A won sale used to be re-entered by hand into production, and each shop stage was tracked wherever it happened to be tracked. I wired the handoffs: a sale marked won opens a confirmed project carrying scope, drawings, install dates and estimate; ready for finishing opens a finishing record with its own inspection checklist; completing it pushes the parent project forward and opens the next stage. Touch-ups notify the project manager when done, and a completed install opens a photography record so finished work actually gets shot.
Pricing lived in the owner's head and in a sheet of model numbers whose scheme encoded material, width, depth and height. I turned it into a structured catalogue — cabinets, doors, drawers, shelves, panels, mouldings and columns, each with its own pricing unit, per square foot, per linear foot or per piece — so a salesperson builds an estimate by selecting real parts. What comes out is a model-number list the drafter works from directly, instead of a quote that has to be translated.
A one-person studio didn't want to learn a CRM, so I built one inside the tool she already used. A dashboard is the only sheet she touches; the data sits in a hidden one behind it. Clicking send intake emails a pre-filled form; the submission creates the client's Drive folder, duplicates the contract template, merges in their name, budget and rooms in scope, writes the folder link back to the record and advances the status. Buttons lock after firing, so nobody gets the same email twice.
Signing a new facility meant typing the same entity details into an order form, an exhibit and an invoice. I mapped the signature documents back to the CRM — parent entity, state, address and signer on the order form; each facility's trading name, entity and monthly fee on the exhibit — and set up the subscription products behind it, with tiered pricing per facility type, room for a custom discount, and billing anchored to the month credentials go out. Contract signed now provisions the customer and a draft invoice in the accounting system, with the link written back to the record.
Send over the problem and I'll tell you how I'd approach it and what it would cost. Most projects are fixed-price and take a week or two.
Start a conversation →