Evalgent
Back to Blog
Voice AI Testing

AI Receptionist for Roofers: Why Storm Leads Get Lost

Deepesh Jayal
16 min read
AI Receptionist for Roofers: Why Storm Leads Get Lost
On this page

A hail line crosses three ZIP codes at 7 p.m. By midnight your platform's roofing customers have taken hundreds of calls. The dashboard says "100% answered." Nobody can say how many homeowners called and never became a usable lead.

This post is for product teams at roofing CRM and field software companies. Many sell an AI answering service for roofers as a feature. Inspection booking under surge is covered in our post on testing roof inspection booking before storm season. This one covers lead capture: why storm leads get lost, and how to measure and test it.

Hundreds
Daily calls at one Missouri roofer after an April 2026 hailstorm, up from "a handful" (KY3)
25.65%
Best joint goal accuracy on 249 hours of spoken task dialogues (SpokenWOZ, arXiv 2305.13040)
0.43%
Joint goal accuracy of a text-trained tracker on spoken DSTC10 data, vs 54.27% on written (arXiv 2109.13489)
~1%
Whisper transcriptions containing hallucinated text (Careless Whisper, arXiv 2402.08021)

Where a storm lead actually gets lost

Storm surge is real and sudden. After an April 28, 2026 hailstorm in the Ozarks, one roofing owner told KY3 he went from "a handful of calls each day" to "hundreds of phone calls a day." His inspection lead time grew to two to three weeks. For that long, the lead record is the only thread back to the homeowner.

The call is the front door to a five-step workflow:

1. Capture. Name, callback number, address, damage, insurance status.

2. Create. A lead record is written to the CRM.

3. Route. The lead lands with the right sales territory or rep.

4. Confirm. The caller hears what happens next.

5. Follow up. A human or an outbound call works the lead.

A lead can fail at any step while the call sounds fine. The caller hears "Someone will call you back today." That sentence plays whether the lead was saved correctly, saved wrong, or never saved. It is the capture-to-write-back chain from our home services QA guide, squeezed into one storm night.

Lost lead: a real homeowner who called about their roof and did not become a contactable, correctly routed CRM lead within 24 hours. Tighten the window once you can measure it.

Nine ways an AI receptionist for roofing companies loses a lead

These nine failure modes cover roofing lead capture from first word to first follow-up. Each one is silent on the call itself.

#FailureWhat the CRM showsHow you find it
1Wrong callback numberA lead with a dead or wrong numberCallback differs from caller ID, unconfirmed
2Address or subdivision wrongLead in the wrong place, or no geocodeGeocode fails, or ZIP disagrees with city
3Insurance fields missingNo carrier, no claim statusRequired-field completeness by tag
4Call drops before the writeNo lead at allPhone log call with no matching lead
5Duplicate merged wronglyTwo homes in one recordAudit of merges by address and phone
6Wrong sales territoryLead sits in an idle queueTerritory vs geocoded address
7Voicemail-only leadA recording nobody openedVoicemails with no lead or no task
8Homeowner flagged as spamLead hidden in a junk bucketSample of spam-labeled calls
9Retail vs insurance mis-taggedLead in the wrong pipelineTag vs what the caller said on audio

Failures 4, 7 and 8 leave no lead at all. Your CRM cannot report on a record that does not exist. Only the phone log knows those callers. That is why reconciliation, covered below, is the core measurement.

Callback numbers: ten digits, said fast, outdoors

Phone numbers are the hardest field on a storm call. The caller stands in the yard and says ten digits fast, with "double" or "oh." One wrong digit kills the lead.

Research on spoken dialogue shows how fragile slot capture is. The SpokenWOZ benchmark recorded 249 hours of human-to-human task calls. The best state tracker got every slot right at once in only 25.65% of turns. An earlier DSTC10 robustness study found a tracker trained on written data fell from 54.27% to 0.43% on spoken data. The test sets differ, so the gap is indicative. Still, text-tested extraction breaks on speech.

