How to Find Old Roofing Estimates That Never Closed in Your CRM
On this page
Somewhere in your CRM right now there is a homeowner you stood on a roof for, measured, photographed, priced, and emailed a proposal to. Then nothing. They never signed, never said no, and never came up again. Multiply that by every rep who ever worked for you, every storm season, every estimating tool you switched off of, and you have a pile that almost always runs into the hundreds or thousands of records. Those are your never-closed estimates, and the problem is rarely that they are worthless. The problem is that you cannot find them. They are scattered across stages nobody maintained, tagged inconsistently by reps who quit, sitting in an old spreadsheet, or stuck in the estimating software you stopped logging into. The job in front of you is a retrieval job before it is a sales job: get every old open bid out of hiding, into one list, deduplicated by property, and ranked by who is actually due now.
Most advice on "following up on old leads" skips straight to scripts and sequences. That is putting the cart three miles ahead of the horse. You cannot run a sequence against records you have not surfaced, and you will surface the wrong ones if you sort by the wrong field. What follows is the unglamorous, operational part nobody writes about: where these estimates actually hide, the exact filter and search logic to pull them in the common roofing CRMs, how to export and reconcile across systems, how to collapse three messy rows for the same house into one clean opportunity, and how to re-grade the whole pile so the roofs that are genuinely in the buy window float to the top and the ones a competitor already re-roofed drop out. Get the finding right and the calling part gets easy.
What "never closed" actually means (and why it is hard to query)
The first reason these records are hard to find is that "never closed" is not one status in your CRM. It is the absence of a status, which is much harder to query than a value that is present. An estimate that never closed could be sitting in any of these states, and they rarely share a label:
- Still in an open pipeline stage (Proposal Sent, Estimate Out, Pending) that nobody ever moved.
- Marked lost with no reason, or a junk reason a rep clicked to clear it off their board.
- Stuck in a stage that no longer exists because someone rebuilt the pipeline and the old records kept the dead stage.
- Tagged follow-up or call back two years ago and never touched.
- Created as a deal/opportunity but with no estimate attached, or an estimate created with no deal — depending on which object your CRM treats as the source of truth.
- Living only in the estimating tool (the proposal was built and sent) but never pushed to the CRM at all.
- Sitting in a closed-won state by accident because a rep mis-clicked to hit a board metric, even though no job was ever built.
The practical consequence: if you just filter Stage = Open you will miss most of them. The never-closed pile is defined by what did not happen — no signed contract, no scheduled production, no paid invoice — far more reliably than by any single stage label a human maintained. The most durable way to find them is to start from the records that have an estimate or proposal event and then subtract the ones that have a downstream production or payment event. Whatever is left is your real never-closed set, regardless of how the stage field reads.
Keep that subtraction logic in mind; it is the backbone of every export below. You are looking for estimate exists minus job happened.
It helps to picture how a real record goes dark, because the pattern repeats thousands of times. A rep inspects a roof in March, builds a proposal in the estimating tool, emails the PDF, and creates a deal in the CRM at "Proposal Sent." The homeowner says they want to think about it. The rep makes one follow-up call, gets voicemail, and moves on to fresher opportunities. Three months later, during a board cleanup, that rep — or a sales manager tidying the pipeline — drags the deal to "Lost" and picks the first reason in the dropdown to clear it. Six months after that, the rep quits. Now the record is a Lost deal with a meaningless reason, owned by nobody, attached to a proposal that lives in a tool you may have since stopped using, on a roof that is now over a year older than when it was already old enough to bid. Nothing about that record's stage tells you it is a live opportunity. Only the underlying fact — bid sent, no job built, roof aging — does. Every retrieval technique below exists to recover records exactly like that one.
A working definition you can filter on
Before touching the CRM, write down the definition you will actually query against, because vague definitions produce vague lists. A workable one for most residential and storm roofers:
A never-closed estimate is any record where (a) a proposal, bid, or estimate was created or sent, AND (b) there is no associated signed contract, production/job record, or paid invoice, AND (c) the last activity is older than your normal sales cycle.
That third clause matters. An estimate you sent last Tuesday is not a never-closed estimate; it is live pipeline, and your reps should be working it through their normal follow-up. You are hunting the records that have gone cold — past the point where a rep is naturally chasing them. For most roofers that threshold is 60 to 120 days for retail/insurance work, longer for large commercial. Pick a number. Anything past it with an estimate and no job is in scope.
Write that definition on a whiteboard. Every filter you build is just a way to express those three clauses in whatever query language your CRM gives you.
Where old estimates hide: the eight common graveyards
You will not find them all in one place. Before you build a single report, inventory where estimate data physically lives in your operation. In a typical roofing company that has been around more than a few years, never-closed estimates are spread across:
- The current CRM pipeline — open and lost deals.
- The current CRM's archive/inactive view — many CRMs hide old or "lost" records from the default board, and reps forget the archive exists.
- The estimating/proposal tool — proposals built and sent that were never logged as deals.
- The measurement/aerial reports tool — every ordered report is a house someone intended to bid; cross-reference against jobs and you find bids that never converted.
- The accounting system — estimates created in the books that never became invoices.
- Old spreadsheets and shared drives — the pre-CRM era, or a rep's personal tracking sheet that left with them.
- Email — proposals sent as PDF attachments that never got logged anywhere structured.
- The canvassing/door app — inspections logged and quoted in the field app that never synced to the CRM.
Make a one-line note next to each: does this system hold estimate data, and can you export it? You only need to chase the ones that actually contain unsold bids. For most companies the big three are the CRM, the estimating tool, and the measurement-report tool, and those three reconciled against the job/production records will surface the vast majority of the pile.
Step one: pull the master export from your CRM
Start with the system of record. The goal of this step is one flat export with every field you will need to filter, dedupe, and score later. Do not try to be clever in the CRM's report builder yet; pull broad, clean in a spreadsheet.
The fields to export
Request these columns at minimum. If a field does not exist, note it as a gap to fill later:
- Record/deal ID (you need a stable key to dedupe and re-import)
- Property address (street, city, state, ZIP — as separate columns if possible)
- Homeowner name
- Phone(s) and email
- Pipeline stage and stage-changed date
- Lost reason (if any)
- Estimate/proposal created date and sent date
- Estimate dollar amount
- Job type (retail, insurance/storm, repair, replacement, commercial)
- Roof material / notes (often free-text)
- Owner/rep assigned
- Last activity date
- Source (where the lead came from)
- Any "job created" / "contract signed" / "invoice" linkage field
The filter logic in common roofing CRMs
The exact menu names vary, but the logic is identical everywhere. You want: an estimate exists, no job exists, and it has gone cold. How to express that in the tools roofers actually use:
- JobNimbus / AccuLynx / Roofr / JobProgress and similar roofing CRMs: Build a report or filtered view on the deal/job object. Filter
estimate amount is not emptyORproposal sent date is not emptyto require that a bid existed. Addcontract signed / job stage is emptyorstatus is not Won/Sold/Productionto require no job. Addlast activity date is before [today minus 90 days]. Many of these tools have a "lost" or "unsold" status — include those records too, because a rep marking something lost is not the same as the roof being gone. - HubSpot / Pipedrive / Salesforce (if you run a general CRM): Filter deals where
Deal Stageis any open stage ORClosed Lost, ANDAmount is known, ANDLast Activity Datemore than 90 days ago, AND no associatedClosed Wondeal on the same company/property. Use the associated-objects logic to exclude anything that later turned into a won deal at the same address. - Spreadsheet-only operations: If your "CRM" is a sheet, sort by last-contact date, then flag every row with a quoted amount and no "sold" marker. Crude, but it works for the first pass.
A critical instruction: include lost deals. The single most common mistake is filtering to only "open" records. A huge share of never-closed estimates were marked lost — often with a meaningless reason — by a rep clearing their board. Those are not dead. "Lost on price" three years ago is a roof that is three years older and a homeowner who may have learned what a cheap roof buys. Pull lost records in, then re-qualify them yourself rather than trusting a years-old disposition a departing rep clicked in a hurry.
When the CRM can't express the logic
Some roofing CRMs have weak report builders and cannot do "estimate exists AND no job." Fine. Export two lists — all records with an estimate, and all records with a job/sale — and do the subtraction in a spreadsheet with a lookup on address or deal ID. The subtraction is the same; you are just doing it outside the tool. This is also exactly how you reconcile across multiple systems, which is the next step.
Three filter recipes you can copy
To make the logic concrete, here are three ready-to-adapt filter sets. Names of fields differ by tool, so map them to your own, but the structure transfers directly.
Recipe 1 — The conservative open-bid pull. Use this first; it returns the cleanest records.
Estimate amountis greater than 0- AND
Stageis one of [Proposal Sent, Estimate Out, Pending, Follow-up] - AND
Last activity dateis before today minus 90 days - AND
Contract signed dateis empty
This gives you the obvious never-closed records — the ones still sitting open. It will under-count, but everything it returns is high quality.
Recipe 2 — The lost-record recovery pull. Run this second; it surfaces the buried half.
Estimate amountis greater than 0- AND
Stageis one of [Closed Lost, Unsold, Dead, Archived] - AND
Lost reasonis one of [Price, No decision, Timing, blank, Other] (exclude only genuine disqualifiers like "duplicate" or "wrong number") - AND
Last activity dateis before today minus 180 days
These are the records a stage-only filter throws away. Re-qualify them on roof age; do not trust the old lost reason.
Recipe 3 — The catch-all subtraction. Run this when the report builder is weak.
- Export A: every record with
Estimate amount > 0regardless of stage - Export B: every record with
Job created date not emptyORInvoice exists - In a spreadsheet:
Export Aminus any address that appears inExport B
The remainder is your true never-closed set. This recipe is also the most defensible, because it does not depend on a single human-maintained stage field being accurate across five years of reps.
Run all three, stack the results, and dedupe — covered shortly. The overlap between them is expected; the union is your pile.
Step two: reconcile across your other systems
The CRM export is the spine. Now you add the records that never made it into the CRM and subtract the houses that actually got roofed. Two cross-references do most of the work.
Cross-reference one: estimating / measurement tool against jobs
Every proposal your estimating tool built, and every aerial measurement report you ordered, represents a house someone intended to bid. Export the full list of proposals/reports with their addresses and dates. Then match that list against your production/job records by address. Any address that has a proposal or an ordered measurement report but no matching job is a never-closed estimate — and a meaningful number of these will not be in your CRM pipeline at all, because the rep built the proposal in the estimating tool and never logged the deal. This single cross-reference routinely surfaces hundreds of bids that were invisible to the CRM report.
Cross-reference two: accounting against the master list
Pull every customer/job from your accounting system that became a real invoice. Match by address against your combined estimate list and remove every match — those houses bought, from you, and are not never-closed (they are past customers, a different and also valuable bucket, but not this project). What remains is closer to a true unsold set.
Build the master never-closed table
After both cross-references you have one combined table. De-duplicate the sources first (the same address may appear in CRM, estimating tool, and measurement tool) — we handle full address-level dedupe next. For now, stack all the estimate-bearing records, then remove anything that matches a real job/invoice. The remainder is your raw never-closed pile. Expect it to be both bigger than the CRM-only number (because of the un-logged proposals) and messier (because it is stitched from multiple systems).
Step three: deduplicate by property, not by name
This is the step that separates a usable list from a confusing one, and it is the step most people skip. In roofing, the unit of value is the property, not the person. People move; roofs stay. Your raw pile will have the same house appearing several times: a 2019 estimate, a 2021 follow-up someone re-entered as a new deal, a 2023 storm inspection. As three separate rows they look like three weak, stale leads. Collapsed into one record they tell a story — this homeowner has engaged with you three times over four years and never re-roofed — which makes them one of the strongest targets in the whole list.
How to dedupe cleanly
- Normalize the address. Standardize abbreviations (St/Street, Ave/Avenue), unit formats, and ZIP. Inconsistent address strings are why naive dedupe fails — "123 N Main St" and "123 North Main Street" read as two houses to a spreadsheet. A standardization pass (USPS address standards are the reference) collapses them.
- Group by normalized address. Every row sharing an address becomes one opportunity.
- Keep the richest record as the master, but preserve the interaction history — number of prior estimates, dates, dollar amounts, and the most recent contact info. A house with three prior touches is scored higher later.
- Carry forward the best contact info, which may come from a different row than the master (the newest phone/email wins).
Do not dedupe by homeowner name. Names are unreliable (typos, nicknames, spouse vs. owner of record, and the new owner if the house sold). The address is the durable key.
Handle sold houses deliberately
When an address has since sold, the old estimate is not dead — it flips. The new owner inherited an aging roof and you have that roof's history on file, which is genuinely useful intelligence. But you treat it as a new, cold contact (new name, new relationship), not a warm follow-up, and the prior consent does not carry to the new occupant. Tag these "sold — new occupant" so they go down a cold track, not the warm reactivation track.
Step four: clean and validate contactability
Now that the list is deduped, make it dialable. A reactivation list is only as good as its contact data, and old records rot.
- Validate phones and emails. Flag disconnected numbers and bounced emails. A cheap validation pass pays for itself by not wasting rep time on dead dials.
- Screen against Do Not Call. Old records carry stale or absent consent. Calling and texting must respect the federal Do Not Call registry and the rules under the Telephone Consumer Protection Act and the FTC's Telemarketing Sales Rule. Prior-business-relationship exemptions exist but are narrower and more time-limited than people assume, and texting cell numbers generally needs consent. Build DNC screening and consent flags in now, not after you get a complaint.
- Check for sold/moved. County records and postal address-change data flag houses that changed hands (route those to the cold track above).
- Score data confidence. Tag each record High / Medium / Low based on completeness and currency of contact info. You work High first. Do not let a pile of Low-confidence records inflate your "list size" so the project feels bigger than it is. A clean 600 beats a dirty 3,000.
A realistic first-pass outcome on a stitched 3,000-record raw pile: roughly 1,800 workable after dedupe and validation, several hundred Low-confidence salvage projects, and a few hundred quarantined as junk or duplicates that could not be reconciled. That ~1,800 is your real never-closed inventory. Now make it rankable.
Step five: re-grade the pile so the roofs that are DUE rise to the top
Here is the insight that changes everything about working old estimates: they appreciate. A bid you wrote too early gets more valuable every year, because the roof on that house ages toward the buy window while the record sits in your CRM doing nothing. An estimate that was premature in year one is ripe in year four. Which means the worst possible way to sort your never-closed list is by recency — calling the freshest records first feels productive but ignores the entire point. You want to sort by which roof is most likely due right now.
That requires re-grading, because the age data baked into your old records is stale and inconsistent. Three signals drive a useful ranking.
Signal one: elapsed time on the roof
Asphalt shingle, the dominant residential material, typically runs roughly 15 to 25 years depending on product grade, ventilation, install quality, and climate, per industry references like the NRCA and the Asphalt Roofing Manufacturers Association. So do the arithmetic the old record won't do for you:
- A homeowner you quoted but didn't sell five years ago has a roof five years older. If it read 14 then, it reads ~19 now — squarely in range.
- A repair quote from four years ago was attached to a roof old enough to need a repair. Add four years.
- A storm estimate that stalled is attached to a roof that took a hit and never got addressed.
Signal two: roof age you can actually verify
Elapsed-time math is a guess layered on inconsistent notes. The expensive failure mode is calling a homeowner whose roof a competitor already replaced two years ago — a wasted dial and a slightly embarrassing one. You sharpen the guess three ways:
- Your own notes, where material and condition were recorded (free, inconsistent).
- County / assessor permit records. A re-roof permit pulled after your estimate date means someone else did the roof — drop it from the replacement track.
- Aerial roof-age tooling that estimates a roof's age as a range from overhead imagery, so you can re-grade an entire stale address list without driving to a single house.
Signal three: storm exposure on that specific roof
Calendar age is one driver; weather is the other. Two identical 16-year-old roofs three miles apart can be in very different shape if a hail core clipped one and missed the other. The National Weather Service and NOAA's Storm Prediction Center publish hail and storm reports, and IBHS documents how hail and wind degrade asphalt shingles. The move: when a storm hits, your first re-work list is the never-closed records inside that footprint — homeowners who already know you, whose roofs you already have on file, in the exact area that just got worn on.
A simple priority score
No data science required — a weighted score in a spreadsheet ranks the list well enough to drive a quarter of calling:
| Factor | Points |
|---|---|
| Roof estimated/known 18+ years (range) | +30 |
| Roof 14-17 years | +18 |
| Prior interaction was a repair (roof already failing) | +15 |
| Inside a recent hail/wind footprint | +25 |
| Stalled insurance/storm estimate on file | +15 |
| Multiple prior estimates at this address (re-engaged, never bought) | +12 |
| Went quiet / no decision (never said no) | +10 |
| Lost on price (price-shopper, may now value quality) | +6 |
| Re-roof permit pulled after your estimate (someone else did it) | -40 |
| Address has since sold | route to cold "new occupant" track |
Sort descending. Roofs scoring 50+ are your this-week list. The negatives fall out of the replacement campaign. This one sort is the difference between a rep who "called some old leads and it didn't really work" and one who books three jobs off a Tuesday.
Where RoofPredict fits: re-grading a stale list without driving it
The hardest part of the ranking above is signal two — knowing which of your old addresses have a roof that is genuinely due now, versus one a competitor already replaced. Your notes are stale, your guesses are rough, and you are not going to drive 1,800 addresses to eyeball shingles. That specific problem is what RoofPredict was built for, and it slots in right after you have a deduped never-closed list.
RoofPredict takes a list of addresses — your never-closed export works fine — and returns, per house, a roof-age range estimated from aerial imagery, plus storm physics modeled on that specific roof: how hail and wind actually loaded that roof, not merely whether a storm passed through the ZIP. Against a pile of old estimates that lets you do two things your CRM cannot:
- Re-grade every stale address at once. Feed in the unsold bids. Houses whose roofs now read 18-22 years jump to the top of the call list; houses a competitor already re-roofed read young and drop out, so you stop wasting dials and stop the awkward call to someone with a two-year-old roof.
- Layer storm reality onto the list. After a hail event, see which of your own never-closed contacts had roofs the storm actually wore on, so your first calls go to people who know you and whose roofs took the hit — not a cold canvass of strangers.
Honest limits, because overselling helps no one. The roof age is a range, not an exact install date — it tells you who is in the buy window, not the day the shingles went on; you confirm condition with an inspection. The storm model gives odds, not proof — it points at the roofs most likely worn out, and the actual damage finding comes from your tech on the ladder. It does not measure the roof for a takeoff (that is what EagleView, HOVER, and Roofr do — a different job), it does not pull permits or read warranty paperwork for you, and it is not a lead service: these homeowners are already yours. What it does is turn a cold pile of old addresses back into a ranked, current list of which roofs are due — the exact input the finding-and-re-grading workflow needs. It is the bridge between "I dug up 1,800 old estimates" and "here are the 180 whose roofs are most likely due this season."
Step six: tag and segment the surfaced pile for follow-up
Finding and ranking is the hard part; now make the list workable by tagging each record so the right rep runs the right play. The never-closed pile splits into a handful of follow-up segments, and the tag drives the message:
| Segment | What it is | Follow-up motion |
|---|---|---|
| Went quiet / no decision | Never said no, just stopped responding | Warm phone-led re-look |
| Lost on price | Chose a cheaper bid years ago | "Roof's older now, let's re-look" |
| Storm/insurance stalled | Started a claim, it fizzled | Event-triggered, fired after a storm |
| Repair-only quote | Patched, underlying roof aging fast | Warm, named-tech if possible |
| Multiple prior touches | Engaged 2-3 times, never bought | High-priority warm call |
| Sold / new occupant | House changed hands | Cold track, fresh consent |
| Permit-pulled (lost the job) | Competitor re-roofed it | Referral / repair / maintenance track |
The point of tagging at the finding stage is that it travels with the record into whatever sequence tool you use, so a rep opening the list knows in one glance whether they are making a warm "picking back up where we left off" call or a cold introduction. Mixing these is how a good list produces bad calls.
The actual outreach sequences — the multi-touch phone/text/email/mail cadences, the scripts, and the claims-safe storm language — are their own discipline; the short version is lead with the phone for warm records, space touches over weeks with a real reason for each, always offer a no-pressure off-ramp, and keep any storm work strictly to documenting condition and handing the homeowner a report they take to their own carrier. You document; the homeowner files; the carrier decides coverage. Never promise approval, never touch the deductible, never claim damage before an inspection.
Getting the surfaced list back into the CRM cleanly
You did the export, reconcile, dedupe, validate, and re-grade outside the CRM in a spreadsheet. Now the ranked list has to land somewhere reps will actually work it, which means importing it back without creating a second mess. A few mechanics matter here, because a sloppy re-import duplicates records and corrupts the very database you just cleaned.
Re-import against the original record ID, not as new records. This is the single most important rule. Every record you exported kept its deal/record ID. When you push updates back — the new score, the segment tag, the re-graded roof age, the cleaned phone number — match on that ID so you update the existing record rather than creating a duplicate. Records that came from outside the CRM (the un-logged proposals and measurement-report addresses) are the only ones you create new, and you create them once, deliberately, with a source tag like "recovered-2026Q2" so you can find them again.
Add purpose-built fields before you import. Create three custom fields on the deal/job object up front: Never-closed score (number), Re-work segment (the tag from the segmentation table), and Roof age range (text, e.g. "18-22"). Map your spreadsheet columns to those fields. Without them, your scoring and segment data has nowhere to land and you lose the work.
Build a saved view or smart list reps open daily. The whole point is that a rep opens one list and sees the ranked, tagged records. Create a saved filter: Never-closed score >= 50, sorted descending, optionally split by Re-work segment so a rep can grab "warm went-quiet" calls in one block. The list should be self-serve; nobody should have to re-run a spreadsheet to know who to call.
Protect the audit trail. Log a note on each re-imported record ("surfaced and re-graded 2026-Q2 — roof range 19-23, segment: went-quiet") so the next person to open it understands why it resurfaced and does not re-mark it lost out of confusion. The notes you generate are the asset; an undocumented re-import looks like spam to the next rep.
Done right, the re-import converts a pile of CSV rows into a living campaign segment inside the tool reps already use, with the scoring and tags intact and no duplicates created. Done wrong, you double your record count and undo a week of cleanup. The difference is matching on ID and creating the custom fields first.
A worked example: surfacing a 5-year never-closed pile
Concrete numbers make the workflow real. Illustrative, not a promise — your mileage varies with market, system hygiene, and season — but the shape holds.
The systems: a JobNimbus-style CRM (5 years of deals), an estimating tool with sent proposals, an aerial-measurement account, and QuickBooks.
CRM export. Filtering estimate amount not empty AND not Won/Sold AND last activity > 90 days (including Lost records) returns 2,100 deals. Pulling Lost-marked records alone adds 700 that a stage-only filter would have missed.
Reconcile. The estimating tool shows 2,600 sent proposals; matching by address against jobs reveals 480 proposals with no CRM deal at all — bids built in the estimating tool and never logged. The measurement tool adds another 120 ordered-report addresses with no job and no deal. Removing every address that matches a real QuickBooks invoice strips out 900 that actually bought. Combined raw never-closed pile: ~2,400 records.
Dedupe by address. Normalizing addresses and grouping collapses 2,400 rows into 1,950 unique properties; 300 houses show 2+ prior estimates (flagged as multi-touch, higher priority). 90 addresses have since sold (routed to cold track).
Validate. After phone/email validation, DNC screening, and confidence scoring: ~1,500 workable, ~350 low-confidence salvage, ~100 quarantined.
Re-grade and score. Running the 1,500 workable addresses through roof-age re-grading (notes + permits + aerial ranges) and applying the priority score: 175 properties score 50+ (roofs likely in the buy window). 130 addresses pulled a re-roof permit after the estimate (someone else did it) and drop to the referral track. The 175 high-scorers, tagged by segment, become the call list.
The payoff of the finding work: the company went from "we have a CRM full of old leads somewhere" to a ranked, deduped, dialable list of 175 properties whose roofs are most likely due — with 600 records surfaced that were never in the CRM at all. The calling is now a known, finite, prioritized task instead of an overwhelming, vague one. That conversion — from chaos to a 175-row ranked sheet — is the entire value of doing the finding properly.
What pros get wrong when digging out old estimates
Most people who say "we tried working our old estimates and it didn't pan out" made one of these retrieval errors, not a sales error.
Filtering on Stage = Open only. This misses every record a rep marked Lost to clear their board — often the largest chunk of the pile. Always include Lost/Unsold and re-qualify them yourself.
Never reconciling against the estimating and measurement tools. Proposals built in the estimating software and reports ordered for bids that never got logged as deals are invisible to a CRM-only report. These un-logged bids are frequently 20-30% of the real pile. Skip the cross-reference and you never even see them.
Deduping by name instead of address. Name-based dedupe scatters the same house across multiple weak rows and hides the multi-touch homeowners who are your strongest targets. Normalize the address and group on it.
Sorting by recency. Calling the newest old-estimates first feels efficient and is backwards. Never-closed estimates appreciate; the five-year-old bid graveyard is often the ripest bucket. Sort by who is due, not who is newest.
Trusting the old disposition. "Lost on price" from three years ago is a label a busy rep clicked, not a verdict. The roof is older now and the homeowner's situation changed. Re-qualify; don't inherit a stale judgment.
Not re-grading roof age. Without a permit check or an aerial roof-age pass, you waste a chunk of every campaign calling houses a competitor already re-roofed. Re-grading removes them and saves rep energy for live opportunities.
Ignoring consent and DNC at the finding stage. Old records carry stale or missing consent. Bolt compliance on after the fact and you risk TCPA and Do Not Call exposure. Screen and flag during cleanup, not after a complaint.
Treating it as a one-time cleanup. The pile regenerates. Every quarter, new estimates go cold, roofs age, and storms hit. Make surfacing-and-ranking a quarterly habit and the list stays fresh instead of rotting back into chaos.
Tools to do this without overbuilding
You do not need an enterprise stack to surface and rank a never-closed pile. You need a way to export, a place to reconcile, a way to dedupe and validate, and a way to re-grade roof age.
- Exports. Whatever your CRM, estimating tool, measurement tool, and accounting system can dump to CSV. That is the entire input.
- Reconciliation and dedupe. A spreadsheet handles the first pass for most companies — address normalization, lookups to subtract jobs, grouping to dedupe. For very large piles, a lightweight dedupe tool or a database import speeds it up, but a sheet works.
- Contact validation and DNC. Use a validation pass plus a dialing/texting tool that supports Do Not Call scrubbing and consent records. Compliance is a feature here, not a nicety.
- Roof-age re-grading. Permit lookups (free, slow, manual) or an aerial roof-age tool (fast, runs against the whole address list) to re-score the pile. This is the step that turns a stale list into a ranked one.
- Where the records land. Re-import the surfaced, tagged, scored list back into your CRM as a campaign segment so reps work it in the tool they already use, and so outcomes get logged for next quarter.
Resist building a giant automation before you have proven the motion by hand. Surface one segment, re-grade it, run it manually, see what the ranked list is worth, then automate the parts that repeat.
A repeatable quarterly cadence
The companies that win at this stop treating it as a one-time archaeology dig and make it a rhythm. A workable quarterly loop:
- Week 1 — Export and reconcile. Pull the CRM, estimating tool, measurement tool, and accounting exports. Subtract real jobs. Add the un-logged proposals. Build the raw never-closed table.
- Week 1-2 — Dedupe and validate. Normalize addresses, group by property, carry forward best contact info, validate phones/emails, screen DNC, score confidence.
- Week 2 — Re-grade and rank. Re-grade roof age (notes, permits, aerial ranges), fold in recent storm footprints, apply the priority score, tag by segment.
- Week 2 — Hand off the ranked list. Re-import the 50+ scorers into the CRM as a campaign, split by segment, assigned to the right reps.
- Weeks 3-7 — Work it (separate discipline). Run your follow-up sequences; log every outcome the same day so the data improves.
- Ongoing — Keep it from rotting. Tag new estimates correctly as they go cold so next quarter's pile is already half-surfaced.
Do that four times a year and the never-closed pile stops being a vague source of guilt and becomes a renewable, ranked inventory you own outright — one no aggregator can resell out from under you, that works in storm seasons and dead ones alike. The job you book next quarter is already sitting in your CRM. The whole task is finding it, ranking it, and calling before someone else re-roofs the house.
FAQ
How do I find old estimates that never closed in my roofing CRM?
Start from the records that have an estimate or proposal and subtract the ones that became a real job. In your CRM, filter for records where an estimate amount or proposal-sent date exists, the status is not Won/Sold/Production, and the last activity is older than your sales cycle (commonly 90 days). Critically, include Lost or Unsold records as well as open ones, because reps often mark estimates lost to clear their board. Then reconcile against your estimating tool, measurement-report tool, and accounting system to catch bids that were never logged as deals and to remove houses that actually bought.
Why does filtering only by open pipeline stage miss most unsold estimates?
Because 'never closed' is the absence of a status, not a single value you can filter on. An old estimate might sit in an open stage, but it might equally be marked Lost with a junk reason, stuck in a deleted stage, mislabeled Won by a mis-click, or living only in your estimating tool and never pushed to the CRM at all. A Stage = Open filter misses every one of those. The reliable approach is to require that an estimate exists and that no signed contract, job, or paid invoice exists, regardless of the stage label.
Should I include lost deals when pulling old roofing estimates?
Yes, and they are often the biggest part of the pile. A rep marking a deal Lost is not the same as the roof being gone. 'Lost on price' from three years ago is a roof that is three years older and a homeowner who may now value quality over the cheapest bid. Pull lost records in, then re-qualify them yourself by re-grading the roof age rather than trusting a years-old disposition a busy or departed rep clicked. The only lost records you should drop are the ones where a re-roof permit shows a competitor already replaced the roof.
How do I export unsold estimates and find ones that were never logged as deals?
Export every record with an estimate from your CRM, then separately export all sent proposals from your estimating tool and all ordered reports from your measurement tool. Match those proposal and report lists against your actual jobs by address. Any address that has a proposal or ordered measurement report but no matching job is a never-closed estimate, and a meaningful share of these will not exist in your CRM pipeline at all because the rep built the bid in the estimating tool and never logged the deal. This cross-reference routinely surfaces hundreds of invisible bids.
Why should I deduplicate old estimates by address instead of by name?
In roofing the property is the unit of value, because people move but roofs stay. The same house often appears several times in a stitched pile, a 2019 estimate, a 2021 re-entry, a 2023 storm inspection. As separate rows they look like three weak stale leads. Collapsed by normalized address into one record they reveal a homeowner who engaged three times and never re-roofed, which is one of your strongest targets. Name-based dedupe fails on typos, nicknames, spouse versus owner of record, and new owners after a sale.
How do I figure out which old estimates are actually worth calling now?
Sort by which roof is most likely due, not by which estimate is newest. Combine three signals. First, elapsed time: add the years since the estimate to the roof age it implied. Second, verifiable roof age from your notes, county permit records, or an aerial roof-age estimate that returns an age range per address, which also flags houses a competitor already re-roofed. Third, storm exposure: prioritize records inside recent hail or wind footprints. Score each record on those factors and call the highest scores first. Never-closed estimates appreciate, so the oldest bids are often the ripest.
How does RoofPredict help with mining old, never-closed estimates?
RoofPredict takes a list of addresses, your never-closed export works fine, and returns a roof-age range per house from aerial imagery plus storm physics modeled on that specific roof. That lets you re-grade a stale pile without driving it: houses whose roofs now read 18 to 22 years rise to the top of the call list, while houses a competitor already re-roofed read young and drop out, so you stop wasting dials. After a storm you can see which of your own past contacts had roofs the storm likely wore on. The roof age is a range, not an exact date, and the storm model gives odds, not proof, so you still confirm condition with an inspection. It is not a lead service; the homeowners are already yours.
Are there legal rules about calling and texting old roofing leads?
Yes. The Telephone Consumer Protection Act and the FTC Telemarketing Sales Rule govern calls and texts, including the federal Do Not Call registry. Exemptions for existing customers and prior business relationships exist but are narrower and more time-limited than many assume, and texting cell numbers generally requires consent. When an old estimate's house has since sold, prior consent does not carry to the new occupant. Build Do Not Call screening and consent flags into your data-cleanup step, use a dialing tool that supports scrubbing, and document opt-ins rather than bolting compliance on after a complaint.
How should I handle storm and insurance language when re-working stalled estimates?
Keep it strictly to documentation. You inspect the roof, document any storm damage with photos, and hand the homeowner the report; the homeowner files with their own carrier and the carrier decides coverage. Never say you will handle, file, manage, or negotiate the claim, never promise approval or a payout, and never discuss the homeowner's deductible. Several states treat a roofer acting as a claims advocate as unlicensed public adjusting. 'We'll document the damage and give you the facts to take to your carrier' is both accurate and safe.
How often should I dig through my CRM for never-closed estimates?
Treat it as a quarterly rhythm, not a one-time archaeology dig. Each quarter, export and reconcile your systems, dedupe and validate, re-grade roof age and storm exposure, then hand the ranked top scorers to your reps as a campaign segment. The pile regenerates constantly: fresh estimates go cold, roofs age 90 days every quarter, and storms hit. A list that felt picked-over in spring has new ripe records by summer, and tagging new estimates correctly as they go cold means next quarter's pile is already half-surfaced.
The Roofline by RoofPredict
Stay Ahead of Roofing Market Changes
Join The Roofline by RoofPredict for weekly roofing intelligence: material price signals, storm demand, insurance and regulatory updates, sales tactics, and local contractor opportunities.
Sources
- National Roofing Contractors Association (NRCA) — nrca.net
- Asphalt Roofing Manufacturers Association — asphaltroofing.org
- Insurance Institute for Business & Home Safety (IBHS) — ibhs.org
- NOAA Storm Prediction Center — spc.noaa.gov
- NOAA Storm Events Database — ncdc.noaa.gov
- National Weather Service — Thunderstorm & Hail Safety — weather.gov
- FTC — National Do Not Call Registry — ftc.gov
- FTC — Complying with the Telemarketing Sales Rule — ftc.gov
- FCC — Telemarketing and Robocalls (TCPA) — fcc.gov
- USPS — Postal Addressing Standards (Publication 28) — usps.com
- Texas Department of Insurance — Hail Damage — tdi.texas.gov
- National Association of Insurance Commissioners — Consumer Resources — naic.org
- U.S. Bureau of Labor Statistics — Roofers — bls.gov
- RoofPredict — roofpredict.com
Related Articles
How to Append Roof Age to Your Roofing Customer List (Turn a Dead Database Into a Work Queue)
You already paid to acquire every name in your database. Here is how to append a roof-age range and storm exposure to that list so you can call the customers whose roofs are finally due.
How to Write a Roof Supplement That Gets Approved the First Time
A practitioner's playbook for building roof supplements that desk adjusters approve without a fight: the photos, line items, code citations, and pricing logic that hold up the first time.
How to Keep Roofing Crews Busy Between Storms (Without Burning Cash)
Storm work is lumpy. The roofers who survive the gaps build a second engine before the sky goes quiet. Here is how to keep crews and reps producing when there is no fresh hail.