Embed the calculator
Script tag
The usual way. Two lines, and the height takes care of itself.
<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.
<!-- 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-stateFull state name, e.g. "New Jersey". Sets the property tax rate.
data-priceHome price in dollars, no separators.
data-rateAnnual interest rate as a percent, e.g. 6.5.
iframe
For platforms that strip script tags — most hosted CMSs, many newsletter tools.
<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.
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
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.
<!-- 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.