Embed documentation

Any of Far Better Off’s 27 calculators can be embedded on any website, free, with no account, no API key and no approval. There are three ways in: a plain <iframe>, a one-line <script>that builds the iframe for you, or simply pasting a calculator’s URL on a platform that supports oEmbed. The widget sizes itself to its content, follows your reader’s light or dark setting unless you pin it, accepts a starting value for any of the 188fields across those calculators, and sets no cookies and loads nothing from any third party. The only condition is the small “Powered by Far Better Off” link that comes with the code.

Which way in

Same widget and same terms in all four cases. Pick by what your publishing tool lets you paste.

MethodUse it whenNeeds JavaScript on the host
iframe + listenerYou can paste HTML and want the widget to work even with JavaScript off. The calculator itself still needs JavaScript inside the frame; only the resizing depends on the host's listener.Only to resize
One-line scriptYou would rather not choose a height or keep a block of inline script intact through a CMS paste box. This is the one to reach for by default.Yes
oEmbedYour platform expands pasted links. Nothing to copy at all — but what arrives is the platform's decision, and the three biggest all trim it. See what WordPress, Discourse and Ghost each do, below.Up to your platform
WordPress pluginYou run WordPress and want a block with a dropdown, or a shortcode, instead of a snippet.No

The one-line script

One request, roughly 2 KB compressed, no dependencies and no build step. It writes the iframe, sizes it, and adds the credit line where the script tag stands. Several widgets can share a page: the loader installs one message listener however many tags it finds, and matches each height message to the window that sent it.

<script src="https://farbetteroff.com/embed.js" data-calculator="mortgage-calculator" data-title="Mortgage Calculator" data-height="2600"></script>

Its attributes

Any other data-* attribute is read as a starting value for the calculator field of that name — the reference below lists all 188 of them.

AttributeAcceptsLeft offNotes
data-calculatorA calculator slugRequiredThe only required attribute. 27 slugs are listed below; data-calc is accepted as a shorthand.
data-widgetrates or mortgage-rates or savings-rates or money-numbers—Use instead of data-calculator for a widget that carries live figures rather than a form: rates is Today's rates, the embeddable form of /rates; mortgage-rates is Mortgage rates, a 3-row cut of the same /rates feed; savings-rates is Savings & CD rates, a 3-row cut of the same /rates feed; money-numbers is Money numbers, the embeddable form of /money-numbers. The loader already knows each one's width, height and credit link, so the tag needs nothing else. These have no fields to prefill and no compact layout — they are already the short form of their page.
data-titleAny textDerived from the slugThe frame's accessible name, which a screen reader reads before the calculator. Worth setting: the fallback turns "fire-calculator" into "Fire calculator".
data-themelight or darkFollows the readerAnything else, including leaving it off, lets each reader's own device setting decide.
data-layoutcompactstandardCompact trims the widget to the answer and the inputs — no chart, comparison, schedule, insight tiles, field help or share row — and puts the answer above the controls, for a sidebar. Readers reach the full calculator through the widget's title link. Anything but "compact" is the standard layout.
data-max-widthPixels600 (360 when compact)The widest the widget may get. It always shrinks to fit a narrower column, so this is a ceiling, not a width.
data-heightPixelsThis calculator's measured heightOnly on screen until the widget reports its real height, which is usually within a frame or two — but it is the height forever on a page that strips the script, so the builder fills it in from a browser measurement of this calculator at this width rather than from one number for all 27.

Those 8 names are the loader’s own settings, so they are the 8 names a calculator field can never have. None of the 188 fields does, and a build-time check keeps it that way.

The iframe

The widget lives at https://farbetteroff.com/embed/<slug>, and that URL is the whole API: ?theme= pins the theme, and any field name sets a starting value. It is a normal page, so you can open it in a tab to see exactly what your readers will get.

<iframe id="calcwise-mortgage-calculator" src="https://farbetteroff.com/embed/mortgage-calculator" title="Mortgage Calculator by Far Better Off" width="100%" height="2600" frameborder="0" style="border:0;max-width:600px;width:100%" loading="lazy"></iframe>
<script>window.addEventListener("message",function(e){if(e&&e.data&&e.data.type==="cw-embed-height"&&e.data.slug==="mortgage-calculator"){var f=document.getElementById("calcwise-mortgage-calculator");if(f){f.style.height=e.data.height+"px"}}});</script>
<p style="font:13px/1.4 system-ui,sans-serif;text-align:center;margin:6px 0">Powered by <a href="https://farbetteroff.com/calculators/mortgage-calculator" target="_blank" rel="noopener">Far Better Off</a></p>

The <p>with the credit link sits in your HTML rather than inside the frame, deliberately: a link inside an iframe is not a link to your readers’ search engines, and the credit is the whole price of the widget. The <script> is what resizes the frame; without it the widget works but stays at its starting height.

Sizing, and the height message

A calculator changes height as a reader uses it — open the amortization table and it grows by a thousand pixels. Rather than guess, the widget measures itself and tells the host page, which is the only way to avoid both an inner scrollbar and a page of empty space.

The contract

The frame calls parent.postMessage({type:"cw-embed-height", slug, height}, "*") when it mounts, whenever its own content resizes, and once more on load. height is the document height in CSS pixels, rounded up; slug is the calculator. That is the entire protocol — no other message is ever sent, and the frame never listens for one.

  • • Check e.origin before trusting a message. Any page can post to yours, and a host that resizes on an unchecked message can be pushed around by one.
  • • Match on e.source, not on the slug, if two copies of the same calculator might share a page.
  • • Until the first message lands, the frame is whatever height you gave it. The builder fills that in from a real browser measurement of the calculator you picked at the width you picked — 2600px for the mortgage calculator at 600px, against 2980px at 360px, where everything stacks and runs taller.

Wiring it up yourself

If you are building the host side — a React component, a Vue wrapper, a template partial — this is all of it.

<iframe id="calc" src="https://farbetteroff.com/embed/mortgage-calculator"
        title="Mortgage Calculator by Far Better Off" width="100%" height="2600"
        frameborder="0" style="border:0;max-width:600px;width:100%" loading="lazy"></iframe>
