HVAC is a seasonal business pretending to be a year-round one. The first cold night and the first hot week generate more calls than you can take, and the eight weeks either side generate almost none. Both problems have the same solution, applied at different times of year.
- Demand spikes a year
- 2Demand spikes a year
- Shoulder seasons to fill
- 2Shoulder seasons to fill
- Message that fills them
- 1Message that fills them
- Natural maintenance cycle
- 12moNatural maintenance cycle
Fill the shoulder seasons before the spike arrives
Nobody thinks about their furnace in September. That is exactly why September is when you should be booking furnace work — the customer is not competing with anyone for your time, and you are not turning down emergency money to do it.
export const seasonal = { preHeating: (c: Ctx) => `${c.company}: booking furnace tune-ups now for October. ` + `Cheaper than a callout in January and you get to pick the day. ` + `Reply BOOK and I'll send times: ${c.link}`, preCooling: (c: Ctx) => `${c.company}: AC service season. We did yours ${c.lastServiceMonth} — ` + `want the same slot this year? Reply YES and I'll pencil it in.`, // The most effective one. Specific, personal, and impossible to // mistake for a mailshot. knownUnit: (c: Ctx) => `${c.company}: your ${c.unitAge}-year-old ${c.unitModel} is due its ` + `annual. Last year we flagged ${c.lastIssue} — worth checking before ` + `it gets cold. Reply and I'll find a slot.`,};Reference the specific unit and the last visit
'Your 11-year-old Carrier is due, and last year we noted the capacitor was reading low' cannot be sent by a competitor and cannot be mistaken for spam. It is the single biggest advantage a local HVAC firm has over a national one, and it only works if your CRM holds the history — see CRM integration.
Triage during the spike
On the first freezing night you will get more calls than you can serve. The honest thing — and the thing that keeps customers — is to sort them fast and tell people the truth about when you can come.
export const triage = { intake: (c: Ctx) => `${c.company}: we're at capacity tonight. Quick check so we can ` + `prioritise — reply with 1, 2 or 3:\n` + `1 = no heat at all\n2 = heat but weak\n3 = noise or smell`, noHeatVulnerable: (c: Ctx) => `${c.company}: you're on tonight's list — ${c.tech}, roughly ${c.eta}. ` + `If it drops below ${c.tempThreshold} before then, please call ${c.phone}.`, scheduled: (c: Ctx) => `${c.company}: booked for ${c.dayDate}, ${c.window}. ` + `In the meantime: ${c.link} has a couple of things worth checking ` + `— sometimes it's just the filter or the breaker.`,};A no-heat call in freezing weather can be a welfare issue
Elderly customers, infants and anyone with a medical condition need escalating to a phone call, not left in a text queue. Build that as a rule in your intake, not a judgement your dispatcher makes at 11pm.
Maintenance plans live or die on the renewal message
A maintenance agreement is the most valuable thing an HVAC company sells, and most of them churn silently — the customer never decides to leave, they just are not reminded. A plain renewal text with the year's visits listed converts far better than an invoice arriving unannounced.
- Say what they got. Two visits, a filter, and priority booking in January — reminding them of the value is most of the sale.
- Say what it costs, before it charges. A surprise renewal charge is how you turn a loyal customer into a chargeback.
- Make cancelling easy. The ones who would have cancelled anyway leave quietly instead of angrily, and the rest trust you more.
The pricing side of running this channel is on the pricing page — for a firm with one line and a few hundred customers, this is well under a hundred dollars a month.
Next step
Browse the other industry playbooks, compare the services that can send this on the providers page, or tag your links with the UTM builder.