Skip to navigation

Embed SDK

One script on your quote pages that checks for AI agents, pauses the step that matters, and gives the agent a link for the customer to approve.

The embed is a small script (no dependencies, under 15 KB gzipped) that runs on your quote and checkout pages. You tell it which step to protect, usually the button that continues to payment. When someone continues from that step, the embed:

  1. Holds the click or submit and asks HumanApproved whether this purchase needs the customer’s approval.
  2. On continue, lets it proceed unchanged.
  3. On review, sends the quote for approval and shows the agent a pause panel with a link to pass to the customer. Once the customer approves the purchase, the panel closes and the step proceeds automatically.

If HumanApproved doesn’t respond in time, or an error occurs, the step proceeds.

Install

Load the embed on every page of the journey, not only the checkout page: what it measures counts from the first page. Load a pinned version with its Subresource Integrity hash:

<script src="https://cdn.beopen.com/approvals-embed/1.5.0/embed.js"
integrity="sha384-…" crossorigin="anonymous" async></script>
<script src="/js/checkout-approvals.js" defer></script>

Copy the snippet from the portal’s Embed page: it has the current version and its integrity hash filled in. There’s no “latest” URL. To upgrade, change both the version and the hash.

Your Content Security Policy must allow the CDN in script-src and https://au.humanapproved.com in connect-src and img-src. See Content Security Policy.

Protect a step

The embed loads async, so queue your call. The queue works whether your script runs before or after the embed loads:

checkout-approvals.js
window.HumanApproved = window.HumanApproved || { q: [] };
HumanApproved.q.push(["protect", {
key: "pk_live_…", // your publishable key
quote: "HTA-4471920", // your quote reference (not personal data)
before: "#continue-to-payment", // the button, link or form to protect
quoteDetails: () => ({ // the quote the customer will approve
quote: {
policyholder: { firstName: "Sam" },
destination: "Japan",
dates: { from: "2026-12-03", to: "2026-12-17" },
travellers: 2,
cover: "Comprehensive",
excess: 200,
premium: { amount: 412.6, currency: "AUD" },
},
mobile: "+61 491 570 156",
}),
}]);

quote holds your product’s fields, as set on the product’s Fields page in the portal. Every option is described in protect() options.

The names you’ll see. The product is HumanApproved. The script comes from cdn.beopen.com/approvals-embed, its global is HumanApproved, its console messages start with [humanapproved], and its browser storage keys start with agent-signals. You can search for any of them to find the integration.

What before protects

before is a CSS selector for a button or link (the embed protects its click) or a form (it protects the submit). A form’s submit is protected when:

  • before matches the form or an element around it,
  • the protected button submits it, or
  • your code calls form.requestSubmit() with no button and the protected element is one of the form’s submit buttons.

form.submit() doesn’t fire a submit event, so it can’t be protected. Submit from code with requestSubmit().

One checkout, several products

A publishable key identifies one product. If your journey sells several products, call protect() with the key of the product being bought, once it’s known. Load the embed on every page, and make the call from the page where the product is selected. Calling protect() again for the same step with another product’s key and quote replaces the earlier call, and the next press checks the new quote against that product.

Give each step its own selector. If the pressed button is replaced while it’s held and before then matches several elements (for example, one button per plan), the embed doesn’t re-fire the press, and the next press proceeds.

Single-page apps

Calling protect again for the same before updates its options, and protection keeps working when the button is re-rendered. If you pass a different quote, any check or review in progress for the old quote is dropped, its panel closes, and the next press checks the new quote.

What happens at the protected step

What happensWhat the embed does
The check returns continueReplays the original click or submit, untouched.
The check returns reviewSends quoteDetails() for approval and shows the pause panel. On approval, closes the panel and replays the step.
The customer declines, or the link expiresTells the agent nothing was paid, and to ask the customer what they want to do. The step stays paused, and the next attempt runs a new check.
No response in 2.5 seconds (or timeoutMs)Lets the step proceed and records the check as fail_open.
Any error (a revoked key, an unpublished product, a server error)Lets the step proceed. The browser console shows the reason.
A press after a fail-openChecks again, waiting at most 1 second. If that also fails open, later attempts for this quote proceed unchecked until the page reloads.

For a product set to monitor only, the press isn’t held at all: the check runs in the background. See Monitor only.

Next steps