Debt-to-Income (DTI) Ratio Analyzer

Step 1: Your Income & Monthly Housing Expenses

Income

Your total income before taxes and deductions.

Monthly Housing Expenses

If not included in P&I (escrowed).
If not included in P&I (escrowed).

Step 2: Your Other Monthly Debt Payments

List all other recurring monthly debt payments (e.g., minimum credit card payments, car loans, student loans, personal loans, alimony, child support).

Step 3: Debt-to-Income (DTI) Analysis

Step 4: Summary & Download Report

Complete the DTI calculation on Tab 3 to view the summary.

Understanding Your DTI:

Your Debt-to-Income (DTI) ratio is a key factor lenders use to assess your ability to manage monthly payments and repay debts. A lower DTI generally indicates a better balance between debt and income.

Front-End DTI specifically looks at your housing costs relative to your income. Back-End DTI includes all your monthly debt obligations.

Improving your DTI can involve increasing your income, reducing your debts, or both. This can positively impact your financial health and borrowing capacity.

Click 'Calculate DTI Ratios' to see your results.

"; document.getElementById('dtiResultsOutput').style.display = 'block'; document.getElementById('dtiInterpretationOutput').style.display = 'none'; } else if (tabName === 'dtiAnalysisTab' && dtiReportData.dtiCalculations.backEndDti !== undefined) { // If returning to this tab and data exists, re-render it calculateAndDisplayDti(false); // false to prevent auto-navigation } if (tabName === 'summaryPdfDtiTab') { displayDtiOverallSummary(); } } function navigateDtiTab(direction, currentTabNumFromHTML) { // currentTabNumFromHTML is 1-based from the HTML onclick, convert to 0-based index let currentTabProcessingIndex = currentTabNumFromHTML -1; if(currentTabProcessingIndex === 0) calculateFrontEndDti(false); if(currentTabProcessingIndex === 1) calculateTotalOtherDebts(false); // If navigating from Tab 3 (index 2), we assume the user might have updated something, // so a fresh calculation will be triggered if they land back on tab 3 or summary. let targetTabIndex = currentDtiTabIndex; if (direction === 'next' && currentDtiTabIndex < dtiTabs.length - 1) { targetTabIndex++; } else if (direction === 'prev' && currentDtiTabIndex > 0) { targetTabIndex--; } openDtiTab(null, dtiTabs[targetTabIndex]); } function updateDtiNavButtons() { const activeTabContent = document.querySelector('#dtiAnalyzerContainer .tab-content.active'); if (!activeTabContent) return; const prevButton = activeTabContent.querySelector('.tab-navigation .nav-button:first-child'); const nextButton = activeTabContent.querySelector('.tab-navigation .nav-button:last-child'); if (prevButton) prevButton.disabled = (currentDtiTabIndex === 0); if (nextButton) nextButton.disabled = (currentDtiTabIndex === dtiTabs.length - 1); } function getDtiNum(id, defaultValue = 0) { const el = document.getElementById(id); if (!el) { console.warn(`Element not found: ${id}`); return defaultValue; } const val = parseFloat(el.value); return isNaN(val) || val < 0 ? defaultValue : val; // Treat negative as invalid for amounts } function getDtiStr(id, defaultValue = '') { const el = document.getElementById(id); if (!el) { console.warn(`Element not found: ${id}`); return defaultValue; } return el.value.trim() || defaultValue; } function toggleHousingFields() { const status = getDtiStr('housingStatus', 'homeowner'); document.getElementById('homeownerFields').style.display = (status === 'homeowner') ? 'block' : 'none'; document.getElementById('renterFields').style.display = (status === 'renter') ? 'block' : 'none'; } function calculateFrontEndDti(displayUpdate = true) { const gmi = getDtiNum('grossMonthlyIncome'); dtiReportData.income = gmi; // Store GMI let totalHousingExpenses = 0; const housingStatus = getDtiStr('housingStatus'); dtiReportData.housingExpenses.status = housingStatus; dtiReportData.housingExpenses.details = {}; // Reset details if (housingStatus === 'homeowner') { const p_i = getDtiNum('mortgagePi'); const taxes = getDtiNum('propertyTaxes'); const insurance = getDtiNum('homeownersInsurance'); const hoa = getDtiNum('hoaDues'); totalHousingExpenses = p_i + taxes + insurance + hoa; dtiReportData.housingExpenses.details = {p_i, taxes, insurance, hoa}; } else { // renter const rent = getDtiNum('monthlyRent'); totalHousingExpenses = rent; dtiReportData.housingExpenses.details = {rent}; } dtiReportData.housingExpenses.total = totalHousingExpenses; const frontEndDtiOutputDiv = document.getElementById('frontEndDtiOutput'); if (gmi > 0) { const frontEndDti = (totalHousingExpenses / gmi) * 100; dtiReportData.dtiCalculations.frontEndDti = frontEndDti; if(displayUpdate) { frontEndDtiOutputDiv.innerHTML = `