<script>
window.addEventListener("message", function (e) {
  // Check the origin first: any page can post a message to yours.
  if (e.origin !== "https://farbetteroff.com") return;
  var m = e.data;
  if (!m || m.type !== "cw-embed-height") return;
  var frame = document.getElementById("calc");
  // Matching on e.source rather than on m.slug lets two copies of the same
  // calculator share a page without resizing each other.
  if (frame && frame.contentWindow === e.source) {
    frame.style.height = Math.round(m.height) + "px";
  }
});
</script>

Theming

Left alone, the widget follows each reader’s own device setting, so it looks right on a dark site and a light one without you choosing. ?theme=light or ?theme=dark on the embed URL (data-theme on the loader) pins it instead, for a site whose design is one or the other regardless of the reader.

A pinned theme is applied before the first paint, so there is no flash of the other one. Anything other than light or dark — including a typo — leaves the reader in charge rather than failing.

The compact layout

?layout=compact on the embed URL (data-layout="compact"on the loader) cuts the widget down to the answer and the inputs, and moves the answer above them. A sidebar can’t be scrolled the way a page can, so what the widget shows first is what most readers see.

What comes off: the chart, the scenario comparison, the amortization schedule, the insight tiles, the per-field help text and the save/share row, whose links point at a page your reader isn’t on. What stays: the headline answer, every control that moves it, the breakdown rows, any warning, and the link to the full calculator in the widget’s own title. Compact defaults to 360px wide rather than 600px, because that is the column it is for, and to its own measured compact height — 1520px for the mortgage calculator, against 2600px standard, because trimming the chart and the schedule takes most of the page away. Both are yours to override.

Like the theme, it is applied before the first paint, so a compact widget never shows the full one and then collapses. Anything other than compact is the standard layout.

<!-- Compact: the answer and the sliders, sized for a sidebar -->
<script src="https://farbetteroff.com/embed.js" data-calculator="mortgage-calculator" data-title="Mortgage Calculator" data-layout="compact" data-height="1520"></script>

Starting values

Every one of the 188 fields on the 27calculators can be given a starting value, so the widget can open on numbers that suit your audience — your city’s home prices, your credit union’s rate, a 15-year term. Readers can still change every one of them; you are setting where the calculator opens, not what it allows.

On the embed URL it is a query parameter. On the loader it is the same name in data-* spelling, which the browser maps back for us: data-home-price arrives as homePrice.

<!-- A $525,000 house, 15% down, over 15 years -->
<script src="https://farbetteroff.com/embed.js" data-calculator="mortgage-calculator" data-title="Mortgage Calculator" data-theme="dark" data-max-width="720" data-height="2530" data-home-price="525000" data-down-mode="1" data-down-percent="15" data-term-years="15"></script>
https://farbetteroff.com/embed/mortgage-calculator?theme=dark&homePrice=525000&downMode=1&downPercent=15&termYears=15

That example opens the mortgage calculator on a $525,000 house, 15% down, over 15 years. It shows the one case worth knowing about: a few calculators have a mode switch, and the field it governs only means what you want once the mode is set alongside it. Here down-mode="1"selects “% of price”, which is what makes down-percent="15" a down payment of 15% rather than an ignored value. The table for each calculator below marks those fields.

Numbers only.A value that isn’t a number — $525,000with its symbol and comma, say — is ignored rather than argued with, so the field opens on whatever it would have anyway: that reader’s own last number if they have used the calculator before, and the default if not. A prefill can never leave the calculator in a broken state, but a malformed one fails quietly, so it is worth checking your snippet against the tables below.

Your numbers win, once. The widget remembers what a reader last typed, in their own browser. A starting value you set still takes precedence over that on arrival, so a returning reader sees the figures you chose rather than their own from last month — and anything they change from there is theirs again.

The range is the slider, not a limit. A starting value past the end of the slider is still used in the math; the thumb simply sits at the end until a reader drags it.

32 of them are choices, not sliders. Those accept the listed values — a loan term in months, a pay frequency — and the builder doesn’t offer them yet, so the URL and the data-* attribute are how you set them today.

45 appear only in context — a field that belongs to a mode the calculator isn’t in is hidden, but presetting it still works, and it is there when the reader switches.

Home & Mortgage

