Real-time ROI across four Innovid solution pillars. Built for live client conversations — no submit button, no spreadsheets.
var CREATIVE_PRESETS={conservative:[5,5],aggressive:[30,30]};
function buildCreative(){
var wfRows=ROI_DEFAULTS.workflow.map(function(r,i){return wfRow('d_wf',i,r);}).join('');
var left='
'
+'
Scenario
'+SCENARIO_NOTE+'
'
+'
'+seclabel('1','Primary inputs')
+field('Total media budget','Display + video, annual',money('d_budget',50000000,1000000,'$'))
+field('Video share of budget',null,'
';
document.querySelectorAll('#mode-creative input').forEach(function(i){i.addEventListener('input',renderCreative);});
var pv=document.getElementById('d_pv');pv.addEventListener('input',function(){document.getElementById('d_pvL').textContent=pv.value+'%';document.getElementById('d_pvR').textContent=(100-pv.value)+'%';});
var pc=document.getElementById('d_pc');pc.addEventListener('input',function(){document.getElementById('d_pcL').textContent=pc.value+'%';document.getElementById('d_pcR').textContent=(100-pc.value)+'%';});
bindDrawerToggle('#mode-creative');
function applyCreativePreset(key){var P=CREATIVE_PRESETS[key];document.getElementById('d_lv').value=P[0];document.getElementById('d_ld').value=P[1];document.querySelectorAll('#dco_presets button').forEach(function(x){x.classList.toggle('on',x.getAttribute('data-p')===key);});renderCreative();}
document.querySelectorAll('#dco_presets button').forEach(function(b){b.addEventListener('click',function(){applyCreativePreset(b.getAttribute('data-p'));});});
applyCreativePreset('conservative');
}
function readCreativeWorkflow(){var g=function(id){return document.getElementById(id).value;};return ROI_DEFAULTS.workflow.map(function(r,i){return{role:r.role,fte:g('d_wf_fte_'+i),salary:g('d_wf_sal_'+i),effPct:g('d_wf_eff_'+i)};});}
function renderCreative(){
var g=function(id){return document.getElementById(id).value;};
var args={totalBudget:g('d_budget'),pctVideo:g('d_pv')/100,pctCTV:g('d_pc')/100,roasVideo:g('d_rv')/100,roasDisplay:g('d_rd')/100,liftVideo:g('d_lv')/100,liftDisplay:g('d_ld')/100,persVideo:g('d_pvv')/100,persDisplay:g('d_pdd')/100,
ctvCpm:g('d_ctvcpm'),olvCpm:g('d_olvcpm'),displayCpm:g('d_dispcpm'),videoTechFee:g('d_vfee')/100,displayTechFee:g('d_dfee')/100,videoServStd:g('d_vstd'),videoServAll:g('d_vall'),displayServStd:g('d_dstd'),displayServAll:g('d_dall'),
workflow:readCreativeWorkflow()};
var r=calcPersonalizationROI(args);
if(!r.valid)return;
document.getElementById('dco_hero').innerHTML=hero('Creative personalization — ROI',r.blendedRoiMultiple,'Invest',r.personalizationCost,'Total return',r.totalBenefits,'Hard-dollar ROI (revenue only, excl. workflow): '+mult(r.hardRoiMultiple)+' · breaks even at just '+pct(r.breakevenLift,1)+' performance lift — this scenario assumes '+g('d_lv')+'% (industry studies: 10–30%)');
var t=document.querySelectorAll('#mode-creative .tile .v');
t[0].textContent=mult(r.blendedRoiMultiple);t[1].textContent=usdC(r.incrementalRevenue);t[2].textContent=pct(r.breakevenLift,1);
document.getElementById('d_tag_workflow_group').textContent=usdC(r.workflow.workflowSavings);
document.getElementById('d_tag_perf_group').textContent=usdC(r.incrementalRevenue);
document.getElementById('d_wf_note').innerHTML='Frees '+r.workflow.fteFreed.toFixed(2)+' FTE of '+r.workflow.totalFte.toFixed(1)+' → '+r.workflow.fteAfter.toFixed(2)+' remaining.';
document.getElementById('dco_sub').textContent='Axis zoomed to highlight the incremental lift ('+usdC(r.incrementalRevenue)+').';
var lo=r.revenueBefore*0.97,hi=r.revenueAfter,rng=(hi-lo)||1;
var bars=[['Before',r.revenueBefore,C.o4],['After',r.revenueAfter,'linear-gradient(180deg,'+C.ocean+','+C.dory+')']];
document.getElementById('dco_bars').innerHTML=bars.map(function(b){var h=20+((b[1]-lo)/rng)*70;return '
'+usdC(b[1])+'
'+b[0]+'
';}).join('');
var ch=[['Video (CTV + OLV)',r.video,C.dory],['Display',r.display,C.purple]];
document.getElementById('dco_channels').innerHTML=ch.map(function(c){var o=c[1];return '
'
+'';
repop('dco_hero');
}
/* ============================= AD SERVING ============================= */
var AS_PRESETS={conservative:{lp:[8,4,2],le:[4,3,3],waste:40},aggressive:{lp:[15,12,8],le:[6,5,5],waste:90}};
function buildAdServing(){
var d=AD_SERVING_DEFAULTS;
var wfRows=d.workflow.map(function(r,i){return wfRow('as_wf',i,r);}).join('');
var perfMeta=[['Reach & Frequency Optimization','5–15%'],['Creative Optimization','4–12%'],['Last Touch Attribution','3–8%']];
var ecpmMeta=[['Log-Level Data','3–6%'],['Audience HQ','3–5%'],['Data Connectivity','3–5%']];
var perfLev=perfMeta.map(function(m,i){return leverRow('as_lp_'+i,m[0],m[1],d.perfLevers[i]);}).join('');
var ecpmLev=ecpmMeta.map(function(m,i){return leverRow('as_le_'+i,m[0],m[1],d.ecpmLevers[i]);}).join('');
var left='
'
+'
Scenario
Ranges are placeholders — no public source calculator exists yet for Ad Serving. Tune per deal.
'
+'
'+seclabel('1','Primary inputs')
+field('Annual ad-served spend','Proxy for impression volume at your average CPM',money('as_annualSpend',d.annualSpend,1000000,'$'))
+field('Ad serving fee','Your investment — a % of served spend',money('as_feePct',d.feePct,0.5,null,'%'))
+'
'
+'
'
+'
Workflow Efficiencies (Ad Serving, Integrations, NIVO Agents, Reach & Frequency, Log-Level Data)
'+wfRows+''+field('Annual spend wasted on over-exposure',null,money('as_wasteWriteoff',d.wasteWriteoff,50000,'$'))+field('Waste reduction with R&F Optimization',null,money('as_wasteReductionPct',d.wasteReductionPct,5,null,'%'))+field('Average ad-serving eCPM',null,money('as_avgEcpm',d.avgEcpm,0.5,'$'))+'
Data & CPM efficiency levers — total
'+ecpmLev
+'
Performance
Optional upside on top of the efficiency headline (Creative Optimization + Last Touch Attribution) — not required to justify the fee.
'+field('Spend split — performance vs. awareness',null,'
NET EFFICIENCY IMPACT '+usdC(r.netEfficiencyImpact)+'COST AVOIDANCE '+usdC(r.costAvoidance)+'HOURS SAVED '+fmt(r.workflow.hoursSaved)+'
'
+'';
repop('as_hero');
}
/* ============================= MEASUREMENT ============================= */
var measSub='sig';
function buildMeasurement(){
var segBtns=[['sig','Is my result significant?'],['size','How big a test do I need?'],['roi','What is the ROI of Measurement?']].map(function(s){return '';}).join('');
document.getElementById('mode-measurement').innerHTML='
'+segBtns+'
';
document.querySelectorAll('#measseg button').forEach(function(b){b.addEventListener('click',function(){measSub=b.getAttribute('data-sub');document.querySelectorAll('#measseg button').forEach(function(x){x.classList.toggle('on',x===b);});buildMeasBody();});});
buildMeasBody();
}
function confSeg(id,val){return '
'+CONF.map(function(c){return '';}).join('')+'
';}
function buildMeasBody(){
if(measSub==='sig'){
var left='
'+(r.significant?('Creative '+r.winner+' outperformed by '+pct(r.uplift)+'. You can be '+pct(r.achieved,1)+' confident this is not chance.'):('Achieved confidence is '+pct(r.achieved,1)+', below your '+pct(r.confidence)+' bar. Gather more data.'))+'
';
var col=r.significant?C.ocean:C.coral;var frac=Math.max(0,Math.min(100,r.achieved*100));
var gauge=document.getElementById('gauge');gauge.setAttribute('stroke',col);gauge.setAttribute('stroke-dasharray',frac+' '+(100-frac));
document.getElementById('gaugeVal').textContent=pct(r.achieved,1);document.getElementById('gaugeVal').style.color=col;
document.getElementById('gaugeSub').textContent='Target: '+pct(r.confidence)+' · p = '+r.pValue.toFixed(4);
var mx=Math.max(r.p1,r.p2)||1;var rd=[['Creative 1',r.p1,r.winner===1],['Creative 2',r.p2,r.winner===2]];
document.getElementById('rateBars').innerHTML=rd.map(function(d){var h=20+(d[1]/mx)*70;return '
'+(d[1]*100).toFixed(3)+'%
'+d[0]+'
';}).join('');
repop('s_banner');
}
function renderSize(){
var g=function(id){return document.getElementById(id).value;};
var r=calcSampleSize({baseRate:g('z_base')/100,upliftLow:g('z_ul')/100,upliftHigh:g('z_uh')/100,confidence:activeConf('z_conf'),impPerDay:g('z_ipd'),power:g('z_power')/100});
if(!r.valid)return;
document.getElementById('z_banner').innerHTML='
Estimated test duration
'+fmt(r.daysMin)+'–'+fmt(r.daysMax)+' days
Each creative needs '+fmt(r.nMin)+'–'+fmt(r.nMax)+' impressions. Bigger real uplift → shorter test.
';
var t=document.querySelectorAll('#meas_body .tile .v');t[0].textContent=fmt(r.nMin);t[1].textContent=fmt(r.nMax);t[2].textContent=fmt(r.daysMin)+' d';
var mx=r.nMax||1;var rows=[['+'+document.getElementById('z_uh').value+'% uplift',r.nMin],['+'+document.getElementById('z_ul').value+'% uplift',r.nMax]];
document.getElementById('z_bars').innerHTML=rows.map(function(rr){return '
'+rr[0]+'
'+(rr[1]/1e6).toFixed(2)+'M
';}).join('');
repop('z_banner');
}
/* ---- MEASUREMENT ROI (bonus 3rd sub-mode) ---- */
var MROI_PRESETS={conservative:{lp:[3,2,2],waste:30},aggressive:{lp:[12,10,8],waste:85}};
function buildMeasRoi(){
var mr=MEASUREMENT_ROI_DEFAULTS;
var wfRows=mr.workflow.map(function(r,i){return wfRow('mr_wf',i,r);}).join('');
var perfMeta=[['Outcomes (Digital/3P/Offline)','4–10%'],['Multi-Touch Attribution','3–8%'],['Reach & Frequency + Conversion Optimization (Harmony)','3–8%']];
var perfLev=perfMeta.map(function(m,i){return leverRow('mr_lp_'+i,m[0],m[1],mr.perfLevers[i]);}).join('');
var left='
'
+'
Scenario
Ranges are placeholders — no public source calculator exists yet for Measurement ROI. Tune per deal.
'
+'
'+seclabel('1','Primary inputs')+field('Annual measured spend',null,money('mr_annualSpend',mr.annualSpend,1000000,'$'))+field('Innovid Measurement fee','Your investment — a % of spend',money('mr_feePct',mr.feePct,0.5,null,'%'))+'
'+wfRows+''+field('Annual spend on redundant/duplicate exposure',null,money('mr_wasteWriteoff',mr.wasteWriteoff,50000,'$'))+field('Waste reduction from spotting redundancy',null,money('mr_wasteReductionPct',mr.wasteReductionPct,5,null,'%'))
+'
Performance (Outcomes, MTA, Linear Measurement, Harmony)
'+field('Spend split — performance vs. other',null,'
';
document.querySelectorAll('#meas_body input').forEach(function(inp){inp.addEventListener('input',renderMeasRoi);});
var pr=document.getElementById('mr_perfPct');pr.addEventListener('input',function(){document.getElementById('mr_perfL').textContent=pr.value+'%';document.getElementById('mr_awareL').textContent=(100-pr.value)+'%';});
bindDrawerToggle('#meas_body');
function applyMroiPreset(key){var P=MROI_PRESETS[key];['mr_lp_0','mr_lp_1','mr_lp_2'].forEach(function(id,i){document.getElementById(id).value=P.lp[i];});document.getElementById('mr_wasteReductionPct').value=P.waste;document.querySelectorAll('#mr_presets button').forEach(function(x){x.classList.toggle('on',x.getAttribute('data-p')===key);});renderMeasRoi();}
document.querySelectorAll('#mr_presets button').forEach(function(b){b.addEventListener('click',function(){applyMroiPreset(b.getAttribute('data-p'));});});
applyMroiPreset('conservative');
}
function renderMeasRoi(){
var g=function(id){return document.getElementById(id).value;};
var wf=MEASUREMENT_ROI_DEFAULTS.workflow.map(function(r,i){return{role:r.role,fte:g('mr_wf_fte_'+i),salary:g('mr_wf_sal_'+i),effPct:g('mr_wf_eff_'+i)};});
var r=calcMeasurementRoi({annualSpend:g('mr_annualSpend'),feePct:g('mr_feePct'),workflow:wf,
wasteWriteoff:g('mr_wasteWriteoff'),wasteReductionPct:g('mr_wasteReductionPct'),
perfPct:g('mr_perfPct'),targetRoasPct:g('mr_targetRoasPct'),perfLevers:[g('mr_lp_0'),g('mr_lp_1'),g('mr_lp_2')]});
if(!r.valid)return;
document.getElementById('mr_hero').innerHTML=hero('Innovid Measurement — total ROI',r.roiMultiple,'Invest',r.investment,'Return',r.totalBenefits,'a '+pct(r.breakevenBoost,1)+' ROAS boost by itself covers the entire fee');
var tiles=document.querySelectorAll('#meas_body .tile .v');
tiles[0].textContent=usdC(r.benefits.workflow);tiles[1].textContent=usdC(r.benefits.waste);tiles[2].textContent=usdC(r.benefits.revenue);
document.getElementById('mr_tag_workflow_group').textContent=usdC(r.benefits.workflow+r.benefits.waste);
document.getElementById('mr_tag_perf_group').textContent=usdC(r.benefits.revenue);
document.getElementById('mr_wf_note').innerHTML='Frees '+r.workflow.fteFreed.toFixed(2)+' FTE of '+r.workflow.totalFte.toFixed(1)+' → '+r.workflow.fteAfter.toFixed(2)+' remaining.';
document.getElementById('mr_perfBoostL').textContent=pct(r.performance.perfBoost);
var segs=[['workflow',C.ocean],['waste',C.purple],['revenue',C.coral]];var tot=r.totalBenefits||1;
document.getElementById('mr_stack').innerHTML=segs.map(function(s){return '';}).join('');
document.getElementById('mr_stack_sub').textContent='Three value drivers stack against a '+usdC(r.investment)+' investment.';
donutSvg('mr_donut','mr_donut_leg',[['Incremental revenue',r.benefits.revenue],['Waste savings',r.benefits.waste],['Workflow savings',r.benefits.workflow]],tot);
document.getElementById('mr_summary').innerHTML='
Summary of assumptions & result
Recap this with the client before the reveal — every number below is theirs.