Total Monthly Housing Expenses: $${totalHousingExpenses.toFixed(2)}

Front-End DTI (Housing Ratio): ${frontEndDti.toFixed(1)}%

`; frontEndDtiOutputDiv.style.display = 'block'; } } else { dtiReportData.dtiCalculations.frontEndDti = 0; if(displayUpdate) { frontEndDtiOutputDiv.innerHTML = "

Enter Gross Monthly Income (must be > $0) to calculate Front-End DTI.

"; frontEndDtiOutputDiv.style.display = 'block'; } } } function addOtherDebtRow() { otherDebtIdCounter++; const container = document.getElementById('otherDebtsContainer'); const newRow = document.createElement('div'); newRow.classList.add('other-debt-row'); // Unique IDs for inputs in the new row newRow.innerHTML = ` `; container.appendChild(newRow); calculateTotalOtherDebts(); // Recalculate when a row is added (even if empty initially) } function calculateTotalOtherDebts(displayUpdate = true) { dtiReportData.otherDebts = []; let totalOther = 0; document.querySelectorAll('#otherDebtsContainer .other-debt-row').forEach((row) => { const nameInput = row.querySelector('input[type="text"]'); const amountInput = row.querySelector('input[type="number"]'); const name = nameInput ? nameInput.value.trim() : `Debt Item`; const amount = amountInput ? getDtiNum(amountInput.id) : 0; // Use getDtiNum for consistency if (name && amount > 0) { // Only add if name is present and amount is positive totalOther += amount; dtiReportData.otherDebts.push({ name, amount }); } }); dtiReportData.dtiCalculations.totalOtherMonthlyDebts = totalOther; const outputDiv = document.getElementById('totalOtherDebtsOutput'); if(displayUpdate){ outputDiv.innerHTML = `

Total Other Monthly Debt Payments: $${totalOther.toFixed(2)}

`; outputDiv.style.display = totalOther > 0 || document.querySelectorAll('#otherDebtsContainer .other-debt-row').length > 0 ? 'block' : 'none'; } } function calculateAndDisplayDti(autoNavigateToSummary = true) { calculateFrontEndDti(false); calculateTotalOtherDebts(false); const gmi = dtiReportData.income; const totalHousing = dtiReportData.housingExpenses.total || 0; const totalOther = dtiReportData.dtiCalculations.totalOtherMonthlyDebts || 0; const resultsDiv = document.getElementById('dtiResultsOutput'); const interpretationDiv = document.getElementById('dtiInterpretationOutput'); if (gmi <= 0) { resultsDiv.innerHTML = "

Gross Monthly Income must be greater than $0 to calculate DTI ratios. Please enter a valid income in Tab 1.

"; resultsDiv.style.display = 'block'; interpretationDiv.style.display = 'none'; document.getElementById('downloadDtiPdfButton').disabled = true; return; } const totalMonthlyDebts = totalHousing + totalOther; dtiReportData.dtiCalculations.totalMonthlyDebts = totalMonthlyDebts; const frontEndDti = (totalHousing / gmi) * 100; const backEndDti = (totalMonthlyDebts / gmi) * 100; dtiReportData.dtiCalculations.frontEndDti = frontEndDti; dtiReportData.dtiCalculations.backEndDti = backEndDti; resultsDiv.innerHTML = `

