Lead SystemsGuides

A checklist for automating lead intake without losing leads

Lead intake is the workflow most often automated first and most often automated badly. A checklist for the parts that decide whether an inquiry survives the trip.

DevLab StudiosJul 11, 20264 min read
Lead IntakeCRMAutomation Design

Lead Systems

A checklist for automating lead intake without losing leads

The failure nobody sees

A lead intake system fails silently more often than loudly. The form submits, the visitor sees a success message, and the inquiry never arrives anywhere. Nobody complains, because the person who would complain does not know it happened, and the business only notices as a vague sense that the site is not converting.

Everything below exists to make that failure impossible or at least loud.

Persist before you deliver

This is the single most important structural decision. Write the submission to your own storage first, synchronously, and decide the visitor's success message from that write. Only then attempt to deliver it onward — to a CRM, an email, a webhook, whatever.

The reason is that every downstream system will be unavailable at some point. If the visitor's confirmation depends on the CRM accepting the record, then a CRM outage becomes a lost lead. If it depends only on your own write, a CRM outage becomes a queued delivery you can retry.

  • Validate the input
  • Write it to storage
  • Respond to the visitor
  • Attempt delivery in the background
  • Record the outcome of every attempt

Validate on the server, whatever the form does

Client-side validation is a convenience for the visitor. It is not a control. Anything that can be submitted from a browser can be submitted without one, so the same schema has to run on the server, and the server's answer is the one that counts.

Sharing one schema definition between the form and the endpoint is worth the small amount of setup. It means the rules cannot drift apart, and a field added in one place cannot be silently ignored in the other.

Record every delivery attempt, not just the last one

A single status column — delivered or failed — throws away the information you need when something is wrong. Keep a row per attempt with the timestamp, the target, the response, and a category for the failure.

The category matters more than it sounds. A transient failure (timeout, rate limit, 5xx) should be retried. A permanent one (malformed payload, rejected address, revoked credential) should not — retrying it just burns attempts and hides the real problem. A configuration failure (missing API key) is a third thing again: it means nothing will ever succeed until a person changes something.

Make duplicates impossible rather than unlikely

Retries, double-clicks, and browser refreshes all produce the same submission twice. Rather than trying to prevent that at the edges, give each submission a key derived from its own content — the type, the sender, the message, and a coarse time bucket — and make that key unique in storage.

The second submission then collapses into the first by construction. This is much more reliable than debouncing a button.

Decide what happens to spam before it arrives

Some proportion of submissions will be automated. A challenge widget handles most of it, a rate limit handles bursts, and a length cap on the request body handles the rest. None of these should be able to reject a real inquiry, which means each needs a decision about what happens when the control itself is unavailable.

A rate limiter that fails closed will eventually take your contact form offline during an unrelated outage. One that fails open will briefly stop counting. For an intake form, failing open is usually the right trade — but it should be a decision someone made, not an accident.

Confirm the path end to end, in production, on purpose

The last item on the checklist is the one most often skipped: submit a real inquiry through the real form on the real site, and follow it all the way to where it is supposed to land. Do this after every change to the pipeline.

An intake system that has never been tested end to end is not a system. It is a hypothesis.

Decide what the visitor is told, and when

The confirmation message is part of the system's contract, not a decoration. "Thanks, we'll be in touch" implies a person will see this. If delivery failed silently and nobody does, the message was a promise the system did not keep.

Say what is true at the moment you say it. If the submission is stored and a person reviews it within a working day, say that. If an automated reply is coming, say so and say roughly when. Vague reassurance is worse than a specific modest claim, because a specific claim can be verified and a vague one quietly erodes trust when it turns out to be untrue.

Keep the raw submission, not only the parsed one

Normalizing input is necessary — trimming, formatting phone numbers, mapping a free-text field onto a known set. Keep what was actually typed as well.

When something looks wrong three weeks later, the question is almost always "what did they actually send us", and a normalized record cannot answer it. The storage cost is trivial. The alternative is reconstructing intent from a value that has already been through two transformations.

Instrument the funnel across the seam

Page analytics tell you how many people submitted. Pipeline logs tell you how many records were delivered. Neither answers the question that matters: of the people who tried, how many became something a person acted on?

Carry one identifier from the form through to the delivery record. Without it a drop-off between the two halves is invisible, because each side reports itself as healthy and neither can see the other.

Review the failures on a schedule, not on complaint

Put a recurring slot in the calendar to look at the failed and pending records. Ten minutes a fortnight is enough.

This is the control that catches everything the other items miss — the failure nobody anticipated, the upstream that started rejecting a field, the gradual rise in one error type. Intake systems do not usually break all at once. They develop a small persistent leak, and the only thing that finds a leak is someone looking.