Documentation
KarbonKit integration guide
Everything needed to put a KarbonKit widget on a web page: the snippet for each widget, every setting with its type, default and allowed values, how sizing works, and working examples for plain HTML, React, Next.js and WordPress. If an attribute, parameter or setting is not on this page, KarbonKit does not support it. A plainer overview is at /docs/, and this page is also available as Markdown at /docs/integration.md.
For AI coding assistants
- Snippets: each widget’s section under Widgets has a complete one. This page as Markdown: https://www.karbonkit.com/docs/integration.md. All KarbonKit docs in one file: https://www.karbonkit.com/llms-full.txt.
- Config ID: the site owner gets one per widget from the dashboard after signing up at https://www.karbonkit.com/signup. If you have not been given one, leave
YOUR_CONFIG_IDin place and tell the user where to get it. Never invent one. - Use the script tag unless the platform strips scripts or the site’s Content Security Policy forbids them; then use that widget’s plain iframe exactly as given.
- Do not self-host, copy or bundle
embed.jsor any widget code: load it fromhttps://widgets.karbonkit.com/embed.js. Do not add anintegrity(SRI) hash to that tag: the file is updated in place at the same URL, so a pinned hash would block it after the next update. - Do not guess option names,
data-attributes, URL parameters or widget types. The loader reads onlydata-karbonkitanddata-config-id, and settings exist only in the dashboard. If the user wants a colour, company name or other setting, tell them which dashboard setting it is (the tables below name each one). A widget that is already embedded is changed from the dashboard (Your saved widgets, then Edit), not in the snippet. - Do not change an iframe’s
type,allowlist or the host, or call KarbonKit’s API from the page. There is no JavaScript API; the only message a widget sends iskarbonkit:resize.
Before you start: the config ID
Every widget is identified by a config ID. Snippets on this page use the placeholder YOUR_CONFIG_ID: replace it with the ID the dashboard gives you before you publish.
- Where it comes from. Create a free account at https://www.karbonkit.com/signup (or sign in at https://www.karbonkit.com/dashboard), configure a widget on its tab, and copy its snippet. Copying saves the widget and puts its config ID in the snippet.
- One per widget, not per site. Each widget you configure gets its own ID, and the widget type and settings are saved against it. The same ID works on any number of pages and sites; nothing ties it to a domain. Two different widgets need two IDs.
- What it looks like. 22 characters of letters, digits,
-and_. The loader rejects anything outside A–Z, a–z, 0–9, _ and -, 8 to 64 characters. - It is not a secret. It sits in your page’s HTML, where anyone can read it. It carries no account access: it only selects which saved widget to show.
- Do not make one up. With an ID the dashboard did not issue, the savings calculator and AR visualiser show an error instead of the widget, and the other widgets show their default settings.
Two ways to embed
Script tag (recommended)
The same two lines work for every widget. The widget type and settings come from the config ID.
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div>
What https://widgets.karbonkit.com/embed.js does:
- Finds every element with both
data-karbonkitanddata-config-id, and replaces its contents with an iframe ofhttps://widgets.karbonkit.com/widget-embed?cid=<config id>&parentOrigin=<your origin>. It reads no other attributes. - The iframe is
width:100%, starts at 600px high, then takes the height the widget reports (61–4999px), so it never needs a scrollbar. It loads lazily (loading="lazy"). - It delegates every permission any widget needs (
allow="camera; microphone; xr-spatial-tracking; fullscreen; accelerometer; gyroscope; magnetometer; clipboard-write") and sandboxes the iframe (sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"). The browser still asks the visitor before a widget uses the camera or microphone. - It watches the page for containers added later, so it works with single-page apps, site builders and tag managers. Include it once per page; one copy serves every widget on it.
- It makes no network request of its own, sets no global variables and has no JavaScript API. Nothing on your page needs to talk to it.
- A missing or malformed
data-config-idshows “Widget misconfigured: missing or invalid config id.” in the container. - Older snippets,
<div data-heatpump-widget="YOUR_CONFIG_ID"></div>, still work: the value is read as the config ID. The olderdata-widget-type,data-user-tier,data-allowed-siteanddata-primary-colorattributes are ignored.
Plain iframe
Use this where the platform strips <script> tags or your Content Security Policy does not allow a third-party script. Each widget has its own type, height and allow list (see Widgets). The iframe stays at the height you set unless you add the resize listener. Copy the allow list exactly: a missing permission only fails when the visitor taps the button that needs it.
Every URL parameter other than type and cid is ignored for branding and text, and the type saved against a config ID wins over type. The parameters older snippets carry are listed at /docs/#url-parameters; do not add them to new embeds.
Widgets
Seven widgets, each with a complete snippet. The dashboard adds an optional credit link after each one, outside the widget; you can delete it. Every widget also shows a small “Powered by KarbonKit” link inside it.
Savings calculator
Sizes a heat pump, solar PV and a battery for a UK home from its postcode, its EPC record or the household's bills, then estimates costs, savings and carbon. Live demo: /tools/savings-calculator/.
| Fact | Value |
|---|---|
| Widget type | lct-calculator |
| Config ID | Required. Without one the widget shows a "Sign up to embed this widget" message instead; with an ID the dashboard did not issue, an error |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 900px (the dashboard's value). On mobile it can run past 1500px, so use the script tag or the resize listener |
| Iframe allow | clipboard-write |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=lct-calculator&cid=YOUR_CONFIG_ID" width="100%" height="900" frameborder="0" style="border: none; border-radius: 8px;" allow="clipboard-write" ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | Buttons, selected options and the footer link |
| Company name | company_name | string | (empty) | Up to 80 characters | Shown in the calculator header ("KarbonKit" when empty) |
| Technologies | available_lcts | array of strings | ["heatPump", "solarPV", "battery"] | Any non-empty subset of heatPump, solarPV, battery. An empty list shows all three | |
| Show nearby installers after results | show_installer_finder | boolean | true | true or false | |
| Caveat banner | caveat | string | (empty) | Up to 240 characters, shown as an amber banner at the top | |
| Enquiry collection (Leads tab) | lead_capture | object | off | See "Enquiry collection settings" below |
AR heat pump visualiser
Places a true-size heat pump or hot water cylinder in the visitor's own space through their phone camera (WebXR on Android Chrome, AR Quick Look on iOS Safari). Desktop browsers get a 3D viewer. Live demo: /tools/heat-pump-visualiser/.
| Fact | Value |
|---|---|
| Widget type | heat-pump-ar |
| Config ID | Required. Without one the widget shows a "Sign up to embed this widget" message instead; with an ID the dashboard did not issue, an error |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 500px (the dashboard's value) |
| Iframe allow | camera; xr-spatial-tracking; accelerometer; gyroscope; magnetometer; fullscreen |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=heat-pump-ar&cid=YOUR_CONFIG_ID" width="100%" height="500" frameborder="0" style="border: none; border-radius: 8px;" allow="camera; xr-spatial-tracking; accelerometer; gyroscope; magnetometer; fullscreen" allowfullscreen ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | The AR button and badges |
| Background colour | secondary_color | hex colour | #fafaf9 | #RRGGBB (six hex digits). Anything else is saved as #fafaf9 | |
| Model that loads first | model_id | integer | 7 | One of 7 (Compact 7 kW heat pump, the default), 16 (8.5 kW heat pump), 17 (Low-profile 8 kW heat pump), 11 (Large 12 kW heat pump), 10 (Hot water cylinder), 12 (Wall-mounted heat pump) |
Sound simulator
Plays a real heat pump recording and measures its level in decibels with the phone's microphone, so a visitor can hear it from different distances. Live demo: /tools/sound-simulator/.
| Fact | Value |
|---|---|
| Widget type | sound-simulator |
| Config ID | Optional, but use one: without it the widget has default colours and no company name, and nothing can be set for it in the dashboard |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 700px (the dashboard's value) |
| Iframe allow | microphone |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=sound-simulator&cid=YOUR_CONFIG_ID" width="100%" height="700" frameborder="0" style="border: none; border-radius: 8px;" allow="microphone" ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Company name | company_name | string | (empty) | Up to 80 characters | Shown as "Provided by …" |
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | Only the footer link; the widget keeps its own colours |
3D house tour
A 3D cutaway home with a complete heat pump system, solar panels and a home battery, and a 9-stop guided tour. Live demo: /tools/house-tour/.
| Fact | Value |
|---|---|
| Widget type | house-tour (older embeds may say system-diagram, which shows the same widget) |
| Config ID | Optional, but use one: without it the widget has default colours and no company name, and nothing can be set for it in the dashboard |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 660px (the dashboard's value) |
| Iframe allow | fullscreen |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=house-tour&cid=YOUR_CONFIG_ID" width="100%" height="660" frameborder="0" style="border: none; border-radius: 8px;" allow="fullscreen" allowfullscreen ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | Accents, tour buttons and the footer link |
| Company name | company_name | string | (empty) | Up to 80 characters | Shown as "Provided by …" |
Installer finder
Postcode search for nearby installers, from a directory built from public records, with a link to check each one on the MCS register. Live demo: /tools/installer-finder/.
| Fact | Value |
|---|---|
| Widget type | installer-finder |
| Config ID | Optional, but use one: without it the widget has default colours and no company name, and nothing can be set for it in the dashboard |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 700px (the dashboard's value) |
| Iframe allow | Nothing needed |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=installer-finder&cid=YOUR_CONFIG_ID" width="100%" height="700" frameborder="0" style="border: none; border-radius: 8px;" ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | Buttons, selected options and the footer link |
| Company name | company_name | string | (empty) | Up to 80 characters | Shown as "Provided by …" |
| Installer source | installer_source | string | directory | directory (the public directory), both (your list first, then the directory), curated (only your list; with no entries yet, the directory is shown) | |
| Your suggested installers | curated_installers | array of objects | [] | Up to 25. Each needs a name (80 characters); postcode, telephone, website (reduced to https://host), email, technologies (heat_pump, solar_pv, battery) and a note (160 characters) are optional. Shown first, labelled "Suggested by" you |
Grant eligibility finder
A postcode and four questions show which UK funding schemes a household may qualify for, each linked to its official page. Live demo: /tools/grant-finder/.
| Fact | Value |
|---|---|
| Widget type | grant-finder |
| Config ID | Optional, but use one: without it the widget has default colours and no company name, and nothing can be set for it in the dashboard |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 900px (the dashboard's value) |
| Iframe allow | Nothing needed |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=grant-finder&cid=YOUR_CONFIG_ID" width="100%" height="900" frameborder="0" style="border: none; border-radius: 8px;" ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | Buttons, selected options and the footer link |
| Company name | company_name | string | (empty) | Up to 80 characters | Shown as "Provided by …" |
| Link to the visitor's council | grant_finder.show_council_link | boolean | false | true or false | |
| Your local schemes | grant_finder.local_schemes | array of objects | [] | Up to 10. Each needs a name (100 characters), an https link and a date to stop showing it (YYYY-MM-DD, at most 3 years ahead). Provider (80), headline (100), summary (400) and council areas (up to 40; none means every visitor) are optional. Labelled "Added by" you |
Boiler escape plan
The carbon arithmetic of replacing a working gas boiler now versus waiting for it to fail, then a readiness plan with optional reminders. Live demo: /tools/boiler-escape-plan/.
| Fact | Value |
|---|---|
| Widget type | boiler-escape-plan |
| Config ID | Optional, but use one: without it the widget has default colours and no company name, and nothing can be set for it in the dashboard |
| Script tag height | Starts at 600px and follows the widget's content |
| Iframe height | 1000px (the dashboard's value). On mobile it can run past 1500px, so use the script tag or the resize listener |
| Iframe allow | Nothing needed |
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
<iframe src="https://widgets.karbonkit.com/widget-embed?type=boiler-escape-plan&cid=YOUR_CONFIG_ID" width="100%" height="1000" frameborder="0" style="border: none; border-radius: 8px;" ></iframe> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
Settings, chosen in the dashboard and saved against the config ID:
| Dashboard setting | Stored field | Type | Default | Allowed values | What it changes |
|---|---|---|---|---|---|
| Company name | company_name | string | (empty) | Up to 80 characters | Shown as "Provided by …" |
| Brand colour | primary_color | hex colour | #2d6a4f | #RRGGBB (six hex digits). Anything else is saved as #2d6a4f | Only the enquiry form and the footer link; the widget keeps its own colours |
| Enquiry collection (Leads tab) | lead_capture | object | off | See "Enquiry collection settings" below |
Enquiry collection settings
The savings calculator and the boiler escape plan can show a “get in touch” form after the visitor’s results, sending their details to your address and your dashboard’s Leads tab. It is off unless you switch it on for that widget in the Leads tab, and it can only be switched on there: no snippet or URL parameter can turn it on. Your own privacy notice needs to cover contacting the visitors who use it.
| Dashboard setting | Stored field (in lead_capture) | Type | Default | Allowed values |
|---|---|---|---|---|
| Collect enquiries | enabled | boolean | false | Stays false unless a valid notification address is set |
| Send enquiries to | notify_email | email address | (empty) | Required to switch collection on. Never sent to the visitor's browser |
| Your organisation's name | owner_label | string | (empty) | Up to 80 characters; names who the visitor agrees to hear from |
| Consent wording | consent_text | string | (empty: standard wording) | Up to 300 characters |
| Ask for a phone number | ask_phone | boolean | false | true or false |
| Ask what they are hoping to achieve | ask_goal | boolean | false | true or false |
How settings behave
- Settings are saved against the config ID when you copy the snippet. To change a widget that is already on your site, open its tab in the dashboard, choose it under Your saved widgets, click Edit, change the settings and click Save changes. The change shows on every page using that config ID at its next load, with no change to your HTML.
- Changing settings and clicking Copy again, without editing a saved widget, saves a new widget with a new config ID. The old one keeps its old settings.
- Nothing in the snippet can change a setting: the loader reads only the config ID, and an iframe with a dashboard config ID ignores other URL parameters.
- Restricting a widget to your own domain is not available: the dashboard only saves an allowed domain for paid accounts, and there is no paid plan today.
- Removing the “Powered by KarbonKit” link is set up by hand on request (hello@karbonkit.com), not in the dashboard.
Height and resizing
Every widget posts its content height to the page that embeds it whenever it changes, as a postMessage of { type: 'karbonkit:resize', height: <pixels> } from https://widgets.karbonkit.com.
- Script tag: handled for you. Nothing to add.
- Plain iframe: stays at its
heightattribute. Either set it tall enough for the smallest screen you care about (the calculator and boiler escape plan can pass 1500px on mobile), or add this listener once, anywhere on the page. It resizes every KarbonKit iframe on the page and ignores messages from anywhere else:
<script>
window.addEventListener('message', function (event) {
if (event.origin !== 'https://widgets.karbonkit.com') return;
if (!event.data || event.data.type !== 'karbonkit:resize') return;
var frames = document.querySelectorAll('iframe[src^="https://widgets.karbonkit.com/"]');
for (var i = 0; i < frames.length; i++) {
if (frames[i].contentWindow === event.source) {
frames[i].style.height = event.data.height + 'px';
}
}
});
</script>A plain iframe learns your page’s origin from the browser’s Referer header and sends its height only to that origin. A page served with Referrer-Policy: no-referrer, or an iframe with referrerpolicy="no-referrer", gets no height messages: use the script tag there. Keep the height attribute on the iframe as the size it shows before the first message arrives.
Examples
Plain HTML
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>What could a heat pump save you?</title> </head> <body> <h1>What could a heat pump save you?</h1> <!-- KarbonKit widget. Replace YOUR_CONFIG_ID with the config ID from your dashboard. --> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <script src="https://widgets.karbonkit.com/embed.js"></script> </body> </html>
Several widgets on one page need one loader:
<div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- ...the rest of your page... --> <div data-karbonkit data-config-id="YOUR_OTHER_CONFIG_ID"></div> <!-- One copy of the loader serves every widget on the page. --> <script src="https://widgets.karbonkit.com/embed.js"></script>
React
Add the loader from an effect rather than as a <script> element in JSX. The container is an empty <div>: React renders it, the loader fills it.
// KarbonKitWidget.jsx
import { useEffect } from 'react';
const LOADER = 'https://widgets.karbonkit.com/embed.js';
export default function KarbonKitWidget({ configId }) {
// Add the loader once per page. It also mounts containers React adds
// later, so client-side navigation and remounts need nothing extra.
useEffect(() => {
if (document.querySelector(`script[src="${LOADER}"]`)) return;
const script = document.createElement('script');
script.src = LOADER;
document.body.appendChild(script);
}, []);
// The loader fills each container once; key gives a new config ID a new one.
return <div key={configId} data-karbonkit="" data-config-id={configId} />;
}import KarbonKitWidget from './KarbonKitWidget';
export default function HeatPumpPage() {
return (
<section>
<h1>What could a heat pump save you?</h1>
<KarbonKitWidget configId="YOUR_CONFIG_ID" />
</section>
);
}Without the loader, as an iframe (take type, height and allow from the widget’s section above):
// KarbonKitIframe.jsx – for sites whose Content Security Policy will not
// allow a third-party script. Take type, height and allow from the widget's
// section of this guide.
import { useEffect, useRef } from 'react';
const HOST = 'https://widgets.karbonkit.com';
export default function KarbonKitIframe({ type, configId, height, allow = '' }) {
const ref = useRef(null);
// Optional: follow the widget's height instead of staying at `height`.
useEffect(() => {
const onMessage = (event) => {
const iframe = ref.current;
if (!iframe || event.origin !== HOST || event.source !== iframe.contentWindow) return;
if (event.data && event.data.type === 'karbonkit:resize') {
iframe.style.height = `${event.data.height}px`;
}
};
window.addEventListener('message', onMessage);
return () => window.removeEventListener('message', onMessage);
}, []);
return (
<iframe
ref={ref}
title="KarbonKit widget"
src={`${HOST}/widget-embed?type=${type}&cid=${configId}`}
width="100%"
height={height}
style={{ border: 'none', borderRadius: 8 }}
allow={allow || undefined}
allowFullScreen={allow.includes('fullscreen')}
/>
);
}
// <KarbonKitIframe type="lct-calculator" configId="YOUR_CONFIG_ID" height={900} allow="clipboard-write" />Next.js
The same component, marked as a Client Component. Its effect runs after hydration, so the loader never alters markup React is still hydrating. Any page, including a Server Component, can render it.
// components/KarbonKitWidget.jsx
'use client';
import { useEffect } from 'react';
const LOADER = 'https://widgets.karbonkit.com/embed.js';
export default function KarbonKitWidget({ configId }) {
// Runs after hydration, so the loader never changes markup React is
// still hydrating.
useEffect(() => {
if (document.querySelector(`script[src="${LOADER}"]`)) return;
const script = document.createElement('script');
script.src = LOADER;
document.body.appendChild(script);
}, []);
return <div key={configId} data-karbonkit="" data-config-id={configId} />;
}// app/heat-pumps/page.jsx – a Server Component can render the widget
import KarbonKitWidget from '../../components/KarbonKitWidget';
export default function Page() {
return (
<main>
<h1>What could a heat pump save you?</h1>
<KarbonKitWidget configId="YOUR_CONFIG_ID" />
</main>
);
}// pages/heat-pumps.jsx – the Pages Router uses the same component
// ('use client' is ignored there and does no harm).
import KarbonKitWidget from '../components/KarbonKitWidget';
export default function HeatPumps() {
return <KarbonKitWidget configId="YOUR_CONFIG_ID" />;
}If your site sets a Content Security Policy (for example in middleware.js or next.config.js), add the sources under Content Security Policy.
WordPress (block editor)
- Edit the page, click + to add a block, and choose Custom HTML (not “Code”, which shows the markup as text).
- Paste the widget’s script-tag snippet from its section above, with your config ID in it.
- Use the block’s Preview tab or preview the page, then publish.
<script src="https://widgets.karbonkit.com/embed.js"></script> <div data-karbonkit data-config-id="YOUR_CONFIG_ID"></div> <!-- Optional: you can delete the credit link below --> <a href="https://www.karbonkit.com/">Heat pump tools by KarbonKit</a>
- WordPress removes
<script>and<iframe>tags when the post is saved by a user without theunfiltered_htmlcapability (on a standard install only Administrators and Editors have it; on multisite only Super Admins). If the block comes back empty, ask an administrator to add it. - If scripts are stripped but iframes are allowed, paste the widget’s plain-iframe snippet instead. On WordPress.com, iframes need the Business plan or above.
- If a performance plugin delays or combines JavaScript, exclude
https://widgets.karbonkit.com/embed.jsfrom it, or the widget appears late or not at all.
Other platforms (Squarespace, Wix, Webflow, Shopify, Ghost) are covered at /docs/.
Troubleshooting
Content Security Policy
If your page sends a Content Security Policy, allow the widget host:
script-src https://widgets.karbonkit.com; # script-tag embeds only frame-src https://widgets.karbonkit.com; # both embed methods
- Add these to your existing sources; do not replace them. With no
frame-src, browsers fall back tochild-src, thendefault-src. - Nothing else is needed: the loader makes no network request, and everything the widget loads is governed by the widget page’s own policy, not yours.
- If your policy uses nonces or hashes for scripts, the loader’s
<script>tag needs your nonce like any other script, or use the plain iframe. - A
Permissions-Policyheader on your page that disablescamera,microphoneorxr-spatial-tracking(for examplecamera=()) overrides the iframe’sallowlist, and the AR visualiser or sound simulator cannot use them.
Iframe height
- Cut off, or an inner scrollbar: a plain iframe is fixed at its
height. Add the resize listener or switch to the script tag. Mobile Safari does not reliably scroll inside an iframe, so a taller fixed height is the weaker fix. - Script tag stuck at 600px: the loader only accepts height messages from the host it was loaded from. Load it from
https://widgets.karbonkit.com/embed.jsexactly; a copy served from anywhere else never resizes. - A parent with a fixed height or
overflow: hiddenclips the widget whatever its own height. Let the container grow.
Cookies and consent
- Widgets set no cookies, store nothing in the visitor’s browser and carry no advertising or third-party analytics trackers; KarbonKit records usage events itself, with a truncated IP address. The loader stores nothing either. Details, including what the widget sends to KarbonKit and to third parties such as postcodes.io, and a section for a data protection officer, are at /privacy/.
- If your consent tool blocks third-party scripts or iframes until the visitor accepts, the widget stays blank until then. Whether to exempt it is your decision, based on what the privacy page says it processes.
- Enquiry collection, if you switch it on, asks for contact details with the visitor’s explicit consent to hear from you. For those details you are the data controller, and your privacy notice needs to say so.
Mixed content and HTTPS
- Always use
https://widgets.karbonkit.comURLs as given, withhttps://. On an HTTPS page, browsers block anhttp://script or iframe as mixed content. - On a plain
http://page the widgets load, but the AR visualiser’s camera view and the sound simulator’s microphone meter do not work: browsers only allow those in a secure context, and an iframe is only secure if every page above it is. Serve the page over HTTPS (http://localhostcounts as secure during development). - Snippets pointing at
http://localhost:3000come from a development copy of the dashboard. Never publish them.
What the widget’s messages mean
| Message | Meaning | Fix |
|---|---|---|
| Widget misconfigured: missing or invalid config id. | The loader found a container whose data-config-id is empty or malformed. | Paste the config ID exactly as the dashboard gives it. |
| Widget not found. | No widget has this config ID (mistyped, or the widget was deleted). | Copy a fresh snippet from the dashboard. |
| Could not reach KarbonKit. Please try again in a moment. | The widget could not load its settings from KarbonKit’s API. | Reload. If it persists, contact hello@karbonkit.com. |
| This widget is not authorised for this site. | The widget has an allowed-domain list and your page is not on it. Only widgets with a domain list can show this. | Contact hello@karbonkit.com. |
| Sign up to embed this widget | A savings calculator or AR visualiser iframe has no config ID. | Add your config ID as cid=, or use the script tag. |
| Replace YOUR_CONFIG_ID in the embed code with your widget’s config ID… | The snippet was published with the placeholder still in it. | Put the config ID from the dashboard in its place. |
| This embed code does not carry a valid config ID. | A savings calculator or AR visualiser was given an ID the dashboard did not issue. | Copy a fresh snippet from the dashboard. |
Not supported
So that nobody spends time trying them:
- Self-hosting
embed.jsor the widget code. The loader points its iframe at the host it was loaded from, so a copy on your server tries to load the widget from your server. - Setting options in the snippet, through
data-attributes, URL parameters or JavaScript. Settings exist only in the dashboard. - A JavaScript API, callbacks or events other than
karbonkit:resize. - Styling the inside of the widget with your own CSS. It runs in an iframe on another origin; brand colour and company name are the supported controls.
- Languages other than English, or audiences outside the UK.