Gross Monthly Income: $${gmi.toFixed(2)}

Total Monthly Housing Expenses: $${totalHousing.toFixed(2)}

Total Other Monthly Debt Payments: $${totalOther.toFixed(2)}


Calculated Front-End DTI (Housing Ratio): ${frontEndDti.toFixed(1)}%

Calculated Back-End DTI (Total Debt Ratio): ${backEndDti.toFixed(1)}%

`; resultsDiv.style.display = 'block'; interpretationDiv.innerHTML = getDtiInterpretation(backEndDti); interpretationDiv.style.display = 'block'; document.getElementById('downloadDtiPdfButton').disabled = false; if (autoNavigateToSummary && currentDtiTabIndex === dtiTabs.indexOf('dtiAnalysisTab')) { openDtiTab(null, 'summaryPdfDtiTab'); } } function getDtiClass(dti, isFrontEnd) { if (isNaN(dti)) return 'dti-high'; // Default if DTI is not a number // General mortgage guidelines: Front-end often preferred <=28%, Back-end <=36% (can go to 43% or higher sometimes) if (isFrontEnd) { if (dti <= 28) return 'dti-good'; if (dti <= 36) return 'dti-fair'; // Using a slightly wider range for 'fair' front-end for visual cue return 'dti-high'; } else { // Back-end if (dti <= 35) return 'dti-good'; if (dti <= 43) return 'dti-fair'; if (dti <= 49) return 'dti-high'; return 'dti-high'; } } function getDtiInterpretation(backEndDti) { let interpretation = "

Understanding Your Back-End DTI:

"; if (isNaN(backEndDti)) { interpretation += "

Could not calculate Back-End DTI. Please check your inputs.

"; return interpretation; } if (backEndDti <= 35) { interpretation += "

Looking Good (35% or less): Your debt appears to be at a manageable level relative to your income. Lenders generally view this favorably, and you likely have more flexibility for savings or other spending after bills are paid.

"; } else if (backEndDti <= 43) { interpretation += "

Manageable (36% - 43%): Your debt is manageable, and this range is often acceptable for many loan applications, including mortgages. However, improving it could offer better loan terms or more financial flexibility.

"; } else if (backEndDti <= 49) { interpretation += "

Opportunity to Improve (44% - 49%): This DTI suggests a significant portion of your income goes to debt. While some loans might still be possible, lenders may have concerns or offer less favorable terms. Reducing debt or increasing income is advisable.

"; } else { // 50% or more interpretation += "

Action Recommended (50% or more): A DTI this high indicates a substantial debt burden. It may be difficult to qualify for new loans, and there might be little room for savings or unexpected costs. Consider strategies to significantly reduce debt or increase income.

"; } interpretation += "

Note: These are general guidelines. Lenders consider many factors, and specific requirements can vary. Maximum DTI limits can sometimes be higher for certain loan programs (e.g., up to 50% for some Qualified Mortgages), but a lower DTI is generally better.

"; return interpretation; } function displayDtiOverallSummary() { const container = document.getElementById('dtiOverallSummaryContainer'); if (!dtiReportData.dtiCalculations.hasOwnProperty('backEndDti')) { // Check if calculation has been run container.innerHTML = "

Please calculate your DTI on Tab 3 to view the summary.

"; document.getElementById('downloadDtiPdfButton').disabled = true; return; } const gmi = dtiReportData.income; const housingTotal = dtiReportData.housingExpenses.total || 0; const otherDebtsTotal = dtiReportData.dtiCalculations.totalOtherMonthlyDebts || 0; const frontEndDti = dtiReportData.dtiCalculations.frontEndDti || 0; const backEndDti = dtiReportData.dtiCalculations.backEndDti || 0; let summaryHTML = `

