More than 1 year (Long Term)
1 year or less (Short Term)
Gross Profit (Gain):$0.00
Taxable Gain (After Exclusions):$0.00
Estimated Federal Tax Rate:0%
Net Investment Income Tax (NIIT):$0.00
Total Estimated Tax:$0.00
Net Profit After Tax:$0.00
Understanding Real Estate Capital Gains Tax
Selling a property often results in a significant financial windfall, but with profit comes the responsibility of taxes. Capital gains tax is the levy applied to the profit realized from the sale of a non-inventory asset, such as real estate. This calculator helps investors and homeowners estimate their potential tax liability by factoring in cost basis adjustments, selling expenses, and specific tax exclusions.
Key Concept: Cost Basis
Your tax isn't just calculated on the difference between what you bought and sold the house for. You can adjust your "Cost Basis" by adding the cost of capital improvements (like a new roof or kitchen renovation) and selling costs (agent commissions, legal fees). This lowers your taxable gain.
Short-Term vs. Long-Term Capital Gains
The duration you hold the property is the single most important factor in determining your tax rate:
Short-Term Capital Gains: If you owned the property for one year or less, the profit is taxed as ordinary income. This means it is added to your salary and other earnings and taxed at your marginal tax bracket (ranging from 10% to 37%).
Long-Term Capital Gains: If you held the property for more than one year, you qualify for preferential tax rates. Depending on your taxable income and filing status, these rates are typically 0%, 15%, or 20%, which is generally much lower than ordinary income tax rates.
The Section 121 Primary Residence Exclusion
One of the most powerful tax breaks in US real estate law is the Section 121 exclusion. If you have owned and used the home as your primary residence for at least two out of the five years prior to the sale, you can exclude a significant portion of the gain from taxation:
Single Filers: Can exclude up to $250,000 of gain.
Married Filing Jointly: Can exclude up to $500,000 of gain.
If your profit falls within these limits and you meet the criteria, you may owe $0 in federal capital gains tax.
Net Investment Income Tax (NIIT)
High-income earners may also be subject to an additional 3.8% Net Investment Income Tax. This applies if your Modified Adjusted Gross Income (MAGI) exceeds statutory thresholds (generally $200,000 for singles and $250,000 for married couples). Our calculator automatically checks if your income warrants this surcharge based on the inputs provided.
How to Use This Calculator
To get the most accurate estimate:
Purchase & Sale Price: Enter the exact contract prices.
Improvements: Sum up receipts for all permanent upgrades made to the property over the years. Do not include repairs (like fixing a leaky faucet), only improvements (like replacing the plumbing).
Selling Costs: Include real estate agent commissions, transfer taxes, and closing fees paid by the seller.
Filing Status & Income: These determine which tax bracket your gain falls into.
function calculateCapitalGains() {
// 1. Get Inputs
var purchasePrice = parseFloat(document.getElementById('purchasePrice').value) || 0;
var salePrice = parseFloat(document.getElementById('salePrice').value) || 0;
var improvements = parseFloat(document.getElementById('improvements').value) || 0;
var sellingCosts = parseFloat(document.getElementById('sellingCosts').value) || 0;
var annualIncome = parseFloat(document.getElementById('annualIncome').value) || 0;
var filingStatus = document.getElementById('filingStatus').value;
var duration = document.getElementById('ownershipDuration').value;
var isPrimary = document.getElementById('primaryResidence').checked;
// 2. Calculate Basis and Initial Gain
var adjustedBasis = purchasePrice + improvements;
var netProceeds = salePrice – sellingCosts;
var totalGain = netProceeds – adjustedBasis;
// If loss, no tax
if (totalGain <= 0) {
displayResults(totalGain, 0, 0, 0, 0);
return;
}
// 3. Apply Section 121 Exclusion if Primary Residence
var taxableGain = totalGain;
if (isPrimary) {
var exclusionAmount = (filingStatus === 'married') ? 500000 : 250000;
taxableGain = Math.max(0, totalGain – exclusionAmount);
}
// 4. Calculate Tax
var estimatedTax = 0;
var niitTax = 0;
var taxRateDisplay = "0%";
// Determine Tax Brackets (2024 Estimates for Long Term)
// Single: 0% < $47,025 | 15% $518,900
// Married: 0% < $94,050 | 15% $583,750
// Head: 0% < $63,000 | 15% $551,350
// NIIT Thresholds
// Single/Head: $200,000
// Married: $250,000
var totalTaxableIncome = annualIncome + taxableGain;
if (duration === 'short') {
// Short Term: Taxed as Ordinary Income
// Simplified progressive calculation not fully implemented here due to complexity,
// but we will estimate based on the top marginal bracket the income falls into.
// Using a simplified heuristic for estimation:
var marginalRate = 0.22; // Default mid-tier
if (totalTaxableIncome < 11600) marginalRate = 0.10;
else if (totalTaxableIncome < 47150) marginalRate = 0.12;
else if (totalTaxableIncome < 100525) marginalRate = 0.22;
else if (totalTaxableIncome < 191950) marginalRate = 0.24;
else if (totalTaxableIncome < 243725) marginalRate = 0.32;
else if (totalTaxableIncome < 609350) marginalRate = 0.35;
else marginalRate = 0.37;
estimatedTax = taxableGain * marginalRate;
taxRateDisplay = (marginalRate * 100).toFixed(1) + "% (Short Term/Ordinary)";
} else {
// Long Term Capital Gains Rates
var rate = 0;
// Define thresholds based on status
var limit0 = 47025;
var limit15 = 518900;
if (filingStatus === 'married') {
limit0 = 94050;
limit15 = 583750;
} else if (filingStatus === 'head') {
limit0 = 63000;
limit15 = 551350;
}
// Logic: The gain sits "on top" of ordinary income.
// We need to see which bucket the gain falls into relative to annualIncome.
var gainSittingStart = annualIncome;
var gainSittingEnd = annualIncome + taxableGain;
var tax0 = 0;
var tax15 = 0;
var tax20 = 0;
// Calculate portion in 0% bucket
if (gainSittingStart 0) tax0 = amountIn0 * 0;
}
// Calculate portion in 15% bucket
if (gainSittingEnd > limit0) {
var start15 = Math.max(gainSittingStart, limit0);
var end15 = Math.min(gainSittingEnd, limit15);
if (end15 > start15) {
tax15 = (end15 – start15) * 0.15;
}
}
// Calculate portion in 20% bucket
if (gainSittingEnd > limit15) {
var start20 = Math.max(gainSittingStart, limit15);
var amountIn20 = gainSittingEnd – start20;
if (amountIn20 > 0) {
tax20 = amountIn20 * 0.20;
}
}
estimatedTax = tax0 + tax15 + tax20;
// Calculate effective rate for display
var effectiveRate = (estimatedTax / taxableGain) * 100;
taxRateDisplay = effectiveRate.toFixed(1) + "% (Long Term)";
}
// 5. Calculate NIIT (Net Investment Income Tax) 3.8%
// Applies to the lesser of: Net Investment Income (the gain) OR (MAGI – Threshold)
var niitThreshold = (filingStatus === 'married') ? 250000 : 200000;
// MAGI roughly approx as annualIncome + taxableGain here for simplicity
var magi = annualIncome + taxableGain;
if (magi > niitThreshold) {
var amountSubjectToNiit = Math.min(taxableGain, magi – niitThreshold);
niitTax = amountSubjectToNiit * 0.038;
}
// 6. Final Results
var finalTotalTax = estimatedTax + niitTax;
var netProfit = totalGain – finalTotalTax; // Profit is Total Gain minus taxes owed
displayResults(totalGain, taxableGain, taxRateDisplay, niitTax, finalTotalTax, netProfit);
}
function displayResults(gross, taxable, rateStr, niit, totalTax, net) {
document.getElementById('result-container').style.display = 'block';
document.getElementById('resGrossGain').innerText = formatCurrency(gross);
document.getElementById('resTaxableGain').innerText = formatCurrency(taxable);
// If it was a string (rate display) or number
if (typeof rateStr === 'number') {
document.getElementById('resTaxRate').innerText = (rateStr * 100).toFixed(1) + "%";
} else {
document.getElementById('resTaxRate').innerText = rateStr;
}
document.getElementById('resNiit').innerText = formatCurrency(niit);
document.getElementById('resTotalTax').innerText = formatCurrency(totalTax);
document.getElementById('resNetProfit').innerText = formatCurrency(net);
}
function formatCurrency(num) {
return "$" + num.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
}