Mortgage Calculatormortgage-calculator · 12
Parameterdata-*What it isDefaultAccepts
homePricedata-home-priceHome price$400,00050,000 – 1,500,000
downModedata-down-modeEnter down payment as00 $ Amount · 1 % of price
downPaymentdata-down-paymentDown payment(in context)$80,0000 – 400,000
downPercentdata-down-percentDown payment(in context)20%0 – 100
ratedata-rateInterest rate (APR)6.5%1 – 12
termYearsdata-term-yearsLoan term3030 30 yr · 20 20 yr · 15 15 yr · 10 10 yr
extraMonthlydata-extra-monthlyExtra principal / month$00 – 3,000
taxYearlydata-tax-yearlyProperty tax / yr(follows another field)$3,6000 – 20,000
insuranceYearlydata-insurance-yearlyHome insurance / yr(follows another field)$1,9000 – 8,000
hoaMonthlydata-hoa-monthlyHOA / month$00 – 1,000
yearBuiltdata-year-builtYear built1,9852022 2020 or newer · 2015 2010s · 2005 2000s · 1995 1990s · 1985 1980s · 1975 1970s · 1965 1960s · 1955 1950s · 1945 1940s · 1930 Before 1940
pmiRatedata-pmi-ratePMI rate / yr(in context)0.5%0 – 2
Mortgage Payoff Calculatormortgage-payoff-calculator · 4
Parameterdata-*What it isDefaultAccepts
balancedata-balanceCurrent loan balance$300,00010,000 – 3,000,000
ratedata-rateInterest rate (APR)6.5%0 – 15
yearsdata-yearsYears left on loan281 – 40
extradata-extraExtra monthly payment$2000 – 5,000
Refinance Calculatorrefinance-calculator · 6
Parameterdata-*What it isDefaultAccepts
balancedata-balanceCurrent loan balance$320,00010,000 – 3,000,000
curRatedata-cur-rateCurrent interest rate7.25%0 – 15
curYearsLeftdata-cur-years-leftYears left on current loan271 – 40
newRatedata-new-rateNew interest rate6%0 – 15
newTermdata-new-termNew loan term (years)305 – 40
closingdata-closingClosing costs$6,0000 – 60,000
Rent vs Buy Calculatorrent-vs-buy-calculator · 18
Parameterdata-*What it isDefaultAccepts
modedata-modeDetail level00 Simple · 1 Detailed
yearsdata-yearsHow long you'll stay71 – 30
homePricedata-home-priceHome price$400,00050,000 – 1,500,000
rentdata-rentMonthly rent$2,400300 – 15,000
downPercentdata-down-percentDown payment20%0 – 100
ratedata-rateMortgage rate (APR)6.5%1 – 12
yearBuiltdata-year-builtYear built1,9852022 2020 or newer · 2015 2010s · 2005 2000s · 1995 1990s · 1985 1980s · 1975 1970s · 1965 1960s · 1955 1950s · 1945 1940s · 1930 Before 1940
termYearsdata-term-yearsLoan term(in context)3030 30 yr · 20 20 yr · 15 15 yr
homeGrowthdata-home-growthHome appreciation / yr(in context)4%-5 – 12
rentGrowthdata-rent-growthRent increase / yr(in context)3%0 – 10
investReturndata-invest-returnInvestment return / yr(in context)7%0 – 12
propTaxPctdata-prop-tax-pctProperty tax / yr(in context)0.89%0 – 4
maintPctdata-maint-pctMaintenance / yr(in context)(follows another field)1%0 – 4
insuranceYearlydata-insurance-yearlyHome insurance / yr(in context)(follows another field)$1,9000 – 8,000
pmiRatePctdata-pmi-rate-pctPMI / yr(in context)0.5%0 – 2
hoaMonthlydata-hoa-monthlyHOA / month(in context)$00 – 1,500
buyClosePctdata-buy-close-pctBuying costs(in context)2%0 – 6
sellClosePctdata-sell-close-pctSelling costs(in context)6%0 – 10
How Much House Can I Affordhow-much-house-can-i-afford · 7
Parameterdata-*What it isDefaultAccepts
incomedata-incomeAnnual household income$90,00020,000 – 500,000
debtsdata-debtsMonthly debt payments$5000 – 5,000
downdata-downDown payment$40,0000 – 300,000
ratedata-rateMortgage rate (APR)6.5%1 – 12
termYearsdata-term-yearsLoan term3030 30 yr · 15 15 yr
yearBuiltdata-year-builtYear built1,9852022 2020 or newer · 2015 2010s · 2005 2000s · 1995 1990s · 1985 1980s · 1975 1970s · 1965 1960s · 1955 1950s · 1945 1940s · 1930 Before 1940
taxRatedata-tax-rateProperty tax rate0.89%0 – 3
Debt-to-Income Calculatordebt-to-income-calculator · 6
Parameterdata-*What it isDefaultAccepts
incomedata-incomeGross monthly income$6,0000 – 100,000
housingdata-housingRent or mortgage payment$1,6000 – 30,000
autodata-autoCar / auto payments$4000 – 10,000
studentdata-studentStudent loan payments$2500 – 10,000
creditCardsdata-credit-cardsCredit card minimums$1500 – 10,000
otherdata-otherOther loan payments$00 – 10,000
Rent Affordability Calculatorrent-affordability-calculator · 4
Parameterdata-*What it isDefaultAccepts
incomedata-incomeGross income per year$60,0000 – 500,000
debtsdata-debtsOther monthly debt payments$00 – 10,000
pctdata-pctShare of income on rent30%15 – 50
utilitiesdata-utilitiesUtilities you pay on top of rent$00 – 2,000

Income & Taxes