Your DTI Ratio Summary:

Gross Monthly Income: $${gmi.toFixed(2)}

Total Monthly Housing Expenses: $${housingTotal.toFixed(2)}

Total Other Monthly Debt Payments: $${otherDebtsTotal.toFixed(2)}


Calculated Front-End DTI: ${frontEndDti.toFixed(1)}%

Calculated Back-End DTI: ${backEndDti.toFixed(1)}%

${getDtiInterpretation(backEndDti)}
`; container.innerHTML = summaryHTML; document.getElementById('downloadDtiPdfButton').disabled = false; } function downloadDtiPdf() { if (!dtiReportData.dtiCalculations.hasOwnProperty('backEndDti')) { alert("Please calculate your DTI ratios first (Tab 3)."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF generation library (jsPDF) is not loaded.'); return; } const jsPDFConstructor = window.jspdf.jsPDF; const doc = new jsPDFConstructor(); if (typeof doc.autoTable !== 'function') { alert('jsPDF AutoTable plugin not loaded.'); return; } const data = dtiReportData; const primaryColor = '#007bff', textColor = '#212529', tableHeaderColor = '#e9ecef'; let yPos = 22; const pageHeight = doc.internal.pageSize.height; const margin = 20; function checkYPdf(increment = 10) { if (yPos + increment > pageHeight - margin) { doc.addPage(); yPos = margin; } } doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Debt-to-Income (DTI) Analysis Report", 14, yPos); yPos += 8; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Report Date: ${new Date().toLocaleDateString()}`, 14, yPos); yPos += 10; // Income checkYPdf(15); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Income", 14, yPos); yPos += 6; doc.autoTable({startY: yPos, body: [['Gross Monthly Income:', `$${data.income.toFixed(2)}`]], theme:'plain', styles:{fontSize:9, cellPadding:1.5}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; // Housing Expenses checkYPdf(20 + (data.housingExpenses.status === 'homeowner' ? 4*6 : 1*6)); // Estimate height doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Monthly Housing Expenses", 14, yPos); yPos += 6; let housingBody = [['Housing Status:', data.housingExpenses.status === 'homeowner' ? 'Homeowner' : 'Renter']]; if (data.housingExpenses.status === 'homeowner' && data.housingExpenses.details) { housingBody.push(['Mortgage P&I:', `$${(data.housingExpenses.details.p_i || 0).toFixed(2)}`]); housingBody.push(['Property Taxes:', `$${(data.housingExpenses.details.taxes || 0).toFixed(2)}`]); housingBody.push(['Homeowner\'s Insurance:', `$${(data.housingExpenses.details.insurance || 0).toFixed(2)}`]); housingBody.push(['HOA Dues:', `$${(data.housingExpenses.details.hoa || 0).toFixed(2)}`]); } else if (data.housingExpenses.status === 'renter' && data.housingExpenses.details) { housingBody.push(['Monthly Rent:', `$${(data.housingExpenses.details.rent || 0).toFixed(2)}`]); } housingBody.push([{content:'Total Housing Expenses:', styles:{fontStyle:'bold'}}, {content:`$${(data.housingExpenses.total || 0).toFixed(2)}`, styles:{fontStyle:'bold'}}]); doc.autoTable({startY: yPos, body: housingBody, theme:'plain', styles:{fontSize:9, cellPadding:1.5}, columnStyles:{0:{fontStyle:'bold'}}}); yPos = doc.lastAutoTable.finalY + 7; if (data.otherDebts && data.otherDebts.length > 0) { checkYPdf(20 + data.otherDebts.length * 6); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Other Monthly Debts", 14, yPos); yPos += 6; const otherDebtsTableBody = data.otherDebts.map(d => [d.name, `$${d.amount.toFixed(2)}`]); doc.autoTable({ startY: yPos, head: [['Debt Name/Type', 'Monthly Payment ($)']], body: otherDebtsTableBody, theme: 'grid', headStyles: {fillColor: tableHeaderColor, textColor: textColor, fontStyle:'bold', fontSize:9}, styles: {fontSize:9, cellPadding:1.5}, columnStyles: {1:{halign:'right'}} }); yPos = doc.lastAutoTable.finalY; } checkYPdf(10); doc.setFontSize(10); doc.setFont(undefined, 'bold'); doc.text(`Total Other Monthly Debt Payments: $${(data.dtiCalculations.totalOtherMonthlyDebts || 0).toFixed(2)}`, 14, yPos); yPos += 10; doc.setFont(undefined, 'normal'); checkYPdf(30); doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("DTI Ratio Analysis", 14, yPos); yPos += 6; let dtiResultsBody = [ [{content: 'Front-End DTI (Housing Ratio):', styles:{fontStyle:'bold'}}, {content: `${(data.dtiCalculations.frontEndDti || 0).toFixed(1)}%`}], [{content: 'Back-End DTI (Total Debt Ratio):', styles:{fontStyle:'bold'}}, {content: `${(data.dtiCalculations.backEndDti || 0).toFixed(1)}%`}] ]; doc.autoTable({ startY: yPos, body: dtiResultsBody, theme:'plain', styles:{fontSize:10, cellPadding:1.5}, columnStyles:{0:{fontStyle:'bold'}}, didDrawCell: function (hookData) { if (hookData.column.index === 1) { // Styling for the DTI percentage values let dtiVal = parseFloat(hookData.cell.text[0].replace('%','')); let isFront = hookData.row.index === 0; const dtiColor = getDtiPdfColor(dtiVal, isFront); doc.setTextColor(dtiColor[0], dtiColor[1], dtiColor[2]); doc.setFont(undefined, 'bold'); } }, willDrawCell: function(hookData){ // Reset for next cells doc.setTextColor(textColor); doc.setFont(undefined, 'normal'); } }); yPos = doc.lastAutoTable.finalY + 7; checkYPdf(60); doc.setFontSize(10); doc.setTextColor(textColor); const interpretationText = getDtiInterpretation(data.dtiCalculations.backEndDti || 0) .replace(/

