{"id":21208,"date":"2026-10-05T14:51:13","date_gmt":"2026-10-05T12:51:13","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?page_id=21208"},"modified":"2026-10-05T15:14:14","modified_gmt":"2026-10-05T13:14:14","slug":"saas-profitability-calculator","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/","title":{"rendered":"Kalkulator rentowno\u015bci SaaS"},"content":{"rendered":"<style>\n.lw-saas{color:var(--text-primary);min-width:0}\n.lw-saas *{box-sizing:border-box}\n.lw-saas h2,.lw-saas h3,.profile-panel:has(.lw-saas) .profile-name{overflow-wrap:anywhere;hyphens:auto}\n.lw-saas .saas-note{padding:16px;border-left:3px solid var(--accent);background:var(--bg-panel);color:var(--text-secondary)}\n.lw-saas fieldset{border:1px solid var(--border);border-radius:10px;padding:18px;margin:20px 0;min-width:0;background:var(--bg-panel)}\n.lw-saas legend{padding:0 8px;font-weight:700;color:var(--text-primary)}\n.lw-saas .saas-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}\n.lw-saas label{display:block;font-size:.9rem;color:var(--text-secondary)}\n.lw-saas input{display:block;width:100%;padding:11px;margin-top:6px;border:1px solid var(--border);border-radius:6px;background:var(--bg-body);color:var(--text-primary);font:inherit}\n.lw-saas input:focus-visible,.lw-saas button:focus-visible,.lw-saas a:focus-visible{outline:3px solid var(--accent);outline-offset:3px}\n.lw-saas input[aria-invalid=true]{border:2px solid var(--accent)}\n.lw-saas .saas-actions{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0}\n.lw-saas button:disabled{opacity:.45;cursor:default;transform:none}\n.lw-saas [data-status]{color:var(--text-primary);font-weight:600}\n.lw-saas .saas-metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}\n.lw-saas .saas-metrics div{padding:16px;border:1px solid var(--border);border-radius:8px;background:var(--bg-panel)}\n.lw-saas dt{color:var(--text-secondary);font-size:.85rem}\n.lw-saas dd{margin:8px 0 0;font-size:1.35rem;font-weight:700;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}\n.lw-saas .saas-table-wrap{max-width:100%;overflow-x:auto;margin:20px 0;border:1px solid var(--border);border-radius:8px}\n.lw-saas table{border-collapse:collapse;width:100%;font-size:.86rem}\n.lw-saas table th,.lw-saas table td{width:auto!important;padding:12px;min-width:120px;word-break:normal;overflow-wrap:normal;text-align:right;border-bottom:1px solid var(--border);color:var(--text-primary);white-space:normal}\n.lw-saas table th{background:var(--bg-panel)}\n.lw-saas table th[scope=row],.lw-saas table thead th:first-child{position:sticky;left:0;z-index:1;border-right:1px solid var(--border)}\n.lw-saas caption{text-align:left;padding:12px;font-weight:700;color:var(--text-primary)}\n.lw-saas .saas-chart{margin:20px 0;color:var(--accent)}\n.lw-saas .saas-chart svg{display:block;width:100%;height:auto}\n.lw-saas figcaption{color:var(--text-secondary);font-size:.85rem}\n.lw-saas .saas-related{display:flex;gap:10px;flex-wrap:wrap;list-style:none;padding:0}\n.lw-saas .saas-related li{list-style:none;margin:0}\n.lw-saas .saas-related a{display:block;border:1px solid var(--border);border-radius:6px;padding:8px 12px}\n.site-container main:has(.lw-saas) .profile-panel{flex:1 1 0;max-width:none;min-width:0}\n.site-container main:has(.lw-saas) .info-panel{flex:0 0 220px;max-width:220px}\n@media(max-width:900px){.site-container main:has(.lw-saas) .profile-panel,.site-container main:has(.lw-saas) .info-panel{flex:auto;width:100%;max-width:100%}}\n@media(max-width:540px){.lw-saas .saas-fields,.lw-saas .saas-metrics{grid-template-columns:1fr}.lw-saas fieldset{padding:12px}}\n<\/style>\n<p><script>\/* SaaS calculators: pure arithmetic. Monetary inputs use one currency, exclude tax. *\/\n(function (scope) {\n'use strict';\nconst finite = x => typeof x === 'number' && Number.isFinite(x);\nfunction number(raw) {\n  const s=String(raw ?? '').trim().replace(\/\\s\/g,'').replace(',','.');\n  if(!\/^(?:\\d+(?:\\.\\d*)?|\\.\\d+)$\/.test(s)) return NaN;\n  const n=Number(s); return finite(n)?n:NaN;\n}\nconst be=(fixed,margin)=>margin>0?Math.ceil(fixed\/margin):(fixed===0&&margin===0?0:null);\nfunction profit(v){\n const support=v.support*v.hour\/60, unit=v.variable+support+v.price*v.fee\/100+v.flat;\n const margin=v.price-unit, fixed=v.fixed;\n return {summary:{revenue:v.customers*v.price,cost:v.customers*unit+fixed,profit:v.customers*margin-fixed,margin,breakEven:be(fixed,margin),minimumPrice:v.customers>0&&v.fee<100?(fixed\/v.customers+v.variable+support+v.flat)\/(1-v.fee\/100):null},\n columns:['scenario','customers','revenue','cost','profit'],rows:[0.5,1,2].map(x=>{const n=Math.round(v.customers*x);return [x+'\u00d7',n,n*v.price,n*unit+fixed,n*margin-fixed];})};\n}\nfunction pricing(v){\n if(Math.abs(v.lightShare+v.mediumShare+v.heavyShare-100)>1e-7)throw Error('shares');\n const profiles=[['light',v.lightShare,v.lightUse],['medium',v.mediumShare,v.mediumUse],['heavy',v.heavyShare,v.heavyUse]];\n const uses=profiles.reduce((s,p)=>s+v.customers*p[1]\/100*p[2],0);\n const packs=profiles.reduce((s,p)=>s+v.customers*p[1]\/100*Math.ceil(p[2]\/v.packSize),0);\n const outcomes=uses*v.success\/100;\n const outcomeBuyers=profiles.reduce((s,p)=>s+(p[2]>0&&v.success>0?v.customers*p[1]\/100:0),0);\n const cost=uses*v.unitCost+v.fixed;\n const data=[['subscription',v.customers*v.subscription,v.customers],['credits',packs*v.packPrice,packs],['outcome',outcomes*v.outcomePrice,outcomeBuyers]];\n const rows=data.map(([name,revenue,invoices])=>{const fees=revenue*v.fee\/100+invoices*v.flat;return [name,revenue,fees,cost,revenue-fees-cost];});\n return {summary:{attempts:uses,outcomes,packs},columns:['model','revenue','fees','operatingCost','profit'],rows};\n}\nfunction automation(v){\n const attempts=v.runs*(1+v.retries\/100), api=attempts*v.api\/1000;\n const rows=['n8n','make','code'].map(k=>{\n const units=attempts*v[k+'Units'];\n const overage=Math.max(0,units-v[k+'Included'])*v[k+'Overage']\/1000;\n const labor=v[k+'Maintenance']*v.hour;\n const setup=v[k+'Setup']*v.hour\/v.months;\n const total=v[k+'Base']+v[k+'Hosting']+overage+labor+setup+api;\n return [k,units,v[k+'Base']+v[k+'Hosting'],overage,labor,setup,api,total,v.runs>0?total\/v.runs:null];\n });\n return {summary:{attempts},columns:['platform','billableUnits','fixedPlanHosting','overage','maintenance','setupMonthly','apiCost','total','perRun'],rows};\n}\nfunction mrr(v){\n const rows=[];let customers=v.customers, current=v.customers*v.price;\n for(let month=1;month<=v.months;month++){\n const opening=current, lost=opening*v.churn\/100, survivors=opening-lost;\n const expansion=survivors*v.expansion\/100, contraction=survivors*v.contraction\/100;\n const fresh=v.newCustomers*v.price;\n current=survivors+expansion-contraction+fresh;\n customers=customers*(1-v.churn\/100)+v.newCustomers;\n const nrr=opening>0?(survivors+expansion-contraction)\/opening*100:null;\n rows.push([month,opening,lost,fresh,expansion,contraction,current,customers,nrr]);\n }\n return {summary:{initialMRR:v.customers*v.price,finalMRR:current,annualRunRate:current*12,finalCustomers:customers},columns:['month','openingMRR','lostMRR','newMRR','expansionMRR','contractionMRR','closingMRR','customersExpected','nrr'],rows};\n}\nfunction digital(v){\n const support=v.support*v.hour\/60, fixed=v.fixed+v.creation*v.hour\/v.months;\n const kept=v.price*(1-v.refunds\/100);\n const fees=v.price*v.fee\/100+v.flat;\n const unit=fees+v.variable+v.acquisition+support;\n const margin=kept-unit;\n const factor=1-v.refunds\/100-v.fee\/100;\n return {summary:{grossRevenue:v.sales*v.price,refundValue:v.sales*v.price*v.refunds\/100,retainedRevenue:v.sales*kept,cost:v.sales*unit+fixed,profit:v.sales*margin-fixed,margin,breakEven:be(fixed,margin),minimumPrice:factor>0&&v.sales>0?(unit-fees+v.flat+fixed\/v.sales)\/factor:null},\n columns:['scenario','sales','retainedRevenue','cost','profit'],rows:[0.5,1,2].map(x=>{const n=Math.round(v.sales*x);return [x+'\u00d7',n,n*kept,n*unit+fixed,n*margin-fixed];})};\n}\nconst api={number,profit,pricing,automation,mrr,digital};\nif(typeof module!=='undefined'&&module.exports)module.exports=api;\nelse scope.LWSaasMath=api;\n})(typeof window!=='undefined'?window:globalThis);\n<\/script><\/p>\n<div class=\"lw-saas\" id=\"saas-profit\">\n<p>Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.<\/p>\n<p class=\"saas-note\">Wszystkie kwoty w tej samej walucie, bez VAT. Przyk\u0142adowe warto\u015bci to za\u0142o\u017cenia, a nie cenniki dostawc\u00f3w. Dane i obliczenia pozostaj\u0105 w przegl\u0105darce.<\/p>\n<p><a href=\"\/blog\/pl\/narzedzia\/#saas\">Wszystkie narz\u0119dzia SaaS<\/a><\/p>\n<form novalidate>\n<fieldset>\n<legend>Wsp\u00f3lne za\u0142o\u017cenia<\/legend>\n<div class=\"saas-fields\">\n<label for=\"saas-profit-customers\">Klienci<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-customers\" name=\"customers\" value=\"100\"><\/label><br \/>\n<label for=\"saas-profit-price\">Cena netto na klienta \/ miesi\u0105c<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-price\" name=\"price\" value=\"19\"><\/label><br \/>\n<label for=\"saas-profit-variable\">Koszt zmienny na klienta \/ miesi\u0105c<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-variable\" name=\"variable\" value=\"2\"><\/label><br \/>\n<label for=\"saas-profit-support\">Minuty wsparcia na klienta \/ miesi\u0105c<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-support\" name=\"support\" value=\"5\"><\/label><br \/>\n<label for=\"saas-profit-hour\">Koszt godziny<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-hour\" name=\"hour\" value=\"40\"><\/label><br \/>\n<label for=\"saas-profit-fixed\">Koszty sta\u0142e miesi\u0119cznie<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-fixed\" name=\"fixed\" value=\"200\"><\/label><br \/>\n<label for=\"saas-profit-fee\">Op\u0142ata p\u0142atnicza (%)<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-fee\" name=\"fee\" value=\"3\"><\/label><br \/>\n<label for=\"saas-profit-flat\">Sta\u0142a op\u0142ata za p\u0142atno\u015b\u0107<input type=\"text\" inputmode=\"decimal\" autocomplete=\"off\" data-rc-private data-mp-mask id=\"saas-profit-flat\" name=\"flat\" value=\"0.3\"><\/label>\n<\/div>\n<\/fieldset>\n<div class=\"saas-actions\"><button type=\"submit\">Oblicz<\/button><button type=\"button\" data-reset>Warto\u015bci przyk\u0142adowe<\/button><\/div>\n<\/form>\n<p role=\"alert\" data-status id=\"saas-profit-status\">\n<div data-result data-rc-private data-mp-mask aria-live=\"polite\" aria-atomic=\"false\"><\/div>\n<p><button type=\"button\" data-csv disabled>Pobierz CSV<\/button><\/p>\n<h2>Model oblicze\u0144 i za\u0142o\u017cenia<\/h2>\n<p>Jedna p\u0142atno\u015b\u0107 na klienta miesi\u0119cznie. Mar\u017ca pokrycia = cena \u00d7 (1 \u2212 op\u0142ata %) \u2212 sta\u0142a op\u0142ata \u2212 koszty zmienne \u2212 minuty wsparcia \u00d7 koszt godziny \u00f7 60. Zysk = klienci \u00d7 mar\u017ca pokrycia \u2212 koszty sta\u0142e. Pr\u00f3g rentowno\u015bci = koszty sta\u0142e \u00f7 mar\u017ca pokrycia, zaokr\u0105glony w g\u00f3r\u0119. Cena minimalna rozdziela koszty sta\u0142e na podan\u0105 liczb\u0119 klient\u00f3w. Wy\u015bwietlana cena minimalna jest zaokr\u0105glana w g\u00f3r\u0119 do pe\u0142nych setnych.<\/p>\n<h2>Pozosta\u0142e narz\u0119dzia SaaS<\/h2>\n<ul class=\"saas-related\">\n<li><a href=\"\/blog\/pl\/narzedzia\/saas-pricing-model-simulator\/\">Symulator modeli cenowych SaaS<\/a><\/li>\n<li><a href=\"\/blog\/pl\/narzedzia\/automation-cost-comparator\/\">Por\u00f3wnanie koszt\u00f3w automatyzacji<\/a><\/li>\n<li><a href=\"\/blog\/pl\/narzedzia\/mrr-churn-simulator\/\">Kalkulator MRR i churn<\/a><\/li>\n<li><a href=\"\/blog\/pl\/narzedzia\/digital-product-profit-calculator\/\">Kalkulator zysku produkt\u00f3w cyfrowych<\/a><\/li>\n<\/ul>\n<h2>\u0179r\u00f3d\u0142a i definicje<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.stripe.com\/products-prices\/pricing-models\" rel=\"noopener\">Stripe: Pricing models<\/a><\/li>\n<\/ul>\n<div class=\"lw-faq\">\n<h2>FAQ<\/h2>\n<h3>Czy dane wej\u015bciowe s\u0105 przesy\u0142ane?<\/h3>\n<p>Kalkulator przetwarza dane lokalnie w przegl\u0105darce. Pliki CSV r\u00f3wnie\u017c powstaj\u0105 lokalnie. Strona nie zapisuje danych scenariusza na serwerze.<\/p>\n<h3>Jakie ograniczenia ma model?<\/h3>\n<p>Nie dodatnia mar\u017ca pokrycia nie pozwala pokry\u0107 dodatkowych koszt\u00f3w sta\u0142ych przez zwi\u0119kszenie liczby klient\u00f3w. Przy zerowej liczbie klient\u00f3w brak podstawy do ceny minimalnej. Koszty wsparcia nale\u017c\u0105 wy\u0142\u0105cznie do osobnych p\u00f3l, aby unikn\u0105\u0107 podw\u00f3jnego naliczania.<\/p>\n<\/div>\n<p><script type=\"application\/json\" data-config>{\"kind\": \"profit\", \"slug\": \"saas-profitability-calculator\", \"title\": \"Kalkulator rentowno\u015bci SaaS\", \"locale\": \"pl-PL\", \"fields\": [{\"key\": \"customers\", \"value\": 100, \"label\": \"Klienci\", \"min\": 0, \"max\": 1000000000.0, \"integer\": true, \"group\": \"common\"}, {\"key\": \"price\", \"value\": 19, \"label\": \"Cena netto na klienta \/ miesi\u0105c\", \"min\": 0, \"max\": 1000000000.0, \"integer\": false, \"group\": \"common\"}, {\"key\": \"variable\", \"value\": 2, \"label\": \"Koszt zmienny na klienta \/ miesi\u0105c\", \"min\": 0, \"max\": 1000000000.0, \"integer\": false, \"group\": \"common\"}, {\"key\": \"support\", \"value\": 5, \"label\": \"Minuty wsparcia na klienta \/ miesi\u0105c\", \"min\": 0, \"max\": 1000000000.0, \"integer\": false, \"group\": \"common\"}, {\"key\": \"hour\", \"value\": 40, \"label\": \"Koszt godziny\", \"min\": 0, \"max\": 1000000000.0, \"integer\": false, \"group\": \"common\"}, {\"key\": \"fixed\", \"value\": 200, \"label\": \"Koszty sta\u0142e miesi\u0119cznie\", \"min\": 0, \"max\": 1000000000.0, \"integer\": false, \"group\": \"common\"}, {\"key\": \"fee\", \"value\": 3, \"label\": \"Op\u0142ata p\u0142atnicza (%)\", \"min\": 0, \"max\": 100, \"integer\": false, \"group\": \"common\"}, {\"key\": \"flat\", \"value\": 0.3, \"label\": \"Sta\u0142a op\u0142ata za p\u0142atno\u015b\u0107\", \"min\": 0, \"max\": 1000000000.0, \"integer\": false, \"group\": \"common\"}], \"labels\": {\"revenue\": \"Przych\u00f3d miesi\u0119czny\", \"cost\": \"Koszt miesi\u0119czny\", \"profit\": \"Zysk miesi\u0119czny\", \"margin\": \"Mar\u017ca pokrycia na klienta\", \"breakEven\": \"Pr\u00f3g rentowno\u015bci: liczba klient\u00f3w\", \"minimumPrice\": \"Cena netto pokrywaj\u0105ca koszty\", \"scenario\": \"Wolumen\", \"customers\": \"Klienci\", \"sales\": \"Sprzeda\u017ce\", \"attempts\": \"Pr\u00f3by miesi\u0119cznie\", \"outcomes\": \"Oczekiwane udane wyniki\", \"packs\": \"Pakiety kredyt\u00f3w miesi\u0119cznie\", \"model\": \"Model cenowy\", \"fees\": \"Op\u0142aty p\u0142atnicze\", \"operatingCost\": \"Koszty pr\u00f3b i koszty sta\u0142e\", \"subscription\": \"Abonament\", \"credits\": \"Pakiety kredyt\u00f3w\", \"outcome\": \"Op\u0142ata za wynik\", \"platform\": \"Platforma\", \"billableUnits\": \"Jednostki rozliczeniowe\", \"fixedPlanHosting\": \"Plan i hosting\", \"overage\": \"Koszt nadwy\u017cki\", \"maintenance\": \"Koszt utrzymania\", \"setupMonthly\": \"Wdro\u017cenie miesi\u0119cznie\", \"apiCost\": \"Koszt zewn\u0119trznego API\", \"total\": \"Koszt \u0142\u0105czny miesi\u0119cznie\", \"perRun\": \"Koszt pierwotnego uruchomienia\", \"n8n\": \"n8n\", \"make\": \"Make\", \"code\": \"W\u0142asny kod\", \"initialMRR\": \"Pocz\u0105tkowy MRR\", \"finalMRR\": \"Ko\u0144cowy MRR\", \"annualRunRate\": \"Ko\u0144cowy ARR (MRR \u00d7 12)\", \"finalCustomers\": \"Oczekiwana ko\u0144cowa liczba klient\u00f3w\", \"month\": \"Miesi\u0105c\", \"openingMRR\": \"MRR na pocz\u0105tku miesi\u0105ca\", \"lostMRR\": \"MRR utracony przez rezygnacje\", \"newMRR\": \"Nowy MRR\", \"expansionMRR\": \"Wzrost MRR\", \"contractionMRR\": \"Spadek MRR\", \"closingMRR\": \"MRR na koniec miesi\u0105ca\", \"customersExpected\": \"Oczekiwana liczba klient\u00f3w\", \"nrr\": \"NRR bez nowych klient\u00f3w\", \"grossRevenue\": \"Przych\u00f3d przed zwrotami\", \"refundValue\": \"Zwroty\", \"retainedRevenue\": \"Zachowany przych\u00f3d\"}, \"ui\": {\"calculate\": \"Oblicz\", \"reset\": \"Warto\u015bci przyk\u0142adowe\", \"csv\": \"Pobierz CSV\", \"results\": \"Wynik\", \"table\": \"Scenariusze i obliczenia\", \"unavailable\": \"Brak mo\u017cliwo\u015bci obliczenia\", \"invalid\": \"Nieprawid\u0142owa warto\u015b\u0107. Dozwolony zakres pola\", \"integer\": \"(liczba ca\u0142kowita)\", \"shares\": \"Trzy udzia\u0142y klient\u00f3w musz\u0105 sumowa\u0107 si\u0119 do 100%.\", \"overflow\": \"Dane prowadz\u0105 do zbyt du\u017cych warto\u015bci.\", \"changed\": \"Dane zmienione. Nowe obliczenie aktualizuje wynik.\", \"undefinedHelp\": \"Brak mo\u017cliwo\u015bci obliczenia: zerowy wolumen, brak dodatniej mar\u017cy pokrycia lub brak ceny pokrywaj\u0105cej koszty przy podanych op\u0142atach.\", \"title\": \"Narz\u0119dzie\", \"assumptions\": \"Za\u0142o\u017cenia\", \"chart\": \"Zmiana MRR; dok\u0142adne warto\u015bci w tabeli\", \"pricingChart\": \"Zysk miesi\u0119czny wed\u0142ug modelu cenowego; dok\u0142adne warto\u015bci w tabeli\", \"method\": \"Model oblicze\u0144 i za\u0142o\u017cenia\", \"sources\": \"\u0179r\u00f3d\u0142a i definicje\", \"faq1\": \"Czy dane wej\u015bciowe s\u0105 przesy\u0142ane?\", \"faq1a\": \"Kalkulator przetwarza dane lokalnie w przegl\u0105darce. Pliki CSV r\u00f3wnie\u017c powstaj\u0105 lokalnie. Strona nie zapisuje danych scenariusza na serwerze.\", \"faq2\": \"Jakie ograniczenia ma model?\", \"related\": \"Pozosta\u0142e narz\u0119dzia SaaS\", \"all\": \"Wszystkie narz\u0119dzia SaaS\"}}<\/script><\/div>\n<p><script>(function(){\n'use strict';\nconst root=document.currentScript.previousElementSibling;\nconst c=JSON.parse(root.querySelector('[data-config]').textContent);\nif(root.dataset.ready)return;root.dataset.ready='1';\nconst form=root.querySelector('form'), result=root.querySelector('[data-result]'), status=root.querySelector('[data-status]'), download=root.querySelector('[data-csv]');\nlet exportRows=null;\nconst fmt=new Intl.NumberFormat(c.locale,{maximumFractionDigits:2});\nconst countFmt=new Intl.NumberFormat(c.locale,{maximumFractionDigits:2});\nconst preciseFmt=new Intl.NumberFormat(c.locale,{maximumFractionDigits:6});\nconst safeMinimum=value=>Math.ceil(value*100)\/100;\nconst e=(tag,text)=>{const n=document.createElement(tag);if(text!==undefined)n.textContent=text;return n;};\nconst label=k=>c.labels[k]||k;\nfunction display(value,key){\n if(value===null)return c.ui.unavailable;\n if(typeof value==='string')return label(value);\n if(key==='minimumPrice')value=safeMinimum(value);\n if(key==='perRun'||key==='margin')return preciseFmt.format(value);\n return (['customers','sales','attempts','outcomes','packs','breakEven','finalCustomers','customersExpected','billableUnits','month'].includes(key)?countFmt:fmt).format(value)+(key==='nrr'?' %':'');\n}\nfunction calculate(){\n status.textContent='';result.replaceChildren();download.disabled=true;exportRows=null;\n root.querySelectorAll('[aria-invalid]').forEach(n=>{n.removeAttribute('aria-invalid');n.removeAttribute('aria-describedby');});\n const v={};let bad=null;\n for(const f of c.fields){\n  const input=form.elements.namedItem(f.key), n=LWSaasMath.number(input.value);\n  if(!Number.isFinite(n)||n<f.min||n>f.max||(f.integer&&!Number.isInteger(n))){\n   input.setAttribute('aria-invalid','true');input.setAttribute('aria-describedby',status.id);\n   if(!bad)bad={input,field:f};\n  }v[f.key]=n;\n }\n if(bad){\n  status.textContent=c.ui.invalid+' '+bad.field.label+': '+bad.field.min+'\u2013'+bad.field.max+(bad.field.integer?' '+c.ui.integer:'');\n  bad.input.focus();return;\n }\n let data;\n try{data=LWSaasMath[c.kind](v);}catch(error){status.textContent=c.ui.shares;return;}\n const values=[...Object.values(data.summary),...data.rows.flat()];\n if(values.some(n=>typeof n==='number'&&!Number.isFinite(n))){status.textContent=c.ui.overflow;return;}\n const h=e('h2',c.ui.results);result.append(h);\n const cards=e('dl');cards.className='saas-metrics';\n for(const [key,value]of Object.entries(data.summary)){\n  const box=e('div');box.append(e('dt',label(key)),e('dd',display(value,key)));cards.append(box);\n }result.append(cards);\n if(c.kind==='mrr'||c.kind==='pricing'){\n  const index=c.kind==='mrr'?6:4;\n  const points=data.rows.map(row=>row[index]);\n  const chart=e('figure');chart.className='saas-chart';\n  const svg=document.createElementNS('http:\/\/www.w3.org\/2000\/svg','svg');\n  svg.setAttribute('viewBox','0 0 600 160');svg.setAttribute('role','img');svg.setAttribute('aria-label',c.ui.chart);\n  const max=Math.max(1,...points.map(Math.abs));\n  if(c.kind==='mrr'){\n   const path=document.createElementNS(svg.namespaceURI,'polyline');\n   path.setAttribute('points',points.map((n,i)=>(20+i*560\/Math.max(1,points.length-1))+','+(140-n\/max*120)).join(' '));\n   path.setAttribute('fill','none');path.setAttribute('stroke','currentColor');path.setAttribute('stroke-width','3');svg.append(path);\n  }else{\n   for(let i=0;i<points.length;i++){\n    const rect=document.createElementNS(svg.namespaceURI,'rect');\n    rect.setAttribute('x',30+i*195);rect.setAttribute('width','140');\n    rect.setAttribute('y',points[i]>=0?80-points[i]\/max*60:80);\n    rect.setAttribute('height',Math.abs(points[i])\/max*60);rect.setAttribute('fill','currentColor');\n    const title=document.createElementNS(svg.namespaceURI,'title');title.textContent=label(data.rows[i][0])+': '+display(points[i],'profit');rect.append(title);svg.append(rect);\n   }\n   const axis=document.createElementNS(svg.namespaceURI,'path');axis.setAttribute('d','M20 80H580');axis.setAttribute('stroke','currentColor');svg.append(axis);\n  }\n  chart.append(svg,e('figcaption',c.ui.chart));result.append(chart);\n }\n const scroll=e('div');scroll.className='saas-table-wrap';scroll.tabIndex=0;\n scroll.setAttribute('role','region');scroll.setAttribute('aria-label',c.ui.table);\n const table=e('table');table.append(e('caption',c.ui.table));\n const head=e('thead'), hr=e('tr');\n data.columns.forEach(k=>{const th=e('th',label(k));th.scope='col';hr.append(th);});head.append(hr);table.append(head);\n const body=e('tbody');\n data.rows.forEach(row=>{const tr=e('tr');row.forEach((value,i)=>{const cell=e(i===0?'th':'td',display(value,data.columns[i]));if(i===0)cell.scope='row';tr.append(cell);});body.append(tr);});\n table.append(body);scroll.append(table);result.append(scroll);\n if(Object.values(data.summary).includes(null)||data.rows.flat().includes(null))result.append(e('p',c.ui.undefinedHelp));\n exportRows=[[c.ui.title,c.title],[c.ui.assumptions]];\n for(const f of c.fields)exportRows.push([f.label,v[f.key]]);\n exportRows.push([],['',c.ui.results]);\n for(const [key,value]of Object.entries(data.summary))exportRows.push([label(key),value===null?c.ui.unavailable:key==='minimumPrice'?safeMinimum(value):value]);\n exportRows.push([],data.columns.map(label),...data.rows.map(row=>row.map(x=>typeof x==='string'?label(x):x===null?c.ui.unavailable:x)));\n download.disabled=false;\n root.dispatchEvent(new CustomEvent('saas-calculated',{detail:data}));\n}\nform.addEventListener('submit',event=>{event.preventDefault();calculate();});\nform.addEventListener('input',()=>{exportRows=null;download.disabled=true;status.textContent=c.ui.changed;result.replaceChildren();});\nroot.querySelector('[data-reset]').addEventListener('click',()=>{form.reset();calculate();});\ndownload.addEventListener('click',()=>{\n if(!exportRows)return;\n const csv='\\uFEFF'+exportRows.map(row=>row.map(x=>'\"'+String(x).replace(\/\"\/g,'\"\"')+'\"').join(';')).join('\\r\\n');\n const url=URL.createObjectURL(new Blob([csv],{type:'text\/csv;charset=utf-8'}));\n const a=e('a');a.href=url;a.download=c.slug+'.csv';root.append(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1000);\n});\nroot._saasCalculate=calculate;\ncalculate();\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":1,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[93056],"class_list":["post-21208","page","type-page","status-publish","hentry","tag-saas-tools-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Kalkulator rentowno\u015bci SaaS | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Kalkulator rentowno\u015bci SaaS | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-05T13:14:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/saas-profitability-calculator\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/saas-profitability-calculator\\\/\",\"name\":\"Kalkulator rentowno\u015bci SaaS | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-10-05T12:51:13+00:00\",\"dateModified\":\"2026-10-05T13:14:14+00:00\",\"description\":\"Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/saas-profitability-calculator\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/saas-profitability-calculator\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/saas-profitability-calculator\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Kalkulator rentowno\u015bci SaaS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Kalkulator rentowno\u015bci SaaS | Lukas Wojcik","description":"Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/","og_locale":"en_US","og_type":"article","og_title":"Kalkulator rentowno\u015bci SaaS | Lukas Wojcik","og_description":"Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-10-05T13:14:14+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/","name":"Kalkulator rentowno\u015bci SaaS | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-10-05T12:51:13+00:00","dateModified":"2026-10-05T13:14:14+00:00","description":"Miesi\u0119czny zysk, cena minimalna i pr\u00f3g rentowno\u015bci z kosztami p\u0142atno\u015bci, API i wsparcia.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/saas-profitability-calculator\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-3\/"},{"@type":"ListItem","position":3,"name":"Kalkulator rentowno\u015bci SaaS"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/21208","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=21208"}],"version-history":[{"count":3,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/21208\/revisions"}],"predecessor-version":[{"id":21313,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/21208\/revisions\/21313"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=21208"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=21208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}