Three cheap defenses work well together:

  • Compare with caller ID. If the stated number differs from caller ID, ask which one to use.
  • Validate the shape. In the North American Numbering Plan, the area code and the exchange start with 2 through 9. NANPA reserves 555-0100 through 555-0199 as fictitious numbers. A stored number that fails these rules is a capture error, not a lead.
  • Read back in groups. "417, 555, 2 1 8 9?" lets the caller catch one swapped digit.

Addresses in new subdivisions

Storms hit new subdivisions with streets your geocoder has never seen. "Oak Ridge Circle" becomes "Oak Ridge Court." USPS Publication 28 defines a "complete address" as one with every element needed to match the ZIP+4 file. Treat anything less as incomplete, and ask for the cross street. Address tests are covered in the roof inspection post.

Dropped calls: the lead that never existed

Cell coverage is patchy after storms, and callers hang up to answer a neighbor or an adjuster. Many voice agents call a `create_lead` tool only near the end of the call, after read-back. If the call drops at second 48, the tool never runs. The caller gave a name and an address, yet the CRM has nothing.

Timeline of one storm call that drops at 48 seconds, comparing an end-of-call lead write that saves nothing with a progressive write that saves a partial lead flagged for callback

The fix is a progressive write. Create a draft lead at the first usable contact field. Update it per slot. Close it from a server-side hang-up event, not from the model.

On Twilio, a phone number's `statusCallback` URL gets call status updates for that number. The call resource docs say the `completed` event fires "regardless of the termination status." Terminal events carry `CallDuration` in seconds and a `SipResponseCode`. Two gotchas matter here. First, Twilio warns that status requests may arrive out of order, so use `SequenceNumber`. Second, the hang-up handler must be idempotent, because a retry should never create a second lead.

Flag it with `status = partial` and `next_action = call back`. A partial lead with a name and caller ID is still a lead.

Duplicates and wrong merges

Storm callers call back after drops and holds, and spouses call from a second phone. Dedupe is needed. Bad dedupe is worse than none.

Two merge rules cause most damage:

  • Merge by address alone. "1204 Maple" exists in two towns, or as two units in a duplex. Two homeowners become one lead, and one of them never hears back.
  • Merge by phone alone. A landlord calls about four rentals. A storm-restoration public adjuster calls for several clients. One phone, many properties, one record.

Each wrong merge is a duplicate lead problem solved the wrong way. A safer key is phone plus normalized address, with a human review queue for near-matches. Never let the voice agent itself decide a merge mid-call.

Wrong sales territory

Contractors route leads by ZIP, county or drawn polygon, using the address the agent heard. A wrong address means a wrong territory. A ZIP that spans two territories breaks ZIP-only rules. Either way, the lead sits in a queue nobody works.

Check territory against the geocoded point, not the spoken ZIP. Alert on any lead with no territory at all. The same many-configs problem appears in our post on testing one agent across hundreds of customer setups.

Spam, solicitation and the homeowner in the junk folder

Storm nights bring lead sellers, agencies, crews seeking subcontract work and robocalls. State officials such as Louisiana's attorney general warn homeowners about out-of-state "storm chasers." Some of those outfits call contractors too.

Filtering helps, but it has two error directions. Letting spam into the CRM wastes rep time. Labeling a real homeowner as spam loses a lead with no trace. STIR/SHAKEN lets carriers verify that caller ID is real. It says nothing about intent. Twilio's `StirStatus` attestation is a useful signal, not a lead filter. Sample spam-labeled calls every storm week and listen to them.

Insurance or retail: the tag that picks the pipeline

An insurance job needs an insurance carrier, claim status and often an adjuster date. A retail job needs scope and budget questions. A wrong tag sends the lead down the wrong pipeline.

Carrier names are hard for speech recognition. "USAA" may be spelled letter by letter. "Allstate" can come back as "all state." Store carrier as a picklist value plus the raw transcript, and allow `unknown`. Claim status should be `not filed`, `filed`, `adjuster scheduled` or `unknown`. Never let the agent guess, or say what insurance will cover. State limits on contractor claim talk are in the roof inspection post.

Worked example: 418 calls, 63 lost leads

