play icon for videos
← Academy
SOPACT ACADEMY · AI SKILLS

Calculate the SROI Ratio with NPV and Sensitivity

From your value map, Sopact Sense discounts multi-year value to a present value, divides by inputs for the ratio, and runs a sensitivity check on the top assumptions — so you report a defensible range, not a single suspicious number.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> @keyframes pulseDot{0%,100%{opacity:1}50%{opacity:.35}} *{box-sizing:border-box} body{margin:0;font-family:'Hanken Grotesk',-apple-system,BlinkMacSystemFont,sans-serif;background:#EEF2F9;padding:26px;display:flex;justify-content:center} .card{width:600px;max-width:100%;background:#FFFFFF;border:1px solid #E3E9F4;border-radius:20px;box-shadow:0 26px 64px -32px rgba(15,30,70,.34),0 2px 4px rgba(15,30,70,.05);overflow:hidden} .hdr{display:flex;align-items:center;gap:11px;padding:16px 20px;border-bottom:1px solid #EEF1F7;background:#F5F8FE} .hdr .ic{display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border:2px solid #155DFC;border-radius:50%;color:#155DFC;font-size:15px;font-weight:800;flex-shrink:0} .hdr .t{min-width:0} .hdr .t .n{font-weight:800;font-size:14.5px;color:#0F172A;letter-spacing:-.2px} .hdr .t .s{font-size:12px;color:#64748B} .hdr .pill{margin-left:auto;display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:700;color:#155DFC;background:#E6EEFF;padding:5px 10px;border-radius:20px;white-space:nowrap} .hdr .pill .d{width:6px;height:6px;border-radius:50%;background:#155DFC;animation:pulseDot 2s infinite} .tabs{display:flex;gap:0;padding:12px 16px 0;background:#F5F8FE} .tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;font-family:inherit;font-size:11.5px;font-weight:700;color:#64748B;background:transparent;border:none;border-bottom:2px solid transparent;padding:8px 4px 10px} .tab.on{font-weight:800;color:#155DFC;border-bottom-color:#155DFC} .tab .num{display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;border-radius:50%;font-size:11px;font-weight:800;color:#64748B;background:#EEF1F7} .tab.on .num{color:#fff;background:#155DFC} .divider{height:1px;background:#EEF1F7} .body{padding:20px} .eyebrow{font-size:10.5px;font-weight:800;letter-spacing:1.2px;text-transform:uppercase;color:#155DFC;margin-bottom:5px} .eyebrow.g{color:#15884F} .headline{font-family:'Inter',Georgia,serif;font-size:18.5px;font-weight:600;line-height:1.25;color:#0F172A;margin-bottom:12px} .lede{font-size:12.5px;line-height:1.55;color:#475569;margin:0 0 14px} .rows{display:flex;flex-direction:column;gap:8px;margin-bottom:14px} .row{display:flex;align-items:center;gap:11px;background:#F5F8FE;border:1px solid #EEF1F7;border-radius:11px;padding:11px 13px} .row .emoji{font-size:17px} .row .rt{flex:1;min-width:0} .row .rt .n{font-size:13px;font-weight:700;color:#0F172A} .row .rt .s{font-size:12px;color:#64748B} .pillsm{font-size:11px;font-weight:800;color:#155DFC;background:#E6EEFF;padding:4px 9px;border-radius:6px;flex-shrink:0} .pillsm.gray{font-weight:700;color:#64748B;background:#EEF1F7} /* chain / timeline */ .chainwrap{position:relative;padding-left:26px} .chainline{position:absolute;left:8px;top:8px;bottom:8px;width:2px;background:#E3E9F4} .cnode{position:relative;margin-bottom:14px} .cdot{position:absolute;left:-26px;top:4px;width:16px;height:16px;border-radius:50%;background:#fff;border:3px solid #94A3B8} .clabel{font-size:9.5px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#64748B;margin-bottom:4px} .cbox{background:#F5F8FE;border:1px solid #EEF1F7;border-radius:11px;padding:10px 12px;font-size:12px;line-height:1.5;color:#334155} .cbox.graded{display:flex;align-items:flex-start;gap:9px;border-left-width:3px;border-left-style:solid} .cnote{margin:0 0 14px 4px;font-size:11px;line-height:1.5} .cnote .plus{display:inline-flex;width:16px;height:16px;align-items:center;justify-content:center;background:#155DFC;color:#fff;border-radius:4px;font-size:10px;font-weight:800;flex-shrink:0;margin-right:6px} .csummary{display:flex;align-items:center;gap:12px;background:#0A1B3D;border-radius:13px;padding:11px 15px;margin-top:4px} .csummary .t{flex:1;font-size:11.5px;color:#CBD8F5} .csummary .t b{color:#F1F5FF} /* matrix */ .mxwrap{border:1px solid #EEF1F7;border-radius:12px;overflow:hidden;margin-bottom:10px} .mxhead{display:grid;grid-template-columns:118px 1fr 1fr;background:#F5F8FE;border-bottom:1px solid #EEF1F7} .mxhead div{font-size:9px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#64748B;padding:7px 9px} .mxrow{display:grid;grid-template-columns:118px 1fr 1fr;border-bottom:1px solid #EEF1F7} .mxrow:last-child{border-bottom:none} .mxrow>div{padding:9px;font-size:11.5px;line-height:1.4;color:#334155;display:flex;align-items:center;flex-wrap:wrap;gap:5px} .mxrow .mxlabel{font-weight:700;color:#0F172A;background:#FAFBFE} .mxchip{font-size:9px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;padding:3px 6px;border-radius:5px;white-space:nowrap} .promptwrap{padding:0 20px 18px} .promptlbl{font-size:10px;font-weight:800;letter-spacing:1px;text-transform:uppercase;color:#94A3B8;margin-bottom:7px} .prompt{display:flex;align-items:flex-start;gap:9px;font-family:ui-monospace,'SF Mono',Menlo,monospace;font-size:11px;line-height:1.5;color:#1E293B;background:#F5F8FE;border:1px solid #EEF1F7;border-left:3px solid #155DFC;border-radius:9px;padding:11px 12px} .prompt .car{color:#155DFC;font-weight:800;flex-shrink:0} .flagrow{display:flex;align-items:flex-start;gap:10px;background:#F5F8FE;border:1px solid #EEF1F7;border-radius:11px;padding:10px 12px;border-left-width:3px;border-left-style:solid;margin-bottom:8px} .flagtag{font-size:9.5px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;padding:4px 8px;border-radius:5px;white-space:nowrap;flex-shrink:0} .flagtxt{font-size:12px;line-height:1.45;color:#334155} .lp{display:flex;align-items:center;gap:12px;background:#0A1B3D;border-radius:13px;padding:14px 16px;margin-top:6px} .lp .ic{display:inline-flex;width:34px;height:34px;align-items:center;justify-content:center;background:#14295C;border:1px solid #26407A;border-radius:9px;color:#7FA8FF;font-size:16px;flex-shrink:0} .lp .rt{flex:1;min-width:0} .lp .rt .n{font-size:13px;font-weight:800;color:#F1F5FF} .lp .rt .s{font-size:11.5px;color:#9DB2D9} .lp .open{font-size:11px;font-weight:800;color:#0A1B3D;background:#7FA8FF;padding:6px 11px;border-radius:7px;white-space:nowrap} </style> </head> <body> <div class="card"> <div class="hdr"> <span class="ic">&#128202;</span> <div class="t"> <div class="n">Investee SROI · SROI Ratio &amp; NPV</div> <div class="s">DEMO-07 · Sopact Sense · SROI Investee</div> </div> <span class="pill"><span class="d"></span>Calculating</span> </div> <div class="tabs" id="tabs"></div> <div class="divider"></div> <div class="body" id="body"></div> <div class="promptwrap"> <div class="promptlbl">The prompt behind this step</div> <div class="prompt"><span class="car">&gt;</span><span id="promptTxt"></span></div> </div> </div> <script> (function(){ var TABS = ["Setup", "Calculate", "Fix", "Report"]; var CONTENT = [{"eyebrow": "Step 1 · Load the dataset", "headline": "The input is your Decision Brief, nothing else", "lede": "Clean data with persistent contact IDs, loaded before any ratio gets computed.", "prompt": "You are the Sopact Sense Assistant working over the [DEMO] dataset (clean data + persistent contact IDs). Load my Decision Brief (decision, audience, outcomes, indicators, evidence standard) first, then wait for my task."}, {"eyebrow": "Step 2 · Compute ratio + sensitivity", "headline": "NPV, ratio, and a range — not one number", "lede": "Each line is graded <strong style=\"color:#15884F\">green</strong>, <strong style=\"color:#C9820A\">amber</strong>, <strong style=\"color:#C63E2B\">red</strong> — a single-point ratio without a sensitivity check stays amber.", "prompt": "From the value map for [PROGRAM], discount multi-year net values at [DISCOUNT_RATE], sum to PV, divide by inputs; sensitivity on top two assumptions ±[PCT]%. Grade green/amber/red."}, {"eyebrow": "Step 3 · One-fix follow-up", "headline": "Bound the ratio", "lede": "The lowest-graded element gets one realistic fix — the single edit that moves it toward green.", "prompt": "Take the lowest-graded element above and fix it using only what the program could realistically measure. Show the before → after grade and the single indicator/edit that moves it to green."}, {"eyebrow": "Step 4 · Missing & incomplete report", "headline": "Every gap becomes one named ask", "lede": "Every amber or red item becomes one named ask — the report leads with the decision it informs.", "prompt": "Create a 'missing & incomplete' report from this analysis in Sopact branding [or paste your website URL / brand guideline to apply your own]. List every element graded amber or red, what is missing, and the one input that fixes each. Lead with the decision this report informs."}]; var BODIES = { setup: "<div class=\"row\"><span class=\"emoji\">&#128202;</span><div class=\"rt\"><div class=\"n\">SROI Investee dataset</div><div class=\"s\">DEMO-07 · clean data + persistent contact IDs</div></div><span class=\"pillsm\">Loaded</span></div><div class=\"row\"><span class=\"emoji\">&#128203;</span><div class=\"rt\"><div class=\"n\">Decision Brief</div><div class=\"s\">Decision, audience, outcomes, indicators, evidence standard</div></div><span class=\"pillsm gray\">Structure</span></div><div class=\"row\"><span class=\"emoji\">&#128202;</span><div class=\"rt\"><div class=\"n\">Value map (from prior step)</div><div class=\"s\">REC-1042 — multi-year net values ready to discount</div></div><span class=\"pillsm gray\">Loaded</span></div>", build: "<div class=\"mxwrap\"><div class=\"mxhead\"><div></div><div>Value</div><div>Note</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Present value of value</div><div>$2.1M<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>3% discount</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Total inputs</div><div>$0.7M</div><div>incl. in-kind</div></div><div class=\"mxrow\"><div class=\"mxlabel\">SROI ratio</div><div>3.0 : 1<span class=\"mxchip\" style=\"background:#C9820A;color:#fff\">AMBER</span></div><div>range 2.4-3.6 under ±15%</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Beyond year 1</div><div>—<span class=\"mxchip\" style=\"background:#C63E2B;color:#fff\">RED</span></div><div>no duration data</div></div></div>", fix: "<div class=\"mxwrap\"><div class=\"mxhead\"><div></div><div>Value</div><div>Note</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Present value of value</div><div>$2.1M<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>3% discount</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Total inputs</div><div>$0.7M</div><div>incl. in-kind</div></div><div class=\"mxrow\"><div class=\"mxlabel\">SROI ratio</div><div>±15% sensitivity run on proxy + attribution<span class=\"mxchip\" style=\"background:#15884F;color:#fff\">GREEN</span></div><div>range 2.4-3.6 under ±15%</div></div><div class=\"mxrow\"><div class=\"mxlabel\">Beyond year 1</div><div>—<span class=\"mxchip\" style=\"background:#C63E2B;color:#fff\">RED</span></div><div>no duration data</div></div></div><div class=\"cnote\" style=\"color:#15884F;margin-left:0\"><span class=\"plus\">+</span><strong>Fix applied:</strong> Run ±15% sensitivity on proxy + attribution</div>", reportFlags: "<div class=\"flagrow\" style=\"border-left-color:#C9820A\"><span class=\"flagtag\" style=\"color:#C9820A;background:#FBF0DA\">AMBER</span><div class=\"flagtxt\">SROI ratio — 3.0:1 is reported as a single point, with no sensitivity range yet run.</div></div><div class=\"flagrow\" style=\"border-left-color:#C63E2B\"><span class=\"flagtag\" style=\"color:#C63E2B;background:#FCE9E7\">RED</span><div class=\"flagtxt\">Beyond year 1 — no duration data exists to value multi-year impact.</div></div>", lpTitle: "Missing & incomplete report · shareable link", lpSub: "Decision-first · Sopact branding · Investee SROI · SROI Ratio & NPV", summaryBefore: "Grade: 1 green &middot; 1 amber &middot; 1 red. A ratio with no range yet.", summaryAfter: "Grade: 2 green &middot; 0 amber &middot; 1 red. A range, not one number." }; var phase = 1; var tabsEl = document.getElementById('tabs'); var bodyEl = document.getElementById('body'); var promptEl = document.getElementById('promptTxt'); function renderTabs(){ tabsEl.innerHTML = ''; TABS.forEach(function(label, i){ var b = document.createElement('button'); b.type = 'button'; b.className = 'tab' + (i === phase ? ' on' : ''); b.innerHTML = '<span class="num">' + (i+1) + '</span><span>' + label + '</span>'; b.addEventListener('click', function(){ phase = i; render(); }); tabsEl.appendChild(b); }); } function renderBody(){ var c = CONTENT[phase]; var eyebrowClass = (phase===2) ? 'eyebrow g' : 'eyebrow'; var out = '<div class="' + eyebrowClass + '">' + c.eyebrow + '</div><div class="headline">' + c.headline + '</div><p class="lede">' + c.lede + '</p>'; if (phase === 0) { out += '<div class="rows">' + BODIES.setup + '</div>'; } else if (phase === 1) { out += BODIES.build; out += '<div class="csummary"><div class="t"><b>' + BODIES.summaryBefore + '</b></div></div>'; } else if (phase === 2) { out += BODIES.fix; out += '<div class="csummary"><div class="t"><b>' + BODIES.summaryAfter + '</b></div></div>'; } else { out += BODIES.reportFlags; out += '<div class="lp"><span class="ic">&#128196;</span><div class="rt"><div class="n">' + BODIES.lpTitle + '</div><div class="s">' + BODIES.lpSub + '</div></div><span class="open">Open &rarr;</span></div>'; } bodyEl.innerHTML = out; promptEl.textContent = c.prompt; } function render(){ renderTabs(); renderBody(); } render(); })(); </script> </body> </html>

In short: The SROI ratio is the present value of the net outcomes divided by the value invested. To calculate it credibly you discount multi-year value to today's money (the NPV), divide by inputs, and — crucially — run a sensitivity check so you report a range rather than a single point. Point Sopact Sense at your value map; it computes the ratio and grades each step — green where the present value is computed, amber where the ratio is a single point, red where there's no duration data to discount.

1 · Set up over your data

The ratio is the last step, and it inherits every weakness below it. Work from your value map over a clean dataset and load your Decision Brief so Sense knows the evidence standard:

You are the Sopact Sense Assistant working over the [DEMO] dataset (clean data + persistent contact IDs). Load my Decision Brief (decision, audience, outcomes, indicators, evidence standard) first, then wait for my task.

2 · Write the ratio-and-sensitivity prompt

Ask for the present value, the ratio, and the sensitivity in one move — a ratio with no range isn't finished:

From the value map for [PROGRAM], discount multi-year net values at [DISCOUNT_RATE], sum to PV, divide by inputs; sensitivity on top two assumptions ±[PCT]%. Grade green / amber / red.

Five elements make it credible: the dataset (the value map underneath); the NPV and ratio (discounted, then divided by inputs); the sensitivity (test the two assumptions the answer depends on most); reporting a range (not a single suspicious figure); and the grade (green / amber / red at a glance).

3 · What Sense computes

Sense returns the present value, the ratio, and a sensitivity range, with each step graded. The demo runs on the SROI Investee dataset, engineered to grade one green, one amber, one red:

Run on the SROI Investee dataset (DEMO 07) already loaded in Sopact Sense.

GRADE: green | Present value | discounted and computed correctly; amber | Ratio | reported as a single point, no range; red | Duration | no drop-off data, so multi-year value can't be discounted

The green step is a correctly discounted present value, the amber step is a ratio stated as one number with no sensitivity range, and the red step is missing duration data — without it, multi-year value can't be discounted honestly.

4 · Turn a weak link green

The ratio is worth most when you fix what makes it fragile. Take the lowest-graded step and strengthen it with one realistic change:

Take the lowest-graded element above and fix it using only what the program could realistically measure. Show the before → after grade and the single indicator/edit that moves it to green.

For the investee, that's collecting how long each outcome persists — a short duration question — so multi-year value can be discounted instead of guessed.

5 · Make the report and share it

Generate a decision-first report in your own brand, then a shareable link:

Create a 'missing & incomplete' report from this analysis in Sopact branding [or paste your website URL / brand guideline to apply your own]. List every element graded amber or red, what is missing, and the one input that fixes each. Lead with the decision this report informs.
Create a shareable link for this report and open it in a new tab.

Tricks, tips, and troubleshooting

A point estimate isn't finished. Any SROI ratio reported as a single number invites suspicion. Ask Sense for a low / central / high range based on the two assumptions the result is most sensitive to.

Discount honestly. Use a stated discount rate and apply it to every future year; don't count year-three value as if it lands today. Ask Sense to show the discounting year by year.

Duration drives the multi-year value. If you don't know how long an outcome lasts, you can't discount it credibly. Ask Sense which outcomes lack duration data — that's usually the reddest part of the calculation.

Tighten the inputs while you're here. Ask Sense which assumption the ratio depends on most, so you know where to invest in better evidence:

Which single assumption does this SROI ratio depend on most, and what would it take to measure it instead of assuming it?

Frequently asked questions

How do you calculate the SROI ratio?

Take the net value of each outcome from the value map (after deadweight, attribution, displacement and drop-off), discount any multi-year value to present value, sum it, and divide by the total inputs invested. A ratio of 3:1 means three dollars of social value per dollar invested. The credibility lives in the adjustments, the sourced proxies, and a sensitivity range — not the headline figure.

What is NPV in SROI?

NPV (net present value) is the value of future outcomes expressed in today's money. Because an outcome that lasts three years isn't worth the same as one that lands immediately, each future year's value is discounted by a stated rate before it's summed. Using NPV is what stops an SROI from overcounting long-duration outcomes.

Why does an SROI ratio need a sensitivity range?

Because the ratio rests on assumptions — proxies, deadweight, attribution, duration — each with uncertainty. A single point implies a precision the data doesn't support. A sensitivity check varies the two most important assumptions by a set percentage and reports the resulting low-to-high range, which is far more credible to a funder than one suspiciously exact number.

Ready to try it for yourself?

Open Sopact Sense, paste your program description, and put it to work.

Try in Sopact