Take-Home Paycheck Calculatortake-home-paycheck-calculator · 10
Parameterdata-*What it isDefaultAccepts
salarydata-salaryAnnual salary$75,00015,000 – 500,000
statusdata-statusFiling status00 Single · 1 Married (joint) · 2 Head of household · 3 Married (separate)
k401data-k401401(k) contribution5%0 – 30
k401typedata-k401typeContribution type(in context)00 Traditional (pre-tax) · 1 Roth (after-tax)
k401agedata-k401ageYour age this year(in context)00 Under 50 · 1 50–59 or 64+ · 2 60–63
statedata-stateWhere you work00 Select your state · 1 Alabama · 2 Alaska · 3 Arizona · 4 Arkansas · 5 California · 6 Colorado · 7 Connecticut · 8 Delaware · 9 District of Columbia · 10 Florida · 11 Georgia · 12 Hawaii · 13 Idaho · 14 Illinois · 15 Indiana · 16 Iowa · 17 Kansas · 18 Kentucky · 19 Louisiana · 20 Maine · 21 Maryland · 22 Massachusetts · 23 Michigan · 24 Minnesota · 25 Mississippi · 26 Missouri · 27 Montana · 28 Nebraska · 29 Nevada · 30 New Hampshire · 31 New Jersey · 32 New Mexico · 33 New York · 34 North Carolina · 35 North Dakota · 36 Ohio · 37 Oklahoma · 38 Oregon · 39 Pennsylvania · 40 Rhode Island · 41 South Carolina · 42 South Dakota · 43 Tennessee · 44 Texas · 45 Utah · 46 Vermont · 47 Virginia · 48 Washington · 49 West Virginia · 50 Wisconsin · 51 Wyoming
localitydata-localityCity, township, county or borough income tax(in context)00 None / not listed · 15 Bloomington (Monroe County) · 11 Carmel and Fishers (Hamilton County) · 13 Evansville (Vanderburgh County) · 9 Fort Wayne (Allen County) · 10 Gary and Hammond (Lake County) · 8 Indianapolis (Marion County) · 14 Lafayette (Tippecanoe County) · 12 South Bend (St. Joseph County) · 111 Bowling Green · 18 Lexington (I live in Fayette County) · 19 Lexington (I work there, live outside) · 16 Louisville (I live in Jefferson County) · 17 Louisville (I work there, live outside) · 51 Albion (I live in the city) · 52 Albion (I work there, live outside) · 31 Battle Creek (I live in the city) · 32 Battle Creek (I work there, live outside) · 49 Benton Harbor (I live in the city) · 50 Benton Harbor (I work there, live outside) · 39 Big Rapids (I live in the city) · 40 Big Rapids (I work there, live outside) · 6 Detroit (I live in the city) · 20 Detroit (I work there, live outside) · 29 East Lansing (I live in the city) · 30 East Lansing (I work there, live outside) · 25 Flint (I live in the city) · 26 Flint (I work there, live outside) · 21 Grand Rapids (I live in the city) · 22 Grand Rapids (I work there, live outside) · 43 Hamtramck (I live in the city) · 44 Hamtramck (I work there, live outside) · 35 Highland Park (I live in the city) · 36 Highland Park (I work there, live outside) · 53 Ionia (I live in the city) · 54 Ionia (I work there, live outside) · 23 Lansing (I live in the city) · 24 Lansing (I work there, live outside) · 55 Lapeer (I live in the city) · 56 Lapeer (I work there, live outside) · 37 Muskegon (I live in the city) · 38 Muskegon (I work there, live outside) · 45 Muskegon Heights (I live in the city) · 46 Muskegon Heights (I work there, live outside) · 27 Pontiac (I live in the city) · 28 Pontiac (I work there, live outside) · 47 Portland (I live in the city) · 48 Portland (I work there, live outside) · 33 Saginaw (I live in the city) · 34 Saginaw (I work there, live outside) · 57 Springfield (I live in the city) · 58 Springfield (I work there, live outside) · 41 Walker (I live in the city) · 42 Walker (I work there, live outside) · 110 St. Louis · 7 New York City (I live in the city) · 97 Akron · 99 Canton · 1 Cincinnati · 2 Cleveland · 3 Columbus · 106 Cuyahoga Falls · 98 Dayton · 105 Euclid · 104 Hamilton · 101 Kettering · 109 Lakewood · 103 Lorain · 108 Mansfield · 107 Middletown · 102 Parma · 100 Springfield · 96 Toledo · 91 Abington Township · 61 Allentown (I live in the city) · 62 Allentown (I work there, live outside) · 75 Altoona (I live in the city) · 76 Altoona (I work there, live outside) · 90 Bensalem Township · 69 Bethlehem (I live in the city) · 70 Bethlehem (I work there, live outside) · 93 Bristol Township · 87 Cheltenham Township (I live in the township) · 88 Cheltenham Township (I work there, live outside) · 65 Erie (I live in the city) · 66 Erie (I work there, live outside) · 73 Harrisburg (I live in the city) · 74 Harrisburg (I work there, live outside) · 71 Lancaster (I live in the city) · 72 Lancaster (I work there, live outside) · 92 Millcreek Township · 95 Mount Lebanon Township (I live in the township) · 83 Norristown Borough (I live in the borough) · 84 Norristown Borough (I work there, live outside) · 4 Philadelphia (I live in the city) · 5 Philadelphia (I work there, live outside) · 59 Pittsburgh (I live in the city) · 60 Pittsburgh (I work there, live outside) · 63 Reading (I live in the city) · 64 Reading (I work there, live outside) · 94 Ross Township (I live in the township) · 67 Scranton (I live in the city) · 68 Scranton (I work there, live outside) · 81 State College Borough (I live in the borough) · 82 State College Borough (I work there, live outside) · 89 Upper Darby Township · 85 West Chester Borough (I live in the borough) · 86 West Chester Borough (I work there, live outside) · 79 Wilkes-Barre (I live in the city) · 80 Wilkes-Barre (I work there, live outside) · 77 York (I live in the city) · 78 York (I work there, live outside)
schoolDistrictdata-school-districtSchool district (where you live)(in context)00 None / not listed · 69 Ada Exempted Village School District (3301) · 1 Amanda-Clearcreek Local School District (2301) · 70 Anna Local School District (7501) · 71 Ansonia Local School District (1901) · 72 Antwerp Local School District (6301) · 73 Arcadia Local School District (3201) · 74 Arcanum-Butler Local School District (1902) · 75 Arlington Local School District (3202) · 2 Athens City School District (0502) · 76 Ayersville Local School District (2001) · 77 Bellevue City School District (3901) · 3 Berkshire Local School District (2801) · 4 Berne Union Local School District (2302) · 5 Bethel Local School District (5501) · 78 Bexley City School District (2501) · 79 Big Walnut Local School District (2101) · 6 Blanchester Local School District (1401) · 80 Bloom-Carroll Local School District (2303) · 81 Bluffton Exempted Village School District (0203) · 7 Botkins Local School District (7502) · 82 Bowling Green City School District (8701) · 83 Bradford Exempted Village School District (5502) · 84 Bryan City School District (8601) · 85 Buckeye Central Local School District (1701) · 86 Buckeye Valley Local School District (2102) · 87 Canal Winchester Local School District (2502) · 8 Cardington-Lincoln Local School District (5901) · 88 Carey Exempted Village School District (8801) · 89 Carlisle Local School District (8301) · 90 Cedar Cliff Local School District (2902) · 9 Celina City School District (5401) · 91 Centerburg Local School District (4201) · 92 Central Local School District (2002) · 10 Chippewa Local School District (8501) · 11 Circleville City School District (6501) · 12 Clear Fork Valley Local School District (7001) · 93 Clermont-Northeastern Local School District (1303) · 13 Clinton-Massie Local School District (1402) · 14 Cloverleaf Local School District (5204) · 15 Clyde-Green Springs Exempted Village School District (7201) · 94 Coldwater Exempted Village School District (5402) · 95 Colonel Crawford Local School District (1703) · 96 Columbiana Exempted Village School District (1502) · 97 Columbus Grove Local School District (6901) · 98 Continental Local School District (6902) · 99 Cory-Rawson Local School District (3203) · 100 Covington Exempted Village School District (5503) · 16 Crestline Exempted Village School District (1704) · 101 Crestview Local School District (1503) · 102 Crestview Local School District (8101) · 103 Dalton Local School District (8502) · 104 Danville Local School District (4202) · 105 Defiance City School District (2003) · 106 Delphos City School District (0204) · 17 Eastwood Local School District (8702) · 107 Eaton City School District (6803) · 108 Edgerton Local School District (8602) · 18 Elgin Local School District (5101) · 109 Elmwood Local School District (8703) · 110 Evergreen Local School District (2602) · 111 Fairbanks Local School District (8001) · 112 Fairborn City School District (2903) · 113 Fairfield Union Local School District (2304) · 114 Fairlawn Local School District (7503) · 115 Fayette Local School District (2603) · 19 Findlay City School District (3204) · 116 Fort Loramie Local School District (7504) · 117 Fort Recovery Local School District (5406) · 118 Franklin Monroe Local School District (1903) · 119 Fremont City School District (7202) · 20 Geneva Area City School District (0404) · 21 Gibsonburg Exempted Village School District (7203) · 120 Goshen Local School District (1305) · 121 Granville Exempted Village School District (4501) · 22 Green Local School District (8503) · 122 Greeneview Local School District (2904) · 23 Greenfield Exempted Village School District (3603) · 123 Greenville City School District (1904) · 124 Hardin Northern Local School District (3302) · 125 Hardin-Houston Local School District (7505) · 126 Hicksville Exempted Village School District (2004) · 127 Highland Local School District (5902) · 128 Hillsboro City School District (3604) · 24 Hillsdale Local School District (0302) · 129 Holgate Local School District (3501) · 25 Hopewell-Loudon Local School District (7403) · 26 Jackson Center Local School District (7506) · 27 James A Garfield Local School District (6704) · 28 Jefferson Local School District (4901) · 130 Jennings Local School District (6903) · 131 Johnstown-Monroe Local School District (4503) · 29 Jonathan Alder Local School District (4902) · 132 Kalida Local School District (6904) · 133 Kenton City School District (3303) · 30 Kings Local School District (8303) · 134 Lakota Local School District (7204) · 31 Lancaster City School District (2305) · 135 Leipsic Local School District (6905) · 136 Liberty Center Local School District (3502) · 137 Liberty Union-Thurston Local School District (2306) · 138 Liberty-Benton Local School District (3205) · 139 Licking Valley Local School District (4506) · 32 Logan Elm Local School District (6502) · 140 London City School District (4903) · 141 Loudonville-Perrysville Exempted Village School District (0303) · 142 Madison Local School District (0905) · 33 Madison Plains Local School District (4904) · 34 Marion Local School District (5403) · 143 McComb Local School District (3206) · 144 Mechanicsburg Exempted Village School District (1102) · 35 Miami East Local School District (5504) · 145 Millcreek-West Unity Local School District (8604) · 146 Miller City-New Cleveland Local School District (6906) · 36 Milton-Union Exempted Village School District (5505) · 147 Minster Local School District (0601) · 148 Mississinawa Valley Local School District (1905) · 149 Mohawk Local School District (8802) · 37 Monroeville Local School District (3902) · 38 Montpelier Exempted Village School District (8605) · 150 Mount Gilead Exempted Village School District (5903) · 151 National Trail Local School District (6802) · 152 New Bremen Local School District (0602) · 153 New Knoxville Local School District (0603) · 154 New Lebanon Local School District (5708) · 155 New London Local School District (3903) · 156 New Miami Local School District (0907) · 157 New Riegel Local School District (7404) · 158 Newark City School District (4507) · 159 Newton Local School District (5506) · 39 North Baltimore Local School District (8705) · 40 North Fork Local School District (4508) · 160 North Union Local School District (8003) · 41 Northeastern Local School District (1203) · 161 Northmor Local School District (5904) · 42 Northridge Local School District (4509) · 43 Northwest Local School District (7612) · 44 Northwestern Local School District (1204) · 162 Northwestern Local School District (8505) · 45 Northwood Local School District (8706) · 46 Norton City School District (7711) · 163 Norwalk City School District (3904) · 47 Norwayne Local School District (8504) · 164 Oberlin City School District (4712) · 165 Old Fort Local School District (7405) · 166 Otsego Local School District (8707) · 167 Ottawa-Glandorf Local School District (6907) · 168 Ottoville Local School District (6908) · 169 Pandora-Gilboa Local School District (6909) · 170 Parkway Local School District (5405) · 171 Patrick Henry Local School District (3504) · 172 Paulding Exempted Village School District (6302) · 173 Perrysburg Exempted Village School District (8708) · 174 Pettisville Local School District (2604) · 175 Pickerington Local School District (2307) · 176 Pike-Delta-York Local School District (2605) · 177 Piqua City School District (5507) · 48 Pleasant Local School District (5103) · 178 Plymouth-Shiloh Local School District (7007) · 179 Preble Shawnee Local School District (6804) · 180 Reynoldsburg City School District (2509) · 49 Ridgedale Local School District (5104) · 181 Ridgemont Local School District (3304) · 50 River Valley Local School District (5105) · 182 Riverdale Local School District (3305) · 51 Riverside Local School District (4604) · 52 Ross Local School District (0908) · 183 Russia Local School District (7507) · 53 Sebring Local School District (5008) · 184 Seneca East Local School District (7406) · 185 Shelby City School District (7008) · 54 Sidney City School District (7508) · 186 South Central Local School District (3905) · 187 Southeastern Local School District (1205) · 188 Southwest Licking Local School District (4510) · 55 Southwest Local School District (3118) · 189 Spencerville Local School District (0209) · 190 Springfield Local School District (5010) · 56 St Marys City School District (0604) · 191 Stryker Local School District (8607) · 192 Swanton Local School District (2606) · 193 Talawanda City School District (0909) · 57 Teays Valley Local School District (6503) · 58 Tiffin City School District (7407) · 59 Tri-County North Local School District (6806) · 194 Tri-Village Local School District (1906) · 195 Triad Local School District (1103) · 60 Trimble Local School District (0505) · 61 Triway Local School District (8509) · 62 Troy City School District (5509) · 196 Twin Valley Community Local School District (6805) · 197 Union-Scioto Local School District (7106) · 198 United Local School District (1510) · 199 Upper Sandusky Exempted Village School District (8803) · 200 Upper Scioto Valley Local School District (3306) · 201 Valley View Local School District (5713) · 202 Van Buren Local School District (3207) · 203 Van Wert City School District (8104) · 204 Vanlue Local School District (3208) · 205 Versailles Exempted Village School District (1907) · 63 Walnut Township Local School District (2308) · 206 Wapakoneta City School District (0605) · 64 Washington Court House City School District (2402) · 65 Wauseon Exempted Village School District (2607) · 207 Wayne Trace Local School District (6303) · 208 Waynesfield-Goshen Local School District (0606) · 209 Wellington Exempted Village School District (4715) · 210 West Liberty-Salem Local School District (1105) · 211 Western Reserve Local School District (3906) · 66 Westerville City School District (2514) · 67 Willard City School District (3907) · 212 Wyoming City School District (3122) · 213 Xenia Community City School District (2906) · 214 Yellow Springs Exempted Village School District (2907) · 68 Zane Trace Local School District (7107)
stateRatedata-state-rateState income tax(in context)5%0 – 13
freqdata-freqPay schedule2652 Weekly · 26 Every 2 weeks · 24 Twice a month · 12 Monthly
Budget Calculatorbudget-calculator · 1
Parameterdata-*What it isDefaultAccepts
incomedata-incomeMonthly take-home pay$4,500500 – 50,000
Salary to Hourly Calculatorsalary-to-hourly-calculator · 6
Parameterdata-*What it isDefaultAccepts
modedata-modeWhat do you want to convert?00 💵 Salary → hourly · 1 ⏱️ Hourly → salary
salarydata-salaryYearly salary(in context)$60,0000 – 500,000
hourlydata-hourlyHourly rate(in context)$250 – 500
hoursPerWeekdata-hours-per-weekHours per week401 – 100
otMultiplierdata-ot-multiplierHours over 40 are paid at(in context)1.51.5 1.5× time-and-a-half · 2 2× double time · 1 1× no premium
weeksPerYeardata-weeks-per-yearPaid weeks per year521 – 52