Here is an illustrative storm night for one contractor. The numbers are a worked example, not measured data.

Waterfall from 418 storm-night calls down to 279 unique homeowners and 216 usable leads, with 63 lost leads split by cause such as dropped calls and wrong callback numbers

Start with the phone log, not the CRM:

  • 418 inbound calls
  • minus 52 solicitation and spam calls
  • minus 41 existing customers asking about jobs
  • minus 9 hang-ups under 10 seconds with no voicemail
  • = 316 calls from prospective homeowners
  • minus 37 repeat calls from the same people
  • = 279 unique homeowners

Now match those 279 against the CRM. Suppose 216 are contactable, correctly routed leads after 24 hours. That leaves 63 lost leads, or 22.6% of genuine demand.

CauseLost leads
Call dropped before the lead write14
Wrong or invalid callback number12
Voicemail-only, never worked11
Routed to the wrong territory9
Merged into another home's record6
Real homeowner labeled spam6
Address unusable, no callback either5
Total63

If 30% of leads become signed jobs, 63 lost leads is about 19 jobs. Meanwhile the answered rate reads 100%. Your customer sees the gap only if your product computes it.

Six numbers that show whether storm leads are leaking

Answer rate is not a lead metric. Track these six per contractor, per storm week.

MetricFormulaStarting threshold
Lead capture rateUnique genuine callers with a CRM lead within 15 min ÷ unique genuine callers≥ 99%
Dropped-call lead creationPartial leads created ÷ dropped calls with at least one captured field100%
Required-field completenessLeads with callback, address, territory and job tag ÷ leads≥ 95%
ContactabilityLeads reached on the stored number within 24 h ÷ leads attemptedWithin 5 pts of human-answered leads
Wrong-merge rateMerges reversed in audit ÷ merges≤ 1%
Spam false-positive rateHomeowners found in a 50-call spam sample ÷ 500
Scorecard of six storm lead capture metrics with formulas and thresholds, where an illustrative week passes four and fails lead capture rate and contactability

The thresholds are starting points, not industry standards.

Add one comparison metric: lead-to-inspection conversion by source. Split leads by lead source: AI-answered live, AI after hours, voicemail, human-answered, web form. If AI-answered leads convert to inspections 10 points below human-answered leads, look at contactability and routing first. Our lead quality post for moving companies uses the same source-split pattern.

For sampling math and field-level grading against call audio, see the booking accuracy scorecard. Broader lead metrics are in metrics for a lead qualification voice agent.

Code: reconcile the phone log against CRM leads

This lead reconciliation check finds failures 4, 7 and 8. Run it nightly and after every storm. Simplified, standard library only.

# Simplified: find genuine callers with no CRM lead, and leads with bad contact data.
GENUINE_MIN_SECONDS = 10

def norm(num: str) -> str:
    return "".join(c for c in num if c.isdigit())[-10:]

def valid_nanp(n: str) -> bool:
    # Area code and exchange start with 2-9; 555-0100..0199 is fictitious.
    return (len(n) == 10 and n[0] in "23456789" and n[3] in "23456789"
            and not (n[3:6] == "555" and n[6:8] == "01"))

def reconcile(calls, leads, spam_numbers, customer_numbers):
    by_sid = {l["source_call_sid"]: l for l in leads if l.get("source_call_sid")}
    by_phone = {}
    for l in leads:
        for p in (l.get("caller_id"), l.get("callback_phone")):
            if p:
                by_phone.setdefault(norm(p), l)

    orphans, suspects, seen = [], [], set()
    for c in calls:  # one row per CallSid from your telephony logs
        caller = norm(c["from"])
        if caller in seen or caller in spam_numbers or caller in customer_numbers:
            continue
        if int(c["call_duration"]) < GENUINE_MIN_SECONDS and not c.get("voicemail_url"):
            continue
        seen.add(caller)
        lead = by_sid.get(c["call_sid"]) or by_phone.get(caller)
        if lead is None:
            orphans.append(c)  # in the phone log, missing from the CRM
            continue
        cb = norm(lead.get("callback_phone", ""))
        if not valid_nanp(cb):
            suspects.append((caller, "invalid callback number"))
        elif cb != caller and not lead.get("callback_confirmed"):
            suspects.append((caller, "callback differs from caller ID, unconfirmed"))
        if not lead.get("territory"):
            suspects.append((caller, "no territory"))
        if lead.get("job_tag") not in {"insurance", "retail", "unknown"}:
            suspects.append((caller, "missing insurance/retail tag"))
    return orphans, suspects