.*?<\/h4>/gi, '') // Remove h4 tag .replace(/

(.*?)<\/strong>(.*?)<\/p>/gi, '$1$2\n') // Strong tags with class .replace(/

.*?(.*?)<\/strong>.*?<\/p>/gi, '$1\n') // For other strong tags .replace(/(.*?)<\/strong>/gi, '$1') // Remaining strong tags .replace(/(.*?)<\/small>/gi, '\n($1)') .replace(/

(.*?)<\/p>/gi, '$1\n') .replace(/\n\s*\n/g, '\n') // Remove multiple blank lines .trim(); const splitText = doc.splitTextToSize(interpretationText, 180); doc.setFontSize(9.5); doc.text("Understanding Your Back-End DTI:", 14, yPos); yPos +=5; splitText.forEach(line => { checkYPdf(5); doc.text(line, 14, yPos); yPos += 5; }); doc.save("DTI_Analysis_Report.pdf"); } function getDtiPdfColor(dti, isFrontEnd) { const classColor = getDtiClass(dti, isFrontEnd); if (classColor === 'dti-good') return [40, 167, 69]; // Green if (classColor === 'dti-fair') return [253, 126, 20]; // Orange return [220, 53, 69]; // Red for high } // Initial calls updateDtiNavButtons(); toggleHousingFields(); calculateFrontEndDti(false); // Calculate on load but don't force display update in the div until income is entered

Scroll to Top