# Measured Bid developer docs --- How to add the Measured Bid widget to a website, track it, and move its leads. Each section below is also a page under https://measuredbid.com/docs. --- # Measured Bid developer docs How to put the Measured Bid price widget on a website, track it, and send its leads where you need them. Written for web developers, people setting up a site builder, and AI assistants. Source: https://measuredbid.com/docs ## Add the widget in three steps 1. **Copy the code.** In Measured Bid, open Widgets, pick the widget and open Install. Copy the Website code. It already has the widget ID in it. 2. **List the website.** In the widget's settings, under Websites, add each address the widget will appear on, one per line, like `https://example.com`. The widget stays blank anywhere else. 3. **Paste it.** Put the code where the price form should appear, in an HTML or code block. It sizes itself. [Where to paste it on each platform](https://measuredbid.com/docs/embed#platforms). > **No developer? Use the link.** Every widget also has a homeowner link, like `https://measuredbid.com/quote/your-widget-id`. It works anywhere without code: a button on your site, a text message, your Google Business Profile. [More on links](https://measuredbid.com/docs/embed#link). ## How it works - The widget is a page on measuredbid.com shown in an iframe on your site. - A homeowner types an address, confirms the house, answers a few questions and sees a price range built from the contractor's rates. - When they send the form, the lead is saved in the Measured Bid dashboard and sent to the contractor's email, texts, webhook or CRM, whichever are set up. - Prices, questions, colors and service area come from the dashboard. Changes show on your site within a minute, with no need to paste the code again. ## What's in these docs | Page | Use it to | | --- | --- | | [Embed the widget](https://measuredbid.com/docs/embed) | Paste the code on any site or site builder, allow the site, use a link instead, test it. | | [URL parameters](https://measuredbid.com/docs/url-parameters) | Prefill the address, open on one trade, carry ad tracking into the lead. | | [Events and tracking](https://measuredbid.com/docs/events) | Track widget steps in Google Tag Manager, GA4 or your own code. | | [Webhooks](https://measuredbid.com/docs/webhooks) | Receive each new lead as JSON, and receive stage changes for leads you sent in. | | [Sending leads in](https://measuredbid.com/docs/lead-intake) | Post leads from other forms or a CRM into Measured Bid, and update their stage. | | [Troubleshooting](https://measuredbid.com/docs/troubleshooting) | Fix a blank widget, a cut-off frame, missing prices or missing leads. | ## Is there an API? There is no public API for prices. Homeowners get prices through the widget. For lead data there are two webhooks Measured Bid sends and one URL it receives: [new leads and lead updates out](https://measuredbid.com/docs/webhooks), and [form leads and stage updates in](https://measuredbid.com/docs/lead-intake). ## For AI assistants Every page has a plain Markdown version: add `.md` to its address, like [/docs/embed.md](https://measuredbid.com/docs/embed.md). All pages in one file: [/llms-full.txt](https://measuredbid.com/llms-full.txt). You can hand an assistant a prompt like this: Prompt: ```text Read https://measuredbid.com/llms-full.txt. Then add my Measured Bid widget (ID: your-widget-id) to my website's quote page, and tell me which website addresses to add under Websites in the widget's settings. ``` Questions: [support@measuredbid.com](mailto:support@measuredbid.com). --- # Add the widget to a website Paste one block of code where the price form should appear. It works on any site that lets you add custom HTML, once the site is listed in the widget's settings. Source: https://measuredbid.com/docs/embed ## The code Copy it from Install in the dashboard, where the widget ID is already filled in. It looks like this: Website code: ```html ``` - Loads the widget in an iframe, 100% wide, 640px tall until it knows its real height. - Resizes the iframe to fit each step, so there's no inner scrollbar. - Copies ad tracking from the page's address into the lead: `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content` and `gclid`, `gbraid`, `wbraid`, `fbclid`, `msclkid`, plus the page address as `ref`. - Scrolls back to the top of the widget when a step changes and the top is off screen. - Pushes an `iq_step` event to `window.dataLayer` when Google Tag Manager is on the page. See [events](https://measuredbid.com/docs/events). ## Allow your website The widget only loads on websites listed in its settings. Browsers enforce this with the `frame-ancestors` security header, and an unlisted site shows a blank box. - Open Widgets, pick the widget, and find Websites. Add one address per line. - List every version visitors use: `https://example.com` and `https://www.example.com` are different sites. - `https://*.example.com` covers every subdomain, but not `example.com` itself. - Addresses must use https. The one exception is `http://localhost` for testing on your own computer. - Up to 20 addresses. Changes apply within a minute. ## Where to paste it | Platform | Where | Notes | | --- | --- | --- | | Any HTML site | Paste it in the page's HTML where the form should appear. | Nothing else needed. | | WordPress | Install the [Measured Bid plugin](https://measuredbid.com/integrations/wordpress) and use the `[instant_quote]` shortcode, or paste the code in a Custom HTML block. | The plugin is easiest. A Custom HTML block needs an account that is allowed to add scripts. | | Squarespace | Add a Code block and paste the code. | Check the live page, not the editor preview. | | Webflow | Add a Code Embed element and paste the code. | Publish the site to test it. | | Shopify | Online Store, Themes, Customize, then add a Custom Liquid section and paste the code. | | | HighLevel sites and funnels | Add a Custom JS/HTML element and paste the code. | | | Wix | Add, Embed Code, Embed HTML, then paste the code. | Wix runs pasted code inside a frame of its own, served from a `filesusr.com` address. Add `https://*.filesusr.com` to Websites along with your domain, and set the element about 900px tall. | | GoDaddy Website Builder | Add a section, pick HTML, then paste the code. | GoDaddy also runs it inside a frame of its own. If the box stays blank, find that frame's address ([how](https://measuredbid.com/docs/troubleshooting#blank)) and add it to Websites. Set a tall height. | | React, Next.js, Vue | Render the iframe yourself. | Frameworks don't run script tags inside injected HTML. [Use the component below](https://measuredbid.com/docs/embed#react). | ## React and other frameworks This component does what the pasted script does: builds the widget address with tracking, resizes the frame, and drops the loading height after the first step. Replace `your-widget-id`. For Vue or Svelte, keep the same steps. MeasuredBidWidget.jsx: ```js "use client"; import { useEffect, useRef } from "react"; const APP = "https://measuredbid.com"; const WIDGET = "your-widget-id"; const PASS = ["utm_source","utm_medium","utm_campaign","utm_term","utm_content","gclid","gbraid","wbraid","fbclid","msclkid"]; export function MeasuredBidWidget({ title = "Price estimate" }) { const ref = useRef(null); useEffect(() => { const frame = ref.current; // Carry ad tracking from this page into the lead, plus the page itself. const page = new URLSearchParams(window.location.search); const params = new URLSearchParams(); PASS.forEach((key) => page.get(key) && params.set(key, page.get(key))); params.set("ref", window.location.href); frame.src = `${APP}/quote/${WIDGET}?${params}`; function onMessage(e) { if (e.origin !== APP || e.source !== frame.contentWindow || !e.data) return; const { type, height, step } = e.data; if (type === "instant-quote:height" && Number.isFinite(height) && height > 0 && height <= 20000) { frame.style.height = `${Math.ceil(height)}px`; } if (type === "instant-quote:step" && step !== "address") frame.style.minHeight = "0"; } window.addEventListener("message", onMessage); return () => window.removeEventListener("message", onMessage); }, []); return