Two notes. Store the `CallSid` on every lead as `source_call_sid`, or matching falls back to phone numbers. And note that `spam_numbers` comes from your filter. Feed a sample of those calls to a human, or the spam false-positive rate stays invisible.

How storm conditions break capture

Quiet-day tests miss the conditions that cause the losses above. Three matter most.

Noisy outdoor callers

Storm callers stand in wind and rain, near generators, and pause to look at the roof. Speech recognition can fail in noise and invent words in silence. The Careless Whisper study found about 1% of Whisper transcriptions held text that was never spoken. Hallucinations were more common for speakers with longer non-speech stretches. A long pause while someone walks to the gutter is exactly that stretch.

Test digit capture under wind noise with long pauses mid-number. Our guide to testing STT under background noise covers how to mix noise at set levels.

Partial and interrupted calls

Script calls that end at every step: after the name, mid-number, during read-back, and while on hold for a transfer. Each should leave a partial lead with whatever was captured. Also script callers who interrupt the read-back with a correction. The stored value must be the correction.

Surge concurrency on the CRM write

At surge, the CRM write can fail while the voice side holds up. Rate limits and webhook timeouts return errors a model can ignore. The agent still says "you're all set." Test lead writes at your storm peak concurrency, and assert that every failed write is retried or queued. Sizing math for storm peaks is in the roof inspection post. Causes and fixes for agent-side load are in concurrency failure in voice agents.

ScenarioQuiet, clearWind and rain noiseCall drops mid-flow100 concurrent calls
Callback differs from caller IDConfirm askedDigits correctPartial lead, caller ID keptWrite succeeds
New subdivision addressCross street askedStreet not inventedPartial leadTerritory set
Insurance claim filed, carrier namedTag insuranceCarrier or `unknown`Tag keptNo field loss
Second call from same homeownerLinked, not mergedLinkedLinkedNo double lead
Lead seller pitching servicesNot a leadNot a leadNo leadNo lead

Evalgent fits this kind of matrix. It generates scenarios from your agent's prompt and flows. It then calls the agent over PSTN, SIP or WebRTC with caller profiles that set background noise, speech pace, interruption level and response delay. Verdicts are judged from the call audio, not only the transcript, so a misheard digit is caught against what was said.

Outbound storm follow-ups and TCPA

Many platforms add outbound follow-ups after a storm, such as a callback to a dropped caller. The FCC's declaratory ruling of February 2024 recognizes AI-generated voices as "artificial" under the TCPA. Consent rules for such calls are in 47 CFR 64.1200.

Revocation rules are changing. FCC 26-67 was adopted September 30 and released October 1, 2026, per Kelley Drye. It allows exclusive opt-out methods and drops "revoke all." It takes effect 30 days after Federal Register publication. Nixon Peabody reported that had not happened as of October 7, 2026.

Test that follow-ups stay informational, state the opt-out method and log every "stop calling." See the outbound voice agent testing plan and TCPA checks for speed-to-lead calls. This is not legal advice.

One agent, many roofing contractors

On a platform, an AI receptionist for roofing companies runs for many contractors at once. Each has its own territories, required fields and handoff rules. Products differ in what a call creates. JobNimbus support says its AssistAI "creates tasks to schedule appointments" for unknown callers. For existing customers it "creates notes on the Contact and Job levels." A task, a note and a lead reconcile differently. Decide which record counts as "the lead" before you measure capture.

Per-contractor config is where storm-week bugs hide: a new required field, redrawn territories, a prompt change that reaches everyone. Reconcile per contractor. A platform average hides one broken setup.

How to test an AI receptionist for roofing companies before storm season

