Embed widget

Embed comments into any website with a script tag — attributes, comment counters, guest comments and the limits of the approach.

Any website — blog, documentation, static HTML, whatever the stack — can embed your community's comments. The widget loads as an iframe from your community address: no CORS, no tracking, no requests to third parties.

Below, <your-community> stands for your community's address, for example yourname.pukalani.app.

Adding it

<div id="pukalani-comments"></div>
<script async src="https://<your-community>/embed.js"
  data-target-id="my-blogpost-42"
  data-target-type="blog"></script>

That's all. If the <div> is missing, the loader creates one itself in front of the script tag.

Alternative: web component

More convenient in CMSes and frameworks that handle custom elements more cleanly than injected <script> tags:

<script async src="https://<your-community>/pukalani-comments.js"></script>
<pukalani-comments target-id="my-blogpost-42" target-type="blog"
  theme="auto" locale="en" primary="sky"></pukalani-comments>

Attributes react live: theme switches without reloading, the other attributes reload the iframe. What is rendered is the same sealed-off iframe in the shadow DOM — security is identical to the script loader.

Attributes

AttributeRequiredDefaultMeaning
data-target-idyes—Stable key of the thread (≤ 255 characters)
data-target-typenopageNamespace, e.g. blog, docs (≤ 64 characters)
data-themenoautolight, dark or auto (follows prefers-color-scheme)
data-localenoende or en — language of the widget interface
data-primarynoThe community's settingAccent colour from the whitelist (red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose)
data-containernopukalani-commentsID of the target element; several widgets on one page each need their own container
Choose a fixed target-id, not the URL. A URL-based ID orphans the thread as soon as the page moves. A slug or the ID from your CMS survives any rebuild.

The widget's background is transparent only with data-theme="auto" — it then takes on the surface of your page.

Switching the theme at runtime

If your page has a light/dark switch of its own:

document.querySelector('#pukalani-comments iframe').contentWindow
  .postMessage({ type: 'pukalani:set-theme', theme: 'dark' }, 'https://<your-community>')

Comment counter

embed.js fills in every element carrying data-pukalani-count — handy for "N comments" links in an article list:

<a href="/blog/post-42#comments">
  <span data-pukalani-count data-target-id="post-42" data-target-type="blog">…</span>
</a>
<script async src="https://<your-community>/embed.js"></script>

data-target-type is optional (default page). The counter also works without a widget on the same page — the script alone is enough.

What you have to set up in your community

  • Enable embedding. While the feature is off, /embed returns a 404; all other pages forbid framing anyway (clickjacking protection for login and dashboard).
  • Register domains. Under Dashboard → Embed sites you enter which domains may embed; optionally you can limit per domain which target-type values are allowed. Changes take effect immediately. Unregistered embedders see a friendly message instead of an empty frame.
  • Guest comments (optional): commenting without an account — only a freely chosen display name is asked for, no email address. The default is off.

Signing in inside the widget

The sign-in button in the widget opens a popup on your community address — the normal login runs there, including sign-in by code. Afterwards the iframe takes over the session through a short-lived handover token and a partitioned cookie (CHIPS).

The consequence: the sign-in applies per embedding domain (as with other comment services). Browsers that discard partitioned cookies stay in reading mode and show a note with a link to the community.

Data protection with guest comments

If you allow guest comments:

  • Only the freely chosen display name is stored from a guest — it appears on the comment line and nowhere else.
  • No contact details are collected: no email address, no IP hash. Until 2 August 2026 the form additionally asked for an email address and filed it with an IP hash for moderation. That collection has been dropped without replacement, because the data was never retrievable; old data is deleted after 90 days. So there is no channel for asking a guest a question — anyone who needs that requires an account.
  • Guests can neither edit nor vote.
  • A tight rate limit applies (5 comments per minute and IP), and the comments count against your community's quota.

Limits

  • SEO: the comments live in the iframe under your community address. Crawlers of the embedding page don't see them — and /embed is set to noindex on top of that.
  • Reading without cookies: following along works without any cookie or storage access, even with strict tracking protection.
  • No inline variant: comments directly in the host page's DOM (without an iframe) deliberately don't exist — that would need an HTML sanitiser of its own and an open CORS allowlist.