Loans & Debt

Auto Loan Calculatorauto-loan-calculator · 7
Parameterdata-*What it isDefaultAccepts
pricedata-priceVehicle price$35,0005,000 – 120,000
downPaymentdata-down-paymentDown payment$3,5000 – 40,000
tradeIndata-trade-inTrade-in value$00 – 40,000
ratedata-rateInterest rate (APR)7.5%0 – 20
termMonthsdata-term-monthsLoan term6036 36 mo · 48 48 mo · 60 60 mo · 72 72 mo · 84 84 mo
salesTaxdata-sales-taxSales tax6%0 – 12
extraMonthlydata-extra-monthlyExtra principal / month$00 – 1,000
Car Affordability Calculatorcar-affordability-calculator · 6
Parameterdata-*What it isDefaultAccepts
takeHomedata-take-homeMonthly take-home pay$4,2001,000 – 40,000
payPctdata-pay-pctShare of pay for the car10%5 – 20
operatingdata-operatingInsurance, gas & upkeep$2960 – 3,000
downdata-downDown payment + trade-in$4,0000 – 60,000
ratedata-rateInterest rate (APR)7.5%0 – 20
termMonthsdata-term-monthsLoan term4836 36 mo · 48 48 mo · 60 60 mo · 72 72 mo
Personal Loan Calculatorpersonal-loan-calculator · 3
Parameterdata-*What it isDefaultAccepts
amountdata-amountLoan amount$15,000500 – 100,000
ratedata-rateInterest rate (APR)12%1 – 36
termMonthsdata-term-monthsLoan term3612 12 mo · 24 24 mo · 36 36 mo · 48 48 mo · 60 60 mo · 72 72 mo
Credit Card Payoff Calculatorcredit-card-payoff-calculator · 4
Parameterdata-*What it isDefaultAccepts
balancedata-balanceCard balance$6,0000 – 50,000
aprdata-aprInterest rate (APR)22%0 – 35
modedata-modeHow will you pay it?00 💪 A fixed amount · 1 🐌 Minimum only
paymentdata-paymentMonthly payment(in context)(follows another field)$2500 – 3,000
Debt Snowball vs. Avalanche Calculatordebt-snowball-calculator · 21
Parameterdata-*What it isDefaultAccepts
debtsdata-debtsHow many debts?32 2 · 3 3 · 4 4 · 5 5 · 6 6
bal1data-bal1Debt 1 · balance(in context)$6,2000 – 50,000
apr1data-apr1Debt 1 · rate (APR)(in context)24.99%0 – 36
min1data-min1Debt 1 · minimum payment(in context)$1550 – 2,000
bal2data-bal2Debt 2 · balance(in context)$2,1000 – 50,000
apr2data-apr2Debt 2 · rate (APR)(in context)6.5%0 – 36
min2data-min2Debt 2 · minimum payment(in context)$950 – 2,000
bal3data-bal3Debt 3 · balance(in context)$11,5000 – 50,000
apr3data-apr3Debt 3 · rate (APR)(in context)18.9%0 – 36
min3data-min3Debt 3 · minimum payment(in context)$2600 – 2,000
bal4data-bal4Debt 4 · balance(in context)$3,4000 – 50,000
apr4data-apr4Debt 4 · rate (APR)(in context)15.9%0 – 36
min4data-min4Debt 4 · minimum payment(in context)$900 – 2,000
bal5data-bal5Debt 5 · balance(in context)$9000 – 50,000
apr5data-apr5Debt 5 · rate (APR)(in context)0%0 – 36
min5data-min5Debt 5 · minimum payment(in context)$750 – 2,000
bal6data-bal6Debt 6 · balance(in context)$17,0000 – 50,000
apr6data-apr6Debt 6 · rate (APR)(in context)7.5%0 – 36
min6data-min6Debt 6 · minimum payment(in context)$1900 – 2,000
extradata-extraExtra payment / month$2000 – 3,000
plandata-planWhich order?00 🏔 Avalanche · 1 ⛄ Snowball

