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.
| Method | Use it when | Needs JavaScript on the host |
|---|---|---|
| iframe + listener | You 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 script | You 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 |
| oEmbed | Your 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 plugin | You 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.
| Attribute | Accepts | Left off | Notes |
|---|---|---|---|
| data-calculator | A calculator slug | Required | The only required attribute. 27 slugs are listed below; data-calc is accepted as a shorthand. |
| data-widget | rates 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-title | Any text | Derived from the slug | The frame's accessible name, which a screen reader reads before the calculator. Worth setting: the fallback turns "fire-calculator" into "Fire calculator". |
| data-theme | light or dark | Follows the reader | Anything else, including leaving it off, lets each reader's own device setting decide. |
| data-layout | compact | standard | Compact 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-width | Pixels | 600 (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-height | Pixels | This calculator's measured height | Only 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=15That 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
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| homePrice | data-home-price | Home price | $400,000 | 50,000 – 1,500,000 |
| downMode | data-down-mode | Enter down payment as | 0 | 0 $ Amount · 1 % of price |
| downPayment | data-down-payment | Down payment(in context) | $80,000 | 0 – 400,000 |
| downPercent | data-down-percent | Down payment(in context) | 20% | 0 – 100 |
| rate | data-rate | Interest rate (APR) | 6.5% | 1 – 12 |
| termYears | data-term-years | Loan term | 30 | 30 30 yr · 20 20 yr · 15 15 yr · 10 10 yr |
| extraMonthly | data-extra-monthly | Extra principal / month | $0 | 0 – 3,000 |
| taxYearly | data-tax-yearly | Property tax / yr(follows another field) | $3,600 | 0 – 20,000 |
| insuranceYearly | data-insurance-yearly | Home insurance / yr(follows another field) | $1,900 | 0 – 8,000 |
| hoaMonthly | data-hoa-monthly | HOA / month | $0 | 0 – 1,000 |
| yearBuilt | data-year-built | Year built | 1,985 | 2022 2020 or newer · 2015 2010s · 2005 2000s · 1995 1990s · 1985 1980s · 1975 1970s · 1965 1960s · 1955 1950s · 1945 1940s · 1930 Before 1940 |
| pmiRate | data-pmi-rate | PMI rate / yr(in context) | 0.5% | 0 – 2 |
Mortgage Payoff Calculatormortgage-payoff-calculator · 4
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| balance | data-balance | Current loan balance | $300,000 | 10,000 – 3,000,000 |
| rate | data-rate | Interest rate (APR) | 6.5% | 0 – 15 |
| years | data-years | Years left on loan | 28 | 1 – 40 |
| extra | data-extra | Extra monthly payment | $200 | 0 – 5,000 |
Refinance Calculatorrefinance-calculator · 6
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| balance | data-balance | Current loan balance | $320,000 | 10,000 – 3,000,000 |
| curRate | data-cur-rate | Current interest rate | 7.25% | 0 – 15 |
| curYearsLeft | data-cur-years-left | Years left on current loan | 27 | 1 – 40 |
| newRate | data-new-rate | New interest rate | 6% | 0 – 15 |
| newTerm | data-new-term | New loan term (years) | 30 | 5 – 40 |
| closing | data-closing | Closing costs | $6,000 | 0 – 60,000 |
Rent vs Buy Calculatorrent-vs-buy-calculator · 18
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| mode | data-mode | Detail level | 0 | 0 Simple · 1 Detailed |
| years | data-years | How long you'll stay | 7 | 1 – 30 |
| homePrice | data-home-price | Home price | $400,000 | 50,000 – 1,500,000 |
| rent | data-rent | Monthly rent | $2,400 | 300 – 15,000 |
| downPercent | data-down-percent | Down payment | 20% | 0 – 100 |
| rate | data-rate | Mortgage rate (APR) | 6.5% | 1 – 12 |
| yearBuilt | data-year-built | Year built | 1,985 | 2022 2020 or newer · 2015 2010s · 2005 2000s · 1995 1990s · 1985 1980s · 1975 1970s · 1965 1960s · 1955 1950s · 1945 1940s · 1930 Before 1940 |
| termYears | data-term-years | Loan term(in context) | 30 | 30 30 yr · 20 20 yr · 15 15 yr |
| homeGrowth | data-home-growth | Home appreciation / yr(in context) | 4% | -5 – 12 |
| rentGrowth | data-rent-growth | Rent increase / yr(in context) | 3% | 0 – 10 |
| investReturn | data-invest-return | Investment return / yr(in context) | 7% | 0 – 12 |
| propTaxPct | data-prop-tax-pct | Property tax / yr(in context) | 0.89% | 0 – 4 |
| maintPct | data-maint-pct | Maintenance / yr(in context)(follows another field) | 1% | 0 – 4 |
| insuranceYearly | data-insurance-yearly | Home insurance / yr(in context)(follows another field) | $1,900 | 0 – 8,000 |
| pmiRatePct | data-pmi-rate-pct | PMI / yr(in context) | 0.5% | 0 – 2 |
| hoaMonthly | data-hoa-monthly | HOA / month(in context) | $0 | 0 – 1,500 |
| buyClosePct | data-buy-close-pct | Buying costs(in context) | 2% | 0 – 6 |
| sellClosePct | data-sell-close-pct | Selling costs(in context) | 6% | 0 – 10 |
How Much House Can I Affordhow-much-house-can-i-afford · 7
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| income | data-income | Annual household income | $90,000 | 20,000 – 500,000 |
| debts | data-debts | Monthly debt payments | $500 | 0 – 5,000 |
| down | data-down | Down payment | $40,000 | 0 – 300,000 |
| rate | data-rate | Mortgage rate (APR) | 6.5% | 1 – 12 |
| termYears | data-term-years | Loan term | 30 | 30 30 yr · 15 15 yr |
| yearBuilt | data-year-built | Year built | 1,985 | 2022 2020 or newer · 2015 2010s · 2005 2000s · 1995 1990s · 1985 1980s · 1975 1970s · 1965 1960s · 1955 1950s · 1945 1940s · 1930 Before 1940 |
| taxRate | data-tax-rate | Property tax rate | 0.89% | 0 – 3 |
Debt-to-Income Calculatordebt-to-income-calculator · 6
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| income | data-income | Gross monthly income | $6,000 | 0 – 100,000 |
| housing | data-housing | Rent or mortgage payment | $1,600 | 0 – 30,000 |
| auto | data-auto | Car / auto payments | $400 | 0 – 10,000 |
| student | data-student | Student loan payments | $250 | 0 – 10,000 |
| creditCards | data-credit-cards | Credit card minimums | $150 | 0 – 10,000 |
| other | data-other | Other loan payments | $0 | 0 – 10,000 |
Rent Affordability Calculatorrent-affordability-calculator · 4
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| income | data-income | Gross income per year | $60,000 | 0 – 500,000 |
| debts | data-debts | Other monthly debt payments | $0 | 0 – 10,000 |
| pct | data-pct | Share of income on rent | 30% | 15 – 50 |
| utilities | data-utilities | Utilities you pay on top of rent | $0 | 0 – 2,000 |
Income & Taxes
Take-Home Paycheck Calculatortake-home-paycheck-calculator · 10
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| salary | data-salary | Annual salary | $75,000 | 15,000 – 500,000 |
| status | data-status | Filing status | 0 | 0 Single · 1 Married (joint) · 2 Head of household · 3 Married (separate) |
| k401 | data-k401 | 401(k) contribution | 5% | 0 – 30 |
| k401type | data-k401type | Contribution type(in context) | 0 | 0 Traditional (pre-tax) · 1 Roth (after-tax) |
| k401age | data-k401age | Your age this year(in context) | 0 | 0 Under 50 · 1 50–59 or 64+ · 2 60–63 |
| state | data-state | Where you work | 0 | 0 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 |
| locality | data-locality | City, township, county or borough income tax(in context) | 0 | 0 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) |
| schoolDistrict | data-school-district | School district (where you live)(in context) | 0 | 0 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) |
| stateRate | data-state-rate | State income tax(in context) | 5% | 0 – 13 |
| freq | data-freq | Pay schedule | 26 | 52 Weekly · 26 Every 2 weeks · 24 Twice a month · 12 Monthly |
Budget Calculatorbudget-calculator · 1
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| income | data-income | Monthly take-home pay | $4,500 | 500 – 50,000 |
Salary to Hourly Calculatorsalary-to-hourly-calculator · 6
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| mode | data-mode | What do you want to convert? | 0 | 0 💵 Salary → hourly · 1 ⏱️ Hourly → salary |
| salary | data-salary | Yearly salary(in context) | $60,000 | 0 – 500,000 |
| hourly | data-hourly | Hourly rate(in context) | $25 | 0 – 500 |
| hoursPerWeek | data-hours-per-week | Hours per week | 40 | 1 – 100 |
| otMultiplier | data-ot-multiplier | Hours over 40 are paid at(in context) | 1.5 | 1.5 1.5× time-and-a-half · 2 2× double time · 1 1× no premium |
| weeksPerYear | data-weeks-per-year | Paid weeks per year | 52 | 1 – 52 |
Loans & Debt
Auto Loan Calculatorauto-loan-calculator · 7
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| price | data-price | Vehicle price | $35,000 | 5,000 – 120,000 |
| downPayment | data-down-payment | Down payment | $3,500 | 0 – 40,000 |
| tradeIn | data-trade-in | Trade-in value | $0 | 0 – 40,000 |
| rate | data-rate | Interest rate (APR) | 7.5% | 0 – 20 |
| termMonths | data-term-months | Loan term | 60 | 36 36 mo · 48 48 mo · 60 60 mo · 72 72 mo · 84 84 mo |
| salesTax | data-sales-tax | Sales tax | 6% | 0 – 12 |
| extraMonthly | data-extra-monthly | Extra principal / month | $0 | 0 – 1,000 |
Car Affordability Calculatorcar-affordability-calculator · 6
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| takeHome | data-take-home | Monthly take-home pay | $4,200 | 1,000 – 40,000 |
| payPct | data-pay-pct | Share of pay for the car | 10% | 5 – 20 |
| operating | data-operating | Insurance, gas & upkeep | $296 | 0 – 3,000 |
| down | data-down | Down payment + trade-in | $4,000 | 0 – 60,000 |
| rate | data-rate | Interest rate (APR) | 7.5% | 0 – 20 |
| termMonths | data-term-months | Loan term | 48 | 36 36 mo · 48 48 mo · 60 60 mo · 72 72 mo |
Personal Loan Calculatorpersonal-loan-calculator · 3
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| amount | data-amount | Loan amount | $15,000 | 500 – 100,000 |
| rate | data-rate | Interest rate (APR) | 12% | 1 – 36 |
| termMonths | data-term-months | Loan term | 36 | 12 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
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| balance | data-balance | Card balance | $6,000 | 0 – 50,000 |
| apr | data-apr | Interest rate (APR) | 22% | 0 – 35 |
| mode | data-mode | How will you pay it? | 0 | 0 💪 A fixed amount · 1 🐌 Minimum only |
| payment | data-payment | Monthly payment(in context)(follows another field) | $250 | 0 – 3,000 |
Debt Snowball vs. Avalanche Calculatordebt-snowball-calculator · 21
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| debts | data-debts | How many debts? | 3 | 2 2 · 3 3 · 4 4 · 5 5 · 6 6 |
| bal1 | data-bal1 | Debt 1 · balance(in context) | $6,200 | 0 – 50,000 |
| apr1 | data-apr1 | Debt 1 · rate (APR)(in context) | 24.99% | 0 – 36 |
| min1 | data-min1 | Debt 1 · minimum payment(in context) | $155 | 0 – 2,000 |
| bal2 | data-bal2 | Debt 2 · balance(in context) | $2,100 | 0 – 50,000 |
| apr2 | data-apr2 | Debt 2 · rate (APR)(in context) | 6.5% | 0 – 36 |
| min2 | data-min2 | Debt 2 · minimum payment(in context) | $95 | 0 – 2,000 |
| bal3 | data-bal3 | Debt 3 · balance(in context) | $11,500 | 0 – 50,000 |
| apr3 | data-apr3 | Debt 3 · rate (APR)(in context) | 18.9% | 0 – 36 |
| min3 | data-min3 | Debt 3 · minimum payment(in context) | $260 | 0 – 2,000 |
| bal4 | data-bal4 | Debt 4 · balance(in context) | $3,400 | 0 – 50,000 |
| apr4 | data-apr4 | Debt 4 · rate (APR)(in context) | 15.9% | 0 – 36 |
| min4 | data-min4 | Debt 4 · minimum payment(in context) | $90 | 0 – 2,000 |
| bal5 | data-bal5 | Debt 5 · balance(in context) | $900 | 0 – 50,000 |
| apr5 | data-apr5 | Debt 5 · rate (APR)(in context) | 0% | 0 – 36 |
| min5 | data-min5 | Debt 5 · minimum payment(in context) | $75 | 0 – 2,000 |
| bal6 | data-bal6 | Debt 6 · balance(in context) | $17,000 | 0 – 50,000 |
| apr6 | data-apr6 | Debt 6 · rate (APR)(in context) | 7.5% | 0 – 36 |
| min6 | data-min6 | Debt 6 · minimum payment(in context) | $190 | 0 – 2,000 |
| extra | data-extra | Extra payment / month | $200 | 0 – 3,000 |
| plan | data-plan | Which order? | 0 | 0 🏔 Avalanche · 1 ⛄ Snowball |
Saving & Investing
Compound Interest Calculatorcompound-interest-calculator · 7
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| mode | data-mode | What do you want to figure out? | 0 | 0 💰 What I'll have · 1 🎯 Time to reach a goal |
| principal | data-principal | Starting amount | $10,000 | 0 – 200,000 |
| monthly | data-monthly | Monthly contribution | $500 | 0 – 5,000 |
| rate | data-rate | Annual return | 7% | 0 – 15 |
| years | data-years | Years(in context) | 25 | 1 – 50 |
| target | data-target | Goal amount(in context) | $1,000,000 | 5,000 – 2,000,000 |
| perYear | data-per-year | Compounding | 12 | 12 Monthly · 4 Quarterly · 1 Yearly |
Net Worth Calculatornet-worth-calculator · 11
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| cash | data-cash | Cash & savings | $12,000 | 0 – 1,000,000 |
| investments | data-investments | Investments (brokerage) | $20,000 | 0 – 5,000,000 |
| retirement | data-retirement | Retirement (401k / IRA) | $45,000 | 0 – 5,000,000 |
| home | data-home | Home value | $320,000 | 0 – 5,000,000 |
| vehicles | data-vehicles | Vehicles | $18,000 | 0 – 500,000 |
| otherAssets | data-other-assets | Other assets | $0 | 0 – 2,000,000 |
| mortgage | data-mortgage | Mortgage balance | $250,000 | 0 – 5,000,000 |
| autoLoans | data-auto-loans | Auto loans | $9,000 | 0 – 500,000 |
| studentLoans | data-student-loans | Student loans | $14,000 | 0 – 500,000 |
| creditCards | data-credit-cards | Credit card debt | $3,000 | 0 – 200,000 |
| otherDebts | data-other-debts | Other debts | $0 | 0 – 1,000,000 |
Retirement Calculatorretirement-calculator · 8
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| age | data-age | Your age now | 30 | 18 – 70 |
| retireAge | data-retire-age | Retirement age | 65 | 40 – 75 |
| current | data-current | Saved so far | $25,000 | 0 – 2,000,000 |
| monthly | data-monthly | Monthly contribution | $600 | 0 – 5,000 |
| rate | data-rate | Annual return | 7% | 1 – 12 |
| withdrawRate | data-withdraw-rate | Yearly withdrawal rate | 4 | 4 4% · 25× · 3.5 3.5% · 29× · 3 3% · 33× |
| ssMonthly | data-ss-monthly | Social Security at 67 (monthly) | $2,600 | 0 – 5,000 |
| ssAge | data-ss-age | Claim Social Security at(in context) | 67 | 62 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
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| age | data-age | Your age now | 30 | 18 – 70 |
| retireAge | data-retire-age | Retirement age | 65 | 40 – 75 |
| salary | data-salary | Annual salary | $65,000 | 10,000 – 500,000 |
| balance | data-balance | Current 401(k) balance | $25,000 | 0 – 3,000,000 |
| contribPct | data-contrib-pct | You contribute | 6% | 0 – 40 |
| matchRate | data-match-rate | Employer matches | 50% | 0 – 100 |
| matchLimitPct | data-match-limit-pct | Up to this % of pay | 6% | 0 – 15 |
| rate | data-rate | Annual return | 7% | 1 – 12 |
| raise | data-raise | Annual raise | 2% | 0 – 8 |
FIRE Calculatorfire-calculator · 8
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| mode | data-mode | What do you want to know? | 0 | 0 🔥 My FIRE date · 1 🏖️ Coast FIRE |
| age | data-age | Your age now | 30 | 18 – 70 |
| retireAge | data-retire-age | Age you'd retire anyway(in context) | 65 | 40 – 75 |
| income | data-income | Take-home pay / year | $70,000 | 0 – 500,000 |
| spending | data-spending | You spend / year | $45,000 | 0 – 300,000 |
| current | data-current | Invested so far | $30,000 | 0 – 3,000,000 |
| rate | data-rate | Annual return (after inflation) | 7% | 1 – 10 |
| withdrawal | data-withdrawal | Withdrawal rate | 4% | 2 – 6 |
Roth vs Traditional Calculatorroth-vs-traditional-calculator · 7
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| account | data-account | Which account? | 0 | 0 🏦 IRA · 1 🏢 401(k) / 403(b) |
| age | data-age | Your age this year | 40 | 40 Under 50 · 55 50–59 or 64+ · 61 60–63 |
| contribution | data-contribution | Yearly contribution(follows another field) | $7,500 | 0 – 35,750 |
| years | data-years | Years until retirement | 30 | 1 – 50 |
| rate | data-rate | Annual return | 7% | 1 – 12 |
| taxNow | data-tax-now | Your tax rate now | 22% | 0 – 50 |
| taxRetire | data-tax-retire | Tax rate in retirement | 22% | 0 – 50 |
Roth IRA Calculatorroth-ira-calculator · 5
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| age | data-age | Your age now | 30 | 18 – 70 |
| retireAge | data-retire-age | Retirement age | 65 | 40 – 75 |
| balance | data-balance | Current Roth IRA balance | $8,000 | 0 – 2,000,000 |
| annual | data-annual | Yearly contribution | $7,500 | 0 – 8,600 |
| rate | data-rate | Annual return | 7% | 1 – 12 |
401(k) Match Calculator401k-match-calculator · 4
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| salary | data-salary | Your yearly salary | $60,000 | 0 – 500,000 |
| contribPct | data-contrib-pct | You contribute | 4% | 0 – 50 |
| matchRate | data-match-rate | Employer matches | 50% | 0 – 100 |
| matchLimitPct | data-match-limit-pct | Up to this % of your pay | 6% | 0 – 15 |
Savings Goal Calculatorsavings-goal-calculator · 4
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| goal | data-goal | Savings goal | $30,000 | 500 – 500,000 |
| current | data-current | Already saved | $5,000 | 0 – 200,000 |
| years | data-years | Years to save | 5 | 1 – 40 |
| apy | data-apy | Interest rate (APY) | 4% | 0 – 12 |
CD Calculatorcd-calculator · 3
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| deposit | data-deposit | Deposit amount | $10,000 | 100 – 1,000,000 |
| apy | data-apy | Interest rate (APY) | 4.25% | 0 – 10 |
| termMonths | data-term-months | Term | 12 | 3 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
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| expenses | data-expenses | Monthly essential expenses | $3,500 | 500 – 20,000 |
| months | data-months | Months of cushion | 6 | 3 3 months · 6 6 months · 12 12 months |
| saved | data-saved | Already saved | $4,000 | 0 – 100,000 |
| monthlySave | data-monthly-save | You can save / month | $400 | 0 – 5,000 |
Inflation Calculatorinflation-calculator · 3
| Parameter | data-* | What it is | Default | Accepts |
|---|---|---|---|---|
| amount | data-amount | Amount today | $10,000 | 0 – 5,000,000 |
| years | data-years | Years from now | 20 | 1 – 60 |
| rate | data-rate | Annual inflation | 3% | 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 | |
|---|---|
| Cookies | None. Not by the widget, not by the loader, not by the page inside the frame. |
| Third-party requests | None. 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 storage | One 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' data | Stays 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 DOM | The 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. |
| Weight | The 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 →