Leo from Bell & Lyons Insurance

The Smart Way to Shop for Insurance

Tap a category. Leo will guide you from there.

Bell & Lyons works with America’s top carriers

Compare Insurance Quotes in Minutes

Compare insurance quotes illustration
Bell & Lyons quote desk

Start your insurance quote with a dedicated chat.

Leo helps compare coverage, answer quick questions, and move you into the right Bell & Lyons quote without a long form.

Leo from Bell and Lyons Insurance
Leo

Online now

Hi, I’m Leo. I can help you compare coverage, answer questions, or get a quote started. What would you like to look at today? You can speak to me in English, Spanish, or French.


        

Compare Insurance With More Clarity

Insurance comparison illustration

What To Expect?

1. Start with a simple chat

Tell Leo what you are shopping for, and the conversation will guide you step by step without dropping you into a long form.

2. Get help as you go

Leo helps explain what matters, keeps the questions clear, and makes the quote process feel faster and easier to finish.

3. Move toward the right quote

By the end, you have a cleaner path to the coverage you want and Bell & Lyons has the details needed to help you compare the next step with confidence.

Explore Our Recent Insurance Guides & Articles

Gas vs. electric cars: which costs more to insure?

Gas vs. electric cars: which costs more to insure?

Florida PIP reform: what changed and what it means for your medical bills after an accident

Florida PIP reform: what changed and what it means for your medical bills after an accident

Do speeding tickets raise your insurance rate right away?

Do speeding tickets raise your insurance rate right away?

How do advanced safety features affect insurance pricing?

How do advanced safety features affect insurance pricing?

Replacement cost vs. actual cash value: why it is the most misunderstood decision Florida homeowners make

Replacement cost vs. actual cash value: why it is the most misunderstood decision Florida homeowners make

NFIP vs. private flood insurance in Florida: how to compare them beyond just price

NFIP vs. private flood insurance in Florida: how to compare them beyond just price

Loss of use coverage gaps: what happens when your Florida home is unlivable after a storm

Loss of use coverage gaps: what happens when your Florida home is unlivable after a storm

Roof age and material: how they affect your Florida homeowners premium more than almost anything else

Roof age and material: how they affect your Florida homeowners premium more than almost anything else

What does renters insurance usually protect inside the apartment?

What does renters insurance usually protect inside the apartment?

Why does renters insurance include liability if you do not own the building?

Why does renters insurance include liability if you do not own the building?

What should a renter do first after a theft or apartment loss?

What should a renter do first after a theft or apartment loss?

How can renters keep the premium manageable without making the policy weak?

How can renters keep the premium manageable without making the policy weak?

How do you compare Marketplace and private health insurance the right way?

How do you compare Marketplace and private health insurance the right way?

How should you weigh premium against deductible in a health plan?

How should you weigh premium against deductible in a health plan?

When is an ACA Marketplace plan usually the right place to start?

When is an ACA Marketplace plan usually the right place to start?

How do you check whether your doctors and hospitals fit a health plan?

How do you check whether your doctors and hospitals fit a health plan?

How do you decide whether Medicare Advantage is the right fit?

How do you decide whether Medicare Advantage is the right fit?

When does a Medicare Supplement strategy make more sense than Advantage?

When does a Medicare Supplement strategy make more sense than Advantage?

How do prescription needs affect Medicare plan choice?

How do prescription needs affect Medicare plan choice?

What Medicare enrollment timing mistakes cause the most confusion?

What Medicare enrollment timing mistakes cause the most confusion?

How should parents think about life insurance for family protection?

How should parents think about life insurance for family protection?

When does term life make more sense than permanent coverage?

When does term life make more sense than permanent coverage?

Why does life insurance matter in a business continuity plan?

Why does life insurance matter in a business continuity plan?

How should an employer compare group health plans for employees?

How should an employer compare group health plans for employees?

How should employers think about contribution strategy on group health?

How should employers think about contribution strategy on group health?

Why does timing matter so much before group health renewal?

Why does timing matter so much before group health renewal?

What should an employer prepare before starting a group health quote?

What should an employer prepare before starting a group health quote?

What does general liability actually protect for a business?

What does general liability actually protect for a business?

What does commercial property insurance cover beyond the building itself?

What does commercial property insurance cover beyond the building itself?

Why should a business review cyber and data exposure even if it is small?

Why should a business review cyber and data exposure even if it is small?

$

Don't Leave Money on the Table!

See how much you could save with Bell & Lyons

14+
Carriers
60s
Free Quote
$1,200+
Avg Saved
or
Your info is secure • No spam, ever • Unsubscribe anytime

You're All Set!

We'll send you personalized rates shortly.

Or get a quote right now →

add_action('wp_footer', function() { ?> // ─── WhatsApp Delivery Fix for Leo Commercial Chatbot ────────────── // v2 — 2026-05-03 // Fixes 3 chatbot bugs + 1 infrastructure bug: // // 1. Phone + email were asked AFTER delivery choice — if mobile // switches to WhatsApp app, contact info is never captured. // FIX: moves phone + email BEFORE delivery_preference. // 2. postLead never fires for commercial (progressiveLeadSent // is only set in _contact_capture, which snippet #22 removes). // FIX: sets progressiveLeadSent = true before delivery click. // 3. WhatsApp message shows "Client" / "the quote" because // commercial uses business_name, not first_name. // FIX: copies business_name → first_name + coverage → carrier. // 4. Snippet #9 Fix 1+2 race condition — data-webhook & postLead // patch run before the chatbot root & postLead exist in DOM/JS. // FIX: polls for root + postLead and applies the patches. // // Load order: AFTER snippet #9 & #22 (priority 15) // ─────────────────────────────────────────────────────────────────── (function() { "use strict"; var WEBHOOK = "https://bellandlyons.com/wp-json/bell-lyons/v1/lead-webhook"; /* ── 1. Re-order steps: phone + email BEFORE delivery_preference ── */ function reorderSteps() { var sources = []; if (typeof v14FlowOverrides !== "undefined") sources.push(v14FlowOverrides); if (typeof localizedContent !== "undefined") sources.push(localizedContent); sources.forEach(function(src) { ["en", "es", "fr"].forEach(function(lg) { var steps = null; try { if (src[lg] && src[lg].commercial) steps = src[lg].commercial.steps; } catch(e) {} try { if (!steps && src[lg] && src[lg].prompts && src[lg].prompts.commercial) steps = src[lg].prompts.commercial.steps; } catch(e) {} if (!steps || !steps.length) return; // Find indices var dpIdx = -1, phoneIdx = -1, emailIdx = -1; for (var i = 0; i < steps.length; i++) { if (steps[i].key === "delivery_preference") dpIdx = i; if (steps[i].key === "phone") phoneIdx = i; if (steps[i].key === "email") emailIdx = i; } // Only act if phone or email come AFTER delivery_preference if (dpIdx < 0) return; if (phoneIdx <= dpIdx && emailIdx <= dpIdx) return; // Pull out phone + email (remove from high index first) var toMove = []; [phoneIdx, emailIdx] .filter(function(x) { return x > dpIdx; }) .sort(function(a, b) { return b - a; }) .forEach(function(idx) { toMove.unshift(steps.splice(idx, 1)[0]); }); // Re-find delivery_preference (indices shifted) dpIdx = -1; for (var j = 0; j < steps.length; j++) { if (steps[j].key === "delivery_preference") { dpIdx = j; break; } } // Insert phone then email right before delivery_preference for (var k = 0; k < toMove.length; k++) { steps.splice(dpIdx + k, 0, toMove[k]); } console.log("[WA-FIX] Moved phone + email before delivery_preference (" + lg + ")"); }); }); } /* ── 2. Patch delivery button clicks ── */ function patchDeliveryClicks() { var root = document.querySelector("[data-assistant-root]"); if (!root) return false; new MutationObserver(function() { var grid = root.querySelector(".bl-delivery-grid"); if (!grid || grid.__waFixPatched) return; grid.__waFixPatched = true; var btns = grid.querySelectorAll("button"); btns.forEach(function(btn) { // Capture-phase listener runs BEFORE the original click handler btn.addEventListener("click", function() { var s = window._blCurrentState; if (!s) return; // a) Ensure postLead fires (the guard checks this flag) s.progressiveLeadSent = true; // b) WhatsApp message: use business_name as first_name fallback if (!s.answers.first_name && !s.answers.full_name) { if (s.answers.business_name) { s.answers.first_name = s.answers.business_name; } } // c) WhatsApp message: use coverage list instead of "the quote" if (!s.selectedQuoteCarrier && s.answers.coverage_needed) { s.selectedQuoteCarrier = { name: s.answers.coverage_needed }; } }, true); }); console.log("[WA-FIX] Delivery buttons patched"); }).observe(root, { childList: true, subtree: true }); return true; } /* ── 3. Fix webhook infrastructure (snippet #9 race condition) ── */ function fixWebhook() { // 3a. Set data-webhook on assistant root var root = document.querySelector("[data-assistant-root]"); if (root && !root.dataset.webhook) { root.dataset.webhook = WEBHOOK; console.log("[WA-FIX] Set data-webhook on root"); } // 3b. Patch postLead to use correct webhook URL (only if not already patched) if (typeof window.postLead === "function" && !window.postLead.__blPatched) { var _orig = window.postLead; window.postLead = function(payload, target) { // Use correct webhook URL as default instead of /api/lead-webhook (404) return _orig(payload, target || WEBHOOK); }; window.postLead.__blPatched = true; console.log("[WA-FIX] Patched postLead with correct webhook URL"); } } /* ── 4. Boot — wait for dependencies, then apply all fixes ── */ var attempts = 0; function tryBoot() { var ready = (typeof v14FlowOverrides !== "undefined") || (typeof localizedContent !== "undefined"); if (!ready) { if (++attempts < 200) setTimeout(tryBoot, 100); return; } // Give snippet #22 time to run (it polls every 50ms) setTimeout(function() { reorderSteps(); if (!patchDeliveryClicks()) { // Root not ready yet, retry var retries = 0; var iv = setInterval(function() { if (patchDeliveryClicks() || ++retries > 60) clearInterval(iv); }, 500); } console.log("[WA-FIX] WhatsApp delivery fix active"); }, 800); } tryBoot(); // Fix webhook with polling — root and postLead may load at any time var webhookAttempts = 0; function tryFixWebhook() { var root = document.querySelector("[data-assistant-root]"); var hasPostLead = typeof window.postLead === "function"; if (root && hasPostLead) { fixWebhook(); return; } if (++webhookAttempts < 200) { setTimeout(tryFixWebhook, 100); } } tryFixWebhook(); // Also re-check after snippet #9 might run (it's priority 10, we're 15) // In case postLead gets defined later by site-v13.js setTimeout(function() { fixWebhook(); }, 2000); setTimeout(function() { fixWebhook(); }, 5000); })(); // Leo Auto Coverage Step Fix (v15.0.5) — Viktor // Fixes ReferenceError: renderAutoCoverageStep defined outside renderAssistant closure // v15.0.5: Uses sendBtn.click() instead of form.dispatchEvent (no
on page) (function() { if (typeof renderAutoCoverageStep !== 'function') return; window.renderAutoCoverageStep = function(step) { var root = document.querySelector('[data-assistant-root]'); if (!root) return; var choices = root.querySelector('[data-choice-grid]'); var input = root.querySelector('[data-assistant-text]'); var sendBtn = root.querySelector('[data-assistant-send]'); var state = window._blCurrentState; if (!choices || !state) return; choices.innerHTML = ''; if (input) input.disabled = false; if (sendBtn) sendBtn.disabled = false; var compareCopy = getAutoCoverageComparisonContent(state.language); var fb = { en: ['Liability', 'Full coverage'], es: ['Solo responsabilidad civil', 'Cobertura completa'], fr: ['Responsabilite civile seulement', 'Couverture complete'] }; var opts = ((step.options && step.options.length) ? step.options : (fb[state.language] || fb.en) || []).filter(function(o) { return !isCoverageComparisonOption(o, state.language); }); opts.forEach(function(option) { var btn = document.createElement('button'); btn.type = 'button'; btn.textContent = option; btn.addEventListener('click', function() { if (input && sendBtn) { input.value = option; sendBtn.click(); } }); choices.appendChild(btn); }); var c = document.createElement('div'); c.className = 'assistant-coverage-compare'; c.innerHTML = '
' + escapeHtml(compareCopy.title) + '
' + escapeHtml(compareCopy.covered) + '
    ' + compareCopy.liabilityCovered.map(function(i){return '
  • '+escapeHtml(i)+'
  • ';}).join('') + '
' + escapeHtml(compareCopy.notCovered) + '
    ' + compareCopy.liabilityNotCovered.map(function(i){return '
  • '+escapeHtml(i)+'
  • ';}).join('') + '
'; Array.from(c.querySelectorAll('.assistant-coverage-tab')).forEach(function(tab) { tab.addEventListener('click', function() { var target = tab.dataset.coverageTab || ''; Array.from(c.querySelectorAll('.assistant-coverage-tab')).forEach(function(t) { var a = t === tab; t.classList.toggle('is-active', a); t.setAttribute('aria-selected', a ? 'true' : 'false'); }); Array.from(c.querySelectorAll('.assistant-coverage-panel')).forEach(function(p) { var a = p.dataset.coveragePanel === target; p.classList.toggle('is-active', a); p.hidden = !a; }); }); }); choices.appendChild(c); }; })(); // Leo Flow Watchdog (v15.0.6) — Viktor // Detects stuck typing indicators and force-advances the flow // v15.0.6: Handles any step transition, wraps respondWithDelay callback in try-catch, // adds error logging to localStorage for diagnostics (function() { var STUCK_MS = 4000; var lastTypingSeen = 0; var watchdogActive = false; var recovered = false; // Error logging for diagnostics function logError(msg, data) { try { var errors = JSON.parse(localStorage.getItem('bl_watchdog_log') || '[]'); errors.push({ t: new Date().toISOString(), msg: msg, data: data }); if (errors.length > 20) errors = errors.slice(-20); localStorage.setItem('bl_watchdog_log', JSON.stringify(errors)); } catch(e) {} } function getFlowConfig(state) { try { if (typeof v14FlowOverrides !== 'undefined' && state.useV14Flow) { var v14c = v14FlowOverrides[state.language] && v14FlowOverrides[state.language][state.type]; if (v14c) return { steps: v14c.steps }; } } catch(e) {} return null; } function renderContactCapture(root, log, choices, state, config, stepIndex) { var step = config.steps[stepIndex]; if (!step) return; // Scanning animation if (!state.scanningStarted && (state.type === 'auto' || state.type === 'home')) { state.scanningStarted = true; try { var scanEl = blBuildScanningAnimation(state.language); state.scanningElement = scanEl; log.appendChild(scanEl); } catch(e) { logError('scan_anim_fail', e.message); } } // Question bubble try { log.appendChild(createBubble('leo', step.question)); } catch(e) {} // Phone capture form try { var phoneForm = blBuildPhoneCaptureForm( state.language, function(phone) { state.answers.phone = phone; state.contactCaptured = true; if (typeof BL_V14 !== 'undefined') BL_V14.contactCaptured = true; try { blTrackEvent('phone_captured', { phone_masked: phone.substring(0,3) + '***' }); } catch(e) {} try { blTrackEvent('contact_captured', { method: 'phone_only', insurance_type: state.type }); } catch(e) {} if (!state.progressiveLeadSent) { state.progressiveLeadSent = true; try { postLead(buildPayload(state.type, state.answers), root.dataset.webhook); } catch(e) {} } try { log.appendChild(createBubble('user', phone)); } catch(e) {} choices.innerHTML = ''; // Advance to delivery step state.step = stepIndex + 1; var delStep = config.steps[state.step]; if (delStep && delStep.type === 'delivery_options') { renderDeliveryOptions(root, log, choices, state, config, state.step); } log.scrollTop = log.scrollHeight; }, function() { // Expand to full form choices.innerHTML = ''; if (typeof showFullContactCapture === 'function') { try { showFullContactCapture(step); return; } catch(e) {} } // Fallback full form var ff = document.createElement('div'); ff.style.cssText = 'display:flex;flex-direction:column;gap:6px;margin:8px 0;'; var ni = document.createElement('input'); ni.type='text'; ni.placeholder='Full name'; ni.className='bl-phone-input'; ni.autocomplete='name'; var pi = document.createElement('input'); pi.type='tel'; pi.placeholder='(555) 123-4567'; pi.className='bl-phone-input'; pi.autocomplete='tel'; var ei = document.createElement('input'); ei.type='email'; ei.placeholder='Email'; ei.className='bl-phone-input'; ei.autocomplete='email'; var sb = document.createElement('button'); sb.type='button'; sb.className='button primary'; sb.textContent='Continue'; ff.appendChild(ni); ff.appendChild(pi); ff.appendChild(ei); ff.appendChild(sb); sb.addEventListener('click', function() { var n=ni.value.trim(), p=pi.value.trim(), e=ei.value.trim(); if(!p&&!e){pi.focus();return;} if(n)state.answers.full_name=n; if(p)state.answers.phone=p; if(e)state.answers.email=e; state.contactCaptured=true; if(typeof BL_V14!=='undefined')BL_V14.contactCaptured=true; if(!state.progressiveLeadSent){state.progressiveLeadSent=true;try{postLead(buildPayload(state.type,state.answers),root.dataset.webhook);}catch(x){}} choices.innerHTML=''; state.step=stepIndex+1; try{log.appendChild(createBubble('user',[n,p,e].filter(Boolean).join(' | ')));}catch(x){} var delStep = config.steps[state.step]; if (delStep && delStep.type === 'delivery_options') { renderDeliveryOptions(root, log, choices, state, config, state.step); } else { state.complete=true; try{log.appendChild(createBubble('leo','Your quote is on the way!'));}catch(x){} } }); choices.appendChild(ff); ni.focus(); } ); choices.appendChild(phoneForm); } catch(e) { logError('phone_form_fail', e.message); choices.innerHTML = '
'; } log.scrollTop = log.scrollHeight; } function renderDeliveryOptions(root, log, choices, state, config, stepIndex) { var step = config.steps[stepIndex]; if (!step) return; try { log.appendChild(createBubble('leo', step.question)); } catch(e) {} try { var delivOpts = blGetDeliveryOptions(state.language); var grid = document.createElement('div'); grid.className = 'bl-delivery-grid'; delivOpts.forEach(function(opt) { var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'bl-delivery-option'; btn.textContent = opt.label; btn.addEventListener('click', function() { state.answers.delivery_preference = opt.value; state.deliveryPreference = opt.value; try { log.appendChild(createBubble('user', opt.label)); } catch(e) {} try { blTrackEvent('delivery_selected', { method: opt.value, insurance_type: state.type }); } catch(e) {} if (opt.value === 'WhatsApp' && typeof openQuoteRequestWhatsApp === 'function') { openQuoteRequestWhatsApp(); } if (state.progressiveLeadSent) { try { postLead(buildPayload(state.type, state.answers), root.dataset.webhook); } catch(e) {} } state.step += 1; state.complete = true; choices.innerHTML = ''; try { log.appendChild(createBubble('leo', blGetMicroReward('delivery', state.language, state.answers) || 'Your quote request has been submitted!')); } catch(e) { try { log.appendChild(createBubble('leo', 'Your quote request has been submitted!')); } catch(x){} } }); grid.appendChild(btn); }); choices.appendChild(grid); } catch(e) { logError('delivery_fail', e.message); } log.scrollTop = log.scrollHeight; } function renderGenericStep(root, log, choices, state, config, stepIndex) { var step = config.steps[stepIndex]; if (!step) return; try { log.appendChild(createBubble('leo', step.question)); } catch(e) {} var sendBtn = root.querySelector('[data-assistant-send]'); var input = root.querySelector('[data-assistant-text]'); if (step.options && step.options.length) { step.options.forEach(function(option) { var label = typeof option === 'string' ? option : option.label; var value = typeof option === 'string' ? option : (option.value || option.label); var btn = document.createElement('button'); btn.type = 'button'; btn.textContent = label; btn.addEventListener('click', function() { state.answers[step.key] = value; try { log.appendChild(createBubble('user', label)); } catch(e) {} if (input && sendBtn) { // Use the native submitText path for proper advancement input.value = value; sendBtn.click(); } }); choices.appendChild(btn); }); } if (input) { input.disabled = false; } if (sendBtn) { sendBtn.disabled = false; } log.scrollTop = log.scrollHeight; } function startWatchdog() { if (watchdogActive) return; watchdogActive = true; setInterval(function() { if (recovered) return; var state = window._blCurrentState; if (!state) return; var root = document.querySelector('[data-assistant-root]'); if (!root) return; var typing = root.querySelector('.bubble.typing, .bubble.leo.typing'); if (typing) { if (!lastTypingSeen) lastTypingSeen = Date.now(); var elapsed = Date.now() - lastTypingSeen; if (elapsed < STUCK_MS) return; // Typing bubble stuck — attempt recovery var config = getFlowConfig(state); if (!config || !config.steps) return; var nextStepIndex = state.step + 1; var nextStep = config.steps[nextStepIndex]; // Check conditional skip if (nextStep && nextStep.conditional) { var condAnswer = state.answers[nextStep.conditional.key]; if (condAnswer !== nextStep.conditional.value && !(nextStep.conditional.values && nextStep.conditional.values.indexOf(condAnswer) >= 0)) { nextStepIndex += 1; nextStep = config.steps[nextStepIndex]; } } if (!nextStep) return; recovered = true; logError('watchdog_recovery', { fromStep: state.step, toStep: nextStepIndex, stepType: nextStep.type, stepKey: nextStep.key }); // Remove typing bubble and old choices typing.remove(); var log = root.querySelector('[data-assistant-log]'); var choices = root.querySelector('[data-choice-grid]'); if (!log || !choices) return; choices.innerHTML = ''; // Update progress bar state.step = nextStepIndex; try { blUpdateProgressBar(log, state.step, config.steps.length, state.language); } catch(e) {} try { blSaveState(state); } catch(e) {} // Render based on step type if (nextStep.type === 'contact_capture') { renderContactCapture(root, log, choices, state, config, nextStepIndex); } else if (nextStep.type === 'delivery_options') { renderDeliveryOptions(root, log, choices, state, config, nextStepIndex); } else { renderGenericStep(root, log, choices, state, config, nextStepIndex); } } else { lastTypingSeen = 0; } }, 1500); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startWatchdog); } else { startWatchdog(); } })();