Skip to content

Quickstart

Get the Expedition Insure quote widget rendering on your page and reacting to its events — the fastest path from a publishable key to a working embed. This page is for operator tech teams wiring up their first integration. For the full contract, see the embed integration guide; for the raw event payloads see /reference/events/; for sequencing your own checkout off the widget see /guides/checkout-sequencing/.

You need two things before the widget will render, both tied to your operator account:

  • A publishable key (pk_op_...). It authenticates every embed request and ships in your page’s HTML — it’s public by design, like a Stripe pk_. You pass it as config.pk.
  • An allowlisted origin. We add the exact origins your widget loads from (scheme + host + port, e.g. https://www.youroperator.com) to your per-operator allowlist. A request from a non-allowlisted origin gets a fail-closed, blank frame — never data.

New here? Start at the partner registration page — it walks you through the setup steps, then signs you in and provisions your operator account (and your first pk_op_...) in one go. After that, manage your key and origins in the operator portal. Send us every origin you’ll embed from (production, staging, and any sandbox); up to 20 per operator.

The key is public; the origin is the boundary. A copied pk_op_... is useless from an origin we haven’t allowlisted. The trust boundary is the server-side origin allowlist plus a per-key rate limit, not key secrecy.

Add one script tag, then call ExpeditionInsure.mount(target, config):

<div id="quote"></div>
<script src="https://expedition.insure/widget.js"></script>
<script>
ExpeditionInsure.mount("#quote", {
pk: "pk_op_...", // your publishable key
destination: "antarctica",
startDate: "2026-12-01",
endDate: "2026-12-14",
ages: [45, 47],
residence: "US",
tripCost: 18000, // total trip cost, whole dollars
travelers: 2,
});
</script>

widget.js is a tiny, React-free loader. On mount() it injects a sandboxed <iframe> into your target element, pointing at https://expedition.insure/embed/quote?<params>. The quote form and options render on our origin — your page never handles insurance data directly.

  • target — a CSS selector string ("#quote") or an HTMLElement. If it matches nothing, mount() throws.
  • configpk is required (missing pk throws); everything else is optional and pre-fills the form. See the config params table for the full list.
  • mount() returns the created HTMLIFrameElement.
  • The iframe auto-sizes to its content (no inner scrollbars) via an ei:resize relay — you don’t set a height.

The global is window.ExpeditionInsure with { mount, on, embedOrigin }. There is no unmount() or update() today — to change config, clear the target element and call mount() again. [needs-product-work]

Subscribe with ExpeditionInsure.on(eventName, handler). It returns an unsubscribe function. Unknown event names throw. Handlers run isolated — a throw in your handler is caught and logged, never breaking the bridge. Multiple handlers per event run in subscribe order.

The two events you’ll wire first:

EventPayload shapeFires when
quote.ready{ quoteId?: string, plansCount?: number }The quote form renders and options are ready.
quote.selected{ planId: string, premiumCents: number, premium: number, currency?: string }A traveler clicks a plan card.
ExpeditionInsure.on("quote.ready", (e) => {
console.log("ready", e.quoteId, e.plansCount);
});
ExpeditionInsure.on("quote.selected", (e) => {
// premiumCents is canonical — integer minor units (cents).
const dollars = e.premiumCents / 100;
console.log("picked", e.planId, dollars, e.currency);
});

Read premiumCents (integer minor units). premiumCents is the premium field — divide by 100 yourself for display.

The full event catalog — quote.error, plus the embedded-checkout payment.succeeded / payment.failed events — is at /reference/events/.

A complete, copy-pasteable page. Drop in your pk_op_..., serve it from an allowlisted origin, and open it:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Travel insurance quote</title>
</head>
<body>
<h1>Add travel insurance to your trip</h1>
<div id="quote"></div>
<script src="https://expedition.insure/widget.js"></script>
<script>
ExpeditionInsure.mount("#quote", {
pk: "pk_op_...", // your publishable key
destination: "antarctica",
startDate: "2026-12-01",
endDate: "2026-12-14",
ages: [45, 47],
residence: "US",
tripCost: 18000, // total trip cost, whole dollars
travelers: 2,
});
ExpeditionInsure.on("quote.ready", (e) => {
console.log("quote ready:", e.quoteId, "plans:", e.plansCount);
});
ExpeditionInsure.on("quote.selected", (e) => {
// Canonical premium is premiumCents (integer minor units).
const display = (e.premiumCents / 100).toLocaleString("en-US", {
style: "currency",
currency: e.currency || "USD",
});
console.log("plan selected:", e.planId, display);
});
</script>
</body>
</html>

If the iframe stays blank, your origin probably isn’t allowlisted yet — check the console for a frame-ancestors CSP violation. If quote.error fires immediately, verify the pk_op_... value and that your page origin is on the allowlist.

  • /guides/checkout-sequencing/ — sequence your own trip-charge checkout off the widget’s events. payment.succeeded is a UX-only signal that can be missed; reconcile sales from the authoritative policy.issued webhook, and keep your trip charge on a separate rail.
  • /reference/events/ — every event and its exact payload, including quote.error, payment.succeeded, and payment.failed.
  • embed integration guide — config params, the key/origin exchange, CSP and sandbox requirements, and troubleshooting in full.