Skip to content

Embed Script Reference ​

Two lines of HTML are all it takes to put a live AI assistant on your site — and the attributes on that <script> tag control everything from which agent loads to how the widget identifies itself to your backend.

This page is for developers who have already generated a Site key and want to understand every knob on the embed tag. If you haven't embedded the widget yet, start with the Quickstart and come back here for the details.

All data-* attributes ​

AttributeRequiredWhat it does
data-siteYesYour Site key (sa_site_live_… or sa_site_test_…). Sent as the X-Perfox-Site header on every request. If it's missing, the browser logs a console error and every request is rejected.
data-workflowNoID of the agent to load on this page, overriding the agent the site is bound to. The agent must be published and have a Web Chat trigger.
data-themeNoA built-in colour preset for the bubble before your agent's own appearance loads: bank_blue or insurance_green. Unknown names fall back to the default. Colours and bubble position you set on the Install tab's Appearance section always take priority.
data-api-urlNoAPI origin. Perfox derives this automatically from the bundle src; set it only when your API is served from a different origin than the bundle.

Site keys have the form sa_site_<env>_<52 chars> — live keys start with sa_site_live_* and test keys with sa_site_test_*. You'll find yours, together with a copy-ready snippet (HTML, React, Vue and a Node.js signing helper), on the Install tab of your agent's Web Chat trigger node.

Minimal embed ​

html
<script>
  (function(){var w=window;w.Perfox=w.Perfox||function(){(w.Perfox.q=w.Perfox.q||[]).push(arguments);};})();
</script>

<script
  src="https://acme-api.perfox.ai/widget/v1/widget.js"
  data-site="sa_site_live_xxxxxxxxxxxxxxxxxxxx"
  defer></script>

The first snippet defines window.Perfox as a queue stub. Any calls you make to Perfox(…) before the bundle has loaded are buffered in that queue. When the bundle finishes loading, it swaps in the real dispatcher, replays the buffered calls in order, and reads data-site off the script tag. See the SDK Reference for how to call window.Perfox after that point.

The bundle lives on your own API host (<slug>-api.perfox.ai) at /widget/v1/widget.js. It is served with permissive CORS, so it loads from any page.

Worked example — per-page agent override ​

Asha runs Acme Support. The site's agent handles general enquiries, but the /returns page needs a specialised returns agent. She adds data-workflow to the embed on that page only.

Setup: Asha's returns agent is published and has its own Web Chat trigger. She copies its ID from the end of the agent's address in Studio (…/agents/<id>).

Action: She pastes the ID into the embed tag on /returns:

html
<!-- override the site's agent on this page only -->
<script
  src="https://acme-api.perfox.ai/widget/v1/widget.js"
  data-site="sa_site_live_…"
  data-workflow="019df323-bf0f-7649-b40e-ff87c9dfabcd"
  defer></script>

Result: Priya, a customer, opens the returns page and the chat widget greets her with the returns agent's persona — not the general one.

What just happened: The widget read data-workflow on load and sent that ID with every request, so Perfox ran the named agent instead of the site's own. Every other page on the site is unaffected.

Boot precedence — host-page boot wins per key ​

The widget mounts once: if #perfox-widget already exists in the DOM (a hot reload, or the script included twice), it does nothing.

Config is resolved with host-page precedence: a value you set in Perfox('boot', { … }) before the bundle loads takes priority over the matching data-* attribute. Data attributes only fill the keys your JavaScript didn't supply. This lets you ship one generic embed snippet across your whole site and customise per page in JavaScript, without rewriting the script tag on each page.

How the widget finds the embed <script> ​

Perfox locates your embed tag in this order:

  1. document.currentScript
  2. The last script[data-workflow] element on the page
  3. The last script whose src contains widget.umd.js, widget.js, or widget.mjs

For deferred, async, or module scripts, document.currentScript is null by the time the bundle runs — steps 2 and 3 cover that case, and the standard /widget/v1/widget.js URL always matches step 3.

Deprecated global ​

The legacy window.__PerfoxUser global still works — it is read once at boot and logs a deprecation warning — but it is no longer the way to identify visitors. Use Perfox('identify', …) from the SDK instead: it can be called at any time and supports HMAC verification. See User Context & Identity.

You can now embed the widget and control which agent appears on each page ​

For the next steps:

  • Quickstart — if you haven't placed the embed on your site yet, start here
  • window.Perfox SDK — how to call Perfox(…) from your own JavaScript (boot options, identify, open/close, events)
  • Identity Verification (HMAC) — how to prove to Perfox that the visitor identity your page sends is genuine, so users can't impersonate each other