Saving & Investing

Compound Interest Calculatorcompound-interest-calculator · 7
Parameterdata-*What it isDefaultAccepts
modedata-modeWhat do you want to figure out?00 💰 What I'll have · 1 🎯 Time to reach a goal
principaldata-principalStarting amount$10,0000 – 200,000
monthlydata-monthlyMonthly contribution$5000 – 5,000
ratedata-rateAnnual return7%0 – 15
yearsdata-yearsYears(in context)251 – 50
targetdata-targetGoal amount(in context)$1,000,0005,000 – 2,000,000
perYeardata-per-yearCompounding1212 Monthly · 4 Quarterly · 1 Yearly
Net Worth Calculatornet-worth-calculator · 11
Parameterdata-*What it isDefaultAccepts
cashdata-cashCash & savings$12,0000 – 1,000,000
investmentsdata-investmentsInvestments (brokerage)$20,0000 – 5,000,000
retirementdata-retirementRetirement (401k / IRA)$45,0000 – 5,000,000
homedata-homeHome value$320,0000 – 5,000,000
vehiclesdata-vehiclesVehicles$18,0000 – 500,000
otherAssetsdata-other-assetsOther assets$00 – 2,000,000
mortgagedata-mortgageMortgage balance$250,0000 – 5,000,000
autoLoansdata-auto-loansAuto loans$9,0000 – 500,000
studentLoansdata-student-loansStudent loans$14,0000 – 500,000
creditCardsdata-credit-cardsCredit card debt$3,0000 – 200,000
otherDebtsdata-other-debtsOther debts$00 – 1,000,000
Retirement Calculatorretirement-calculator · 8
Parameterdata-*What it isDefaultAccepts
agedata-ageYour age now3018 – 70
retireAgedata-retire-ageRetirement age6540 – 75
currentdata-currentSaved so far$25,0000 – 2,000,000
monthlydata-monthlyMonthly contribution$6000 – 5,000
ratedata-rateAnnual return7%1 – 12
withdrawRatedata-withdraw-rateYearly withdrawal rate44 4% · 25× · 3.5 3.5% · 29× · 3 3% · 33×
ssMonthlydata-ss-monthlySocial Security at 67 (monthly)$2,6000 – 5,000
ssAgedata-ss-ageClaim Social Security at(in context)6762 62 — 70% of your full benefit · 63 63 — 75% of your full benefit · 64 64 — 80% of your full benefit · 65 65 — 86.7% of your full benefit · 66 66 — 93.3% of your full benefit · 67 67 — full benefit (100%) · 68 68 — 108% of your full benefit · 69 69 — 116% of your full benefit · 70 70 — 124% of your full benefit
401(k) Calculator401k-calculator · 9
Parameterdata-*What it isDefaultAccepts
agedata-ageYour age now3018 – 70
retireAgedata-retire-ageRetirement age6540 – 75
salarydata-salaryAnnual salary$65,00010,000 – 500,000
balancedata-balanceCurrent 401(k) balance$25,0000 – 3,000,000
contribPctdata-contrib-pctYou contribute6%0 – 40
matchRatedata-match-rateEmployer matches50%0 – 100
matchLimitPctdata-match-limit-pctUp to this % of pay6%0 – 15
ratedata-rateAnnual return7%1 – 12
raisedata-raiseAnnual raise2%0 – 8
FIRE Calculatorfire-calculator · 8
Parameterdata-*What it isDefaultAccepts
modedata-modeWhat do you want to know?00 🔥 My FIRE date · 1 🏖️ Coast FIRE
agedata-ageYour age now3018 – 70
retireAgedata-retire-ageAge you'd retire anyway(in context)6540 – 75
incomedata-incomeTake-home pay / year$70,0000 – 500,000
spendingdata-spendingYou spend / year$45,0000 – 300,000
currentdata-currentInvested so far$30,0000 – 3,000,000
ratedata-rateAnnual return (after inflation)7%1 – 10
withdrawaldata-withdrawalWithdrawal rate4%2 – 6
Roth vs Traditional Calculatorroth-vs-traditional-calculator · 7
Parameterdata-*What it isDefaultAccepts
accountdata-accountWhich account?00 🏦 IRA · 1 🏢 401(k) / 403(b)
agedata-ageYour age this year4040 Under 50 · 55 50–59 or 64+ · 61 60–63
contributiondata-contributionYearly contribution(follows another field)$7,5000 – 35,750
yearsdata-yearsYears until retirement301 – 50
ratedata-rateAnnual return7%1 – 12
taxNowdata-tax-nowYour tax rate now22%0 – 50
taxRetiredata-tax-retireTax rate in retirement22%0 – 50
Roth IRA Calculatorroth-ira-calculator · 5
Parameterdata-*What it isDefaultAccepts
agedata-ageYour age now3018 – 70
retireAgedata-retire-ageRetirement age6540 – 75
balancedata-balanceCurrent Roth IRA balance$8,0000 – 2,000,000
annualdata-annualYearly contribution$7,5000 – 8,600
ratedata-rateAnnual return7%1 – 12
401(k) Match Calculator401k-match-calculator · 4
Parameterdata-*What it isDefaultAccepts
salarydata-salaryYour yearly salary$60,0000 – 500,000
contribPctdata-contrib-pctYou contribute4%0 – 50
matchRatedata-match-rateEmployer matches50%0 – 100
matchLimitPctdata-match-limit-pctUp to this % of your pay6%0 – 15
Savings Goal Calculatorsavings-goal-calculator · 4
Parameterdata-*What it isDefaultAccepts
goaldata-goalSavings goal$30,000500 – 500,000
currentdata-currentAlready saved$5,0000 – 200,000
yearsdata-yearsYears to save51 – 40
apydata-apyInterest rate (APY)4%0 – 12
CD Calculatorcd-calculator · 3
Parameterdata-*What it isDefaultAccepts
depositdata-depositDeposit amount$10,000100 – 1,000,000
apydata-apyInterest rate (APY)4.25%0 – 10
termMonthsdata-term-monthsTerm123 3 mo · 6 6 mo · 9 9 mo · 12 12 mo · 18 18 mo · 24 24 mo · 36 36 mo · 48 48 mo · 60 60 mo
Emergency Fund Calculatoremergency-fund-calculator · 4
Parameterdata-*What it isDefaultAccepts
expensesdata-expensesMonthly essential expenses$3,500500 – 20,000
monthsdata-monthsMonths of cushion63 3 months · 6 6 months · 12 12 months
saveddata-savedAlready saved$4,0000 – 100,000
monthlySavedata-monthly-saveYou can save / month$4000 – 5,000
Inflation Calculatorinflation-calculator · 3
Parameterdata-*What it isDefaultAccepts
amountdata-amountAmount today$10,0000 – 5,000,000
yearsdata-yearsYears from now201 – 60
ratedata-rateAnnual inflation3%0 – 15