1. Define a lost lead. Fix the record type, required fields and time window that count as "captured."

2. Store the call ID on every lead. Add `source_call_sid` and `caller_id` fields.

3. Move to progressive writes. Create a partial lead after the first usable contact field. Close it from the hang-up status event, idempotently.

4. Add capture guards. Compare callback with caller ID, validate NANP shape, read back in groups, and require a cross street for unknown streets.

5. Fix dedupe rules. Link repeat calls by phone plus address. Send near-matches to human review. Never merge on address or phone alone.

6. Run the scenario matrix. Cover dropped calls at each step, wind noise, corrections during read-back, landlords with several properties, lead sellers and insurance versus retail callers.

7. Load-test the CRM write path. Hit your storm peak concurrency and assert zero silent write failures.

8. Reconcile nightly in production. Run the phone-log-versus-CRM check per contractor. Sample 50 spam-labeled calls each storm week.

9. Report the gap to customers. Show lead capture rate next to the answered rate.

For step 8, Evalgent's production monitoring takes pushed call recordings, transcribes them, maps each call to a scenario and judges it. It flags tool-call failures, so a lead write that errored mid-call shows up next to the call that caused it. See also the AI phone agent go-live checklist.

Frequently asked questions

Can an AI receptionist answer calls for a roofing company?

An AI receptionist can answer calls for a roofing company, including storm-night surges a small office cannot staff. Answering is the easy part. The harder part is turning each call into a correct lead: a confirmed callback number, a usable address, the right territory and an insurance or retail tag. Measure lead capture, not answer rate.

Why do roofing companies lose storm leads?

Roofing companies lose storm leads mostly to silent capture failures, not unanswered calls. Common causes are dropped calls before the lead is saved, wrong callback digits, voicemails nobody works, wrong-territory routing, wrong duplicate merges and real homeowners filtered as spam. Each looks fine on the call. Only matching the phone log against the CRM shows the loss.

How do you know if an AI receptionist is losing leads?

Match every genuine caller in the phone log to a CRM lead within a set window, such as 15 minutes. Callers with no lead are losses. Then check each lead's callback number, territory and job tag. Compare lead-to-inspection conversion for AI-answered leads with human-answered leads. A gap of 10 points or more signals a capture problem.

What should an AI receptionist capture from a roofing lead?

A roofing lead needs a name, a confirmed callback number, a complete service address with cross street if unclear, the damage type and urgency, and an insurance or retail tag. Insurance leads also need carrier and claim status, with "unknown" allowed. Store the call ID and caller ID on the lead so it can be reconciled later.

What happens to a lead when a call drops?

When a call drops, the lead is lost if the agent only saves it at the end of the call. The fix is a progressive write: create a partial lead once one contact field is captured, then close it from the server's hang-up event. A partial lead with a name and caller ID still gets a callback.

How should an AI receptionist handle spam calls after a storm?

After a storm, an AI receptionist should screen out lead sellers, crews seeking subcontract work and robocalls without creating leads for them. The risk runs both ways. A homeowner wrongly labeled as spam disappears without a trace. Sample about 50 spam-labeled calls each storm week and listen to them. STIR/SHAKEN verifies caller ID, not intent.

Should an AI receptionist tag insurance or retail roofing jobs?

An AI receptionist should tag each roofing lead as insurance, retail or unknown, because the tag picks the sales pipeline and the first call. It should record carrier and claim status as stated, never guess them, and never say what insurance will cover. State laws in places like Florida and Texas limit contractor claim talk.

Can an AI receptionist make storm follow-up calls?

An AI receptionist can make storm follow-up calls only with the right consent. The FCC confirmed in 2024 that AI-generated voices count as artificial voice under the TCPA. FCC 26-67, released October 1, 2026, changes opt-out rules once published. Keep follow-ups informational, state the opt-out method and log every request. This is not legal advice.

The bottom line

An AI receptionist for roofing companies can answer every storm call and still lose leads without a trace. Match the phone log to the CRM every night, test dropped and noisy calls before hail season, and report lead capture rate to customers next to the answered rate.

Related Articles