GemmaPoddocs
Guides

Embed on any page

The script-tag embedding cookbook — pin, hash, and lock down.

The minimal embed

<div id="pod"></div>
<script src="https://cdn.jsdelivr.net/npm/@gemmapod/embed@0.1.0/dist/gemmapod-shim.iife.js"></script>
<script>
  GemmaPod.mountPod(document.getElementById("pod"), {
    name: "Embedded pod",
    persona: "Helpful product explainer.",
    systemPrompt: "Be terse.",
    model: "gemma4:e4b",
    transport: {
      dartc: { signalUrl: "wss://signal.gemmapod.com/signal", podId: "your-pod-id" },
      fallback: { model: "onnx-community/gemma-4-E2B-it-ONNX" },
    },
  });
</script>

Production deserves more care than that.

Subresource Integrity

When you load JS from a CDN, pin the version AND add an SRI hash. That way a CDN compromise or a future maintainer republishing the same version with different bytes fails closed in every visitor's browser.

# Compute SHA-384 of the exact tarball you tested.
curl -fsSL "https://cdn.jsdelivr.net/npm/@gemmapod/embed@0.1.0/dist/gemmapod-shim.iife.js" \
  | openssl dgst -sha384 -binary | openssl base64 -A

Then:

<script
  src="https://cdn.jsdelivr.net/npm/@gemmapod/embed@0.1.0/dist/gemmapod-shim.iife.js"
  integrity="sha384-PASTE_HASH_HERE"
  crossorigin="anonymous"
></script>

Content Security Policy

The shim needs these script-src directives:

DirectiveWhy
'self'Your page's own scripts
'unsafe-inline'The shim's inlined boot snippet runs from a <script> element with body content
'wasm-unsafe-eval'WebAssembly.instantiate(...) for the inlined WASM core
https://cdn.jsdelivr.netThe shim IIFE itself when CDN-loaded

For connect-src you need:

DirectiveWhy
wss:WebRTC signaling endpoint(s) the manifest may specify
stun:STUN servers for ICE
https://huggingface.co https://*.hf.co https://cas-bridge.xethub.hf.coOnly if you ship the WebGPU fallback path
https://cdn.jsdelivr.netOnly if you ship the WebGPU fallback path — transformers.js

gemmapod.com/<id>-served pods already ship a strict CSP with these exact directives. If you embed via a <script> tag on your own page, copy them into your Content-Security-Policy response header.

Hosting the IIFE yourself

Don't trust jsDelivr's uptime? Host the shim on your own static infrastructure:

curl -fsSL "https://cdn.jsdelivr.net/npm/@gemmapod/embed@0.1.0/dist/gemmapod-shim.iife.js" \
  > public/vendor/gemmapod-shim.iife.js

And reference it as /vendor/gemmapod-shim.iife.js. CSP simplifies significantly when everything is 'self'.

Cleanup on SPA navigation

The runtime keeps a WebRTC peer connection alive until you destroy it. On route changes:

let current;
GemmaPod.mountPod(el, config).then((m) => (current = m));

window.addEventListener("popstate", async () => {
  if (current) await current.destroy();
  current = undefined;
});

See also