oEmbed

Every calculator page, every embed URL and every /rates, /money-numbers page advertises an oEmbed endpoint, so a platform that runs discovery can resolve a pasted Far Better Off link with nothing copied. What it does with the answer is its own decision, and a platform that has never heard of us usually trims it — the three sections below say exactly what WordPress, Discourse and Ghost each render, read off their source. The endpoint is https://farbetteroff.com/api/oembed, it answers json and xml, and it returns a rich response whose html is the same markup as the iframe snippet above.

curl "https://farbetteroff.com/api/oembed?url=https://farbetteroff.com/calculators/mortgage-calculator"

It accepts the spec’s maxwidth and maxheightas ceilings, passes a pasted link’s theme and field values through into the widget, and drops anything else (so a tracking parameter on a shared link can’t ride along). For a calculator it also hands back a thumbnail that is a picture of the answer rather than a logo. Some platforms only allow providers on a public list; if yours asks, the provider name is Far Better Off and the endpoint is the URL above.

Live-data pages resolve too

The live-data pages below are the URL a reader would actually have in their clipboard, so they resolve the same way a calculator page does — paste it and a platform that runs discovery renders the widget instead of the link. The response carries a thumbnail_url too — the same card the page shares, served from https://farbetteroff.com/og/rates, a URL that stays put across deploys and refreshes on the widget’s own six-hour timer, so a consumer that shows a picture rather than the widget gets today’s figures instead of a logo.

curl "https://farbetteroff.com/api/oembed?url=https://farbetteroff.com/rates"

What WordPress does with it

Worth knowing before you paste, because WordPress rewrites what it gets back from any provider that isn’t on its own list. Its wp_filter_oembed_result() keeps the <iframe> and discards everything around it, allows eight attributes on it (src, width, height, frameborder, marginwidth, marginheight, scrolling, title) and adds sandbox="allow-scripts". So the resize listener and the credit line are gone and the widget stands at the measured height this endpoint returns — it still calculates, and its own links still work, but nothing on the host page says where it came from. The free WordPress plugin registers Far Better Off as a provider, and a registered provider’s markup is passed through untouched: auto-height and credit line intact.

What Discourse does with it

A forum renders a provider’s own oEmbed markup only when the iframe’s address matches its allowed_iframessetting, which ships with six entries (Google Maps, OpenStreetMap, Google Calendar, CodePen, Instagram, Spotify). So on a forum that hasn’t been told about us, a pasted link is a onebox link preview — the calculator’s title, description and result image, with a link back — not the widget. An admin turns it into the widget in one line: Settings → Posting → allowed_iframes, add https://farbetteroff.com/embed/. Discourse then keeps more of the snippet than WordPress does: the “Powered by Far Better Off” line survives its sanitizer, and its sandbox allows the widget’s own links to open. The resize script doesn’t survive, so the widget stands at the measured height this endpoint returns.

What Ghost does with it

Ghost 6.34 and later ignores the htmlfrom any provider not on its built-in list — “an arbitrary site’s self-declared oEmbed endpoint, which we must not trust” — and renders a bookmark cardinstead: the calculator’s title, description, share image and a link back. That is Ghost’s decision and nothing we publish changes it. On Ghost 6.33 and earlier the same paste becomes the widget. To put the calculator itself on a current Ghost site, use the iframe or the one-line script above in an HTML card — both work, and both keep the credit line and the auto-height.

What the widget does to your page

The short version: nothing you didn’t ask for. The longer version, because “no tracking” is a claim worth spelling out:

What happens
CookiesNone. Not by the widget, not by the loader, not by the page inside the frame.
Third-party requestsNone. Everything the widget loads comes from farbetteroff.com — no ad network, no font CDN, no tag manager, no analytics vendor on your readers' browsers but ours, and ours is cookieless and counts page views.
Local storageOne key inside the frame, on the reader's own device, holding the numbers they typed so the calculator remembers them next time. It is written only if they change something, it is never sent anywhere, and a browser that blocks storage in a third-party frame costs nothing but that memory.
Your readers' dataStays in their browser. The calculators run entirely on the client — the numbers a reader types are never sent to us, because there is nothing to send them to.
Your page's DOMThe loader inserts one <div> where its <script> tag stands, containing the iframe and the credit line, and installs one message listener. It reads nothing else on your page.
WeightThe loader is 7,904 bytes of readable, unminified JavaScript — roughly 2 KB compressed — in one request. Check it yourself: curl -s https://farbetteroff.com/embed.js | wc -c. The iframe is lazy-loaded, so a widget below the fold costs nothing until a reader scrolls to it.

If your site runs a Content Security Policy, this is all it needs:

Content-Security-Policy:
  frame-src  https://farbetteroff.com;
  script-src https://farbetteroff.com;   /* only if you use the one-line loader */

When something looks wrong

The widget is stuck at its starting height, with a scrollbar inside it.

The height message isn't reaching your page. Either the listener script was stripped on paste — CMS editors do this — or a CSP is blocking it. The one-line script is the fix: it installs its own listener, so there is nothing for an editor to remove.

It's much too tall, with empty space under the calculator.

The same cause, seen on a wide column: the frame is sitting at the starting height you gave it instead of measuring itself. Check that the listener survived, or switch to the one-line script.

My starting values are being ignored.

Check the spelling against the table above — the name is case-sensitive, and on the loader it must be the hyphenated data-* form. A value that isn't a plain number is ignored by design, so a currency symbol or a thousands comma in the attribute leaves the field where it already was. Open your embed URL directly in a tab: the fields either show your numbers or they don't, which is faster than reading the snippet again.

Nothing renders at all.

If you used the one-line script, check that data-calculator holds a real slug from the list above, and that your CMS didn't rewrite the <script> tag. If you sandbox the iframe yourself, it needs at least allow-scripts — the calculator is client-side.

It doesn't match my site's dark mode.

By default it follows the reader's device rather than your site's setting, which is usually what you want and occasionally isn't. Pin it with data-theme="dark" or ?theme=dark.

Terms, in full

  • • Free for any site, commercial or not. No account, no key, no application, no usage limit, and nothing to renew.
  • • Keep the “Powered by Far Better Off” link that comes with the code. That link is what pays for all of this.
  • • The calculators are educational tools, not financial advice, and some are deliberately narrower than they look: the paycheck calculator is federal-only, and house affordability and rent-vs-buy leave out PMI. Each calculator page states its own assumptions — worth a look before you put one in front of your readers.
  • • The loader is MIT licensed, so you are welcome to host your own copy of /embed.js rather than load ours.

Want the numbers without the frame?

The same math is a free JSON API — no key, CORS open, cacheable — if you would rather build your own interface around it than put ours on your page. Read the API docs → or see a worked example →