Embed the calculator

Free to put on any site — a brokerage, a blog, a housing nonprofit, a course page. No signup, no key, no tracking of your visitors. The frame sizes itself to its content, and every embed carries a single attribution line back here.

Script tag

The usual way. Two lines, and the height takes care of itself.

HTML
<div data-usmc-calculator></div>
<script src="https://www.usmortgagecalc.com/embed.js" async></script>

Every element with data-usmc-calculator becomes a calculator. The loader is under 2KB, has no dependencies, and is safe to include more than once.

Presetting the fields

A regional site should not open on a blank state field.

HTML
<!-- Opens on Texas with a $450,000 price already filled in -->
<div data-usmc-calculator data-state="Texas" data-price="450000" data-rate="6.5"></div>
<script src="https://www.usmortgagecalc.com/embed.js" async></script>
data-state

Full state name, e.g. "New Jersey". Sets the property tax rate.

data-price

Home price in dollars, no separators.

data-rate

Annual interest rate as a percent, e.g. 6.5.

iframe

For platforms that strip script tags — most hosted CMSs, many newsletter tools.

HTML
<iframe
  src="https://www.usmortgagecalc.com/embed/calculator"
  title="US Mortgage Calculator"
  width="100%"
  height="720"
  style="border:0"
  loading="lazy"
></iframe>

A fixed height works fine. The calculator grows when results appear, so allow around 1,100px if you would rather never show an inner scrollbar, or use the script version and let it resize itself.

React

Listening for the height message directly, no loader script.

MortgageCalculator.jsx
import { useEffect, useRef, useState } from "react";

export function MortgageCalculator({ state, price }) {
  const frame = useRef(null);
  const [height, setHeight] = useState(720);

  useEffect(() => {
    const onMessage = (event) => {
      if (event.origin !== "https://www.usmortgagecalc.com") return;
      if (event.data?.type !== "usmc:height") return;
      if (event.source !== frame.current?.contentWindow) return;
      setHeight(Math.ceil(event.data.height));
    };

    window.addEventListener("message", onMessage);
    return () => window.removeEventListener("message", onMessage);
  }, []);

  const params = new URLSearchParams({ utm_source: "embed" });
  if (state) params.set("state", state);
  if (price) params.set("price", String(price));

  return (
    <iframe
      ref={frame}
      src={`https://www.usmortgagecalc.com/embed/calculator?${params}`}
      title="US Mortgage Calculator"
      loading="lazy"
      style={{ width: "100%", height, border: 0, display: "block" }}
    />
  );
}

Next.js

app/tools/mortgage/page.tsx
// app/tools/mortgage/page.tsx
import Script from "next/script";

export const metadata = {
  title: "Mortgage calculator",
};

export default function Page() {
  return (
    <main>
      <h1>Work out your monthly payment</h1>

      <div data-usmc-calculator data-state="Ohio" />
      <Script src="https://www.usmortgagecalc.com/embed.js" strategy="lazyOnload" />
    </main>
  );
}

// The loader mounts on DOMContentLoaded and exposes window.usmcEmbed.mount()
// for client-side route changes, so call it from a useEffect if the widget
// appears on a route the user navigates to rather than lands on.

WordPress

Three routes, depending on what your theme allows.

WordPress
<!-- Block editor: add a "Custom HTML" block and paste this -->
<div data-usmc-calculator></div>
<script src="https://www.usmortgagecalc.com/embed.js" async></script>


<!-- Classic editor or a theme that strips <script>: use the iframe instead -->
<iframe
  src="https://www.usmortgagecalc.com/embed/calculator"
  title="US Mortgage Calculator"
  width="100%"
  height="720"
  style="border:0"
  loading="lazy"
></iframe>


<!-- Or register a shortcode in functions.php -->
<?php
add_shortcode( 'mortgage_calculator', function ( $atts ) {
    $atts = shortcode_atts( array( 'state' => '', 'price' => '' ), $atts );
    $query = http_build_query( array_filter( array(
        'state'      => $atts['state'],
        'price'      => $atts['price'],
        'utm_source' => 'embed',
    ) ) );

    return sprintf(
        '<iframe src="%s" title="US Mortgage Calculator" width="100%%" height="720" style="border:0" loading="lazy"></iframe>',
        esc_url( 'https://www.usmortgagecalc.com/embed/calculator?' . $query )
    );
} );
?>

<!-- Then use [mortgage_calculator state="Florida"] in any post -->

What the widget does and does not do

  • It stores nothing. No cookies are set in the frame, nothing your visitors type is transmitted, and the calculation runs in their browser.
  • It carries no ads. The embedded view is deliberately free of them.
  • It keeps one attribution link. A single line under the calculator crediting this site. That link is the entire price of the widget, and removing it is the one thing the licence does not permit.
  • It cannot navigate your page. The frame is sandboxed without top-level navigation, and the only message it sends out is its own height.

Rather build your own?

The widget is a convenience, not the only route. The REST API gives you the same calculations as JSON so you can render them in your own design, and the datasets are downloadable under CC BY 4.0 if you only need the numbers.