Microsoft 365 Copilot ROI Calculator
Start with the break-even. How many minutes a day must each active user save to cover the license? Then see payback, net value over your horizon and a sensitivity grid. Every assumption is an input you can change.
Sensitivity: net value per month
Rows are minutes saved per active user per day; columns are the share of seats in active use.
How to read this
Break-even minutes
The license cost divided by the value of one saved minute across your active users. If people save more than this each workday, Copilot covers its license.
Realization
Not every saved minute becomes useful output. Realization discounts the time saved to what actually turns into work; 50% is a cautious starting point.
What is not included
Copilot Chat agents and metered consumption are billed separately by Microsoft. Run a measured pilot with a few teams before buying for everyone.
window.C2N = (function () { function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); } function fire(el) { el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); } function enhance(form) { [].forEach.call(form.querySelectorAll('select[data-seg]'), function (sel) { var seg = document.createElement('div'); seg.className = 'c2n-seg'; seg.setAttribute('role', 'radiogroup'); seg.style.gridTemplateColumns = 'repeat(' + Math.min(sel.options.length, +sel.dataset.seg || sel.options.length) + ',1fr)'; [].forEach.call(sel.options, function (o) { var b = document.createElement('button'); b.type = 'button'; b.textContent = o.textContent; b.dataset.v = o.value; b.setAttribute('role', 'radio'); b.addEventListener('click', function () { sel.value = o.value; sync(form); fire(sel); }); seg.appendChild(b); }); sel.hidden = true; sel.parentNode.insertBefore(seg, sel.nextSibling); }); [].forEach.call(form.querySelectorAll('input[data-range]'), function (num) { var r = num.dataset.range.split(','), rg = document.createElement('input'); rg.type = 'range'; rg.min = r[0]; rg.max = r[1]; rg.step = r[2] || 1; rg.className = 'c2n-range'; rg.setAttribute('aria-label', num.name); rg.addEventListener('input', function (e) { e.stopPropagation(); num.value = rg.value; fire(num); }); num.parentNode.appendChild(rg); }); } function sync(form) { [].forEach.call(form.querySelectorAll('select[data-seg]'), function (sel) { [].forEach.call(sel.nextSibling.children, function (b) { var on = b.dataset.v === sel.value; b.classList.toggle('on', on); b.setAttribute('aria-checked', on); }); }); [].forEach.call(form.querySelectorAll('input[data-range]'), function (num) { num.parentNode.querySelector('.c2n-range').value = num.value; }); } function render(el, r) { var h = '<div class="c2n-cx-bar"><span>Results · ' + esc(r.title) + (r.unit === undefined ? ' · USD' : r.unit) + '</span><span class="c2n-cx-live">Live</span></div>'; if (r.lead) h += '<p class="c2n-cx-lead">' + r.lead + '</p>'; if (r.kpis) h += '<div class="c2n-cx-kpis">' + r.kpis.map(function (k, i) { return '<div class="c2n-cx-kpi' + (i ? '' : ' on') + '"><small>' + esc(k[0]) + '</small><b>' + k[1] + '</b><span>' + (k[2] || '') + '</span></div>'; }).join('') + '</div>'; if (r.rows) { var cell = function (tag) { return function (c, i) { return '<' + tag + (i ? ' class="n"' : '') + '>' + c + '</' + tag + '>'; }; }; h += '<div class="c2n-cx-scroll"><table class="c2n-cx-table">' + (r.head ? '<tr>' + r.head.map(cell('th')).join('') + '</tr>' : '') + r.rows.map(function (row) { return '<tr>' + row.map(cell('td')).join('') + '</tr>'; }).join('') + (r.total ? '<tr class="t">' + r.total.map(cell('td')).join('') + '</tr>' : '') + '</table></div>'; } h += '<div class="c2n-cx-foot"><p>' + (r.note || '') + '</p>' + (r.cta ? '<a class="c2n-cx-btn" href="' + esc(r.cta[1]) + '">' + esc(r.cta[0]) + '</a>' : '') + '</div>'; el.innerHTML = h; } function money(n, d) { return (n < 0 ? '-$' : '$') + Math.abs(n).toLocaleString('en-US', { minimumFractionDigits: d || 0, maximumFractionDigits: d || 0 }); } function values(form) { var v = {}; [].forEach.call(form.elements, function (el) { if (el.name) v[el.name] = el.type === 'number' ? Math.max(0, +el.value || 0) : el.value; }); return v; } function restore(form) { var q = new URLSearchParams(location.search); [].forEach.call(form.elements, function (el) { if (el.name) { if (q.has(el.name)) el.value = q.get(el.name); } }); } function save(form) { var o = {}; [].forEach.call(form.elements, function (el) { if (el.name) o[el.name] = el.value; }); history.replaceState(null, '', '?' + new URLSearchParams(o)); } function mount(form, calc) { enhance(form); restore(form); var run = function () { sync(form); calc(values(form)); save(form); }; form.addEventListener('input', run); form.addEventListener('submit', function (e) { e.preventDefault(); }); run(); } return { mount: mount, render: render, money: money, esc: esc, sync: sync, enhance: enhance }; })(); (function () { var P = {"Microsoft 365 Copilot (add-on)":{"c":[360,31.5,null]},"Microsoft 365 Copilot Business (add-on)":{"c":[252,22.05,25.2]}}; var $ = C2N.money; C2N.mount(document.getElementById('cr'), function (x) { x.active = Math.min(100, x.active) / 100; x.real = Math.min(100, x.real) / 100; x.seats = Math.max(1, x.seats); x.months = Math.max(1, x.months); x.price = P[x.ed === 'biz' ? 'Microsoft 365 Copilot Business (add-on)' : 'Microsoft 365 Copilot (add-on)'].c[0] / 12; function net(mins, active) { return x.seats * active * mins / 60 * x.days * x.rate * x.real - x.seats * x.price; } var cost = x.seats * x.price, perMin = x.seats * x.active * x.days * x.rate * x.real / 60; var be = perMin > 0 ? cost / perMin : Infinity, monthly = net(x.mins, x.active); var payback = monthly > 0 ? Math.max(1, Math.ceil(x.setup / monthly)) : null, horizon = monthly * x.months - x.setup; var cls = function (n) { return n >= 0 ? 'c2n-cx-ok' : 'c2n-cx-bad'; }; C2N.render(document.getElementById('cr-out'), { title: 'Copilot ROI', lead: 'At ' + $(x.price * 12) + ' per seat per year, each active user must save <strong>' + (isFinite(be) ? be.toFixed(1) : 'n/a') + ' minutes a day</strong> for the licenses to pay for themselves. You assumed ' + x.mins + '.', kpis: [['Break-even', isFinite(be) ? be.toFixed(1) + ' min' : 'n/a', 'per active user per day'], ['Net over ' + x.months + ' months', '<span class="' + cls(horizon) + '">' + $(horizon) + '</span>', payback ? 'pays back in month ' + payback : 'does not pay back']], head: ['Monthly', 'Amount'], rows: [['License cost (' + x.seats + ' seats)', $(cost)], ['Value of time saved', $(cost + monthly)], ['One-time rollout', $(x.setup)]], total: ['Net per month', '<span class="' + cls(monthly) + '">' + $(monthly) + '</span>'], note: 'Microsoft US list price, annual commitment, current month. Defaults are a cautious starting point, not a promise.', cta: ['Plan a Copilot pilot', '/tools/forms/?f=quote&items=' + encodeURIComponent('Microsoft 365 Copilot pilot: ' + x.seats + ' seats')] }); var actives = [0.3, 0.5, 0.7, 0.9], minsList = [5, 10, 20, 30, 45, 60]; document.getElementById('cr-grid').innerHTML = '<tr><th>Minutes / day</th>' + actives.map(function (a) { return '<th class="n">' + a * 100 + '% active</th>'; }).join('') + '</tr>' + minsList.map(function (m) { return '<tr><td>' + m + ' min</td>' + actives.map(function (a) { var n = net(m, a); return '<td class="n ' + (n >= 0 ? 'ok' : 'bad') + '">' + $(n) + '</td>'; }).join('') + '</tr>'; }).join(''); }); })();