Developer docs
Embeds and attribution
One iframe that works on any page builder, a small script that carries the host page's campaign attribution into the player, and a message contract for passing click ids across the frame when you need more than the URL can carry.
The universal embed
Every video's Share modal offers one embed: a responsive 16:9 wrapper capped at 780px around the chrome-free /embed/{shortId} surface, plus two scripts. The first copies the host page's query string, referrer and path onto the iframe source at insert time; the second injects the video's structured data into the host page for search and AI crawlers. Copy it from the Share modal; this is what it produces.
<!-- StreamAgent video -- works on any page builder -->
<div style="position:relative;width:100%;max-width:780px;aspect-ratio:16/9;margin:0 auto;">
<iframe id="sa-abc123"
src="https://you.streamagent.io/embed/abc123"
style="position:absolute;inset:0;width:100%;height:100%;border:0;"
allow="autoplay; encrypted-media; picture-in-picture; fullscreen; clipboard-write"
allowfullscreen
title="Pricing walkthrough"></iframe>
</div>
<script>(function(){var f=document.getElementById('sa-abc123');if(!f)return;var p=window.location.search.slice(1);var r=document.referrer?'sa_ref='+encodeURIComponent(document.referrer):'';var u='sa_url='+encodeURIComponent(window.location.pathname);var q=[p,r,u].filter(Boolean).join('&');if(q)f.src=f.src+(f.src.indexOf('?')>-1?'&':'?')+q;})();</script>
<script src="https://you.streamagent.io/embed/abc123/companion.js" async></script>Routes and rotations
A route embeds from its own URL with ?embed=1, which renders the bare player rather than the share page. The wrapper takes the entry video's aspect ratio, so a vertical route gives a vertical embed. Its forwarding script copies only utm_* parameters and ad click ids, marks the frame so a second script on the page never forwards twice, and leaves everything else on the host URL alone.
<!-- Pricing walkthrough — interactive video embed -->
<div style="position:relative;width:100%;aspect-ratio:16/9;">
<!-- aspect-ratio needs a modern browser; for legacy support replace it with: height:0;padding-bottom:56.25%; -->
<iframe data-sa-route src="https://app.streamagent.io/r/pricing-walkthrough?embed=1" title="Pricing walkthrough" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" allow="autoplay; encrypted-media; picture-in-picture; fullscreen" allowfullscreen loading="lazy"></iframe>
</div>
<script>
/* A static iframe can't see this page's URL, so campaign attribution would
stop at the frame edge. This copies the page's utm_* params and ad click
ids onto the player URL at insert time. */
(function () {
var clickIds = ["fbclid","gclid","ttclid","li_fat_id"]
var params = new URLSearchParams(window.location.search)
var pairs = []
params.forEach(function (v, k) {
if (k.indexOf('utm_') === 0 || clickIds.indexOf(k) !== -1) pairs.push([k, v])
})
if (!pairs.length) return
var frames = document.querySelectorAll('iframe[data-sa-route]:not([data-sa-forwarded])')
for (var i = 0; i < frames.length; i++) {
var url = new URL(frames[i].getAttribute('src'), window.location.href)
for (var j = 0; j < pairs.length; j++) url.searchParams.set(pairs[j][0], pairs[j][1])
frames[i].setAttribute('data-sa-forwarded', '1')
frames[i].src = url.toString()
}
})()
</script>A Smart Rotation embeds through /embed/r/{slug}. The server resolves the audience lane and redirects the frame to the winning video or route, carrying the forwarded parameters with it so lane rules that match on utm_source or utm_campaign see them.
<!-- StreamAgent -- works on any page builder -->
<div style="position:relative;width:100%;max-width:780px;aspect-ratio:16/9;margin:0 auto;">
<iframe id="sa-spring-offer"
src="https://you.streamagent.io/embed/r/spring-offer"
style="position:absolute;inset:0;width:100%;height:100%;border:0;"
allow="autoplay; encrypted-media; picture-in-picture; fullscreen; clipboard-write"
allowfullscreen></iframe>
</div>
<script>(function(){var f=document.getElementById('sa-spring-offer');if(!f)return;var p=window.location.search.slice(1);var r=document.referrer?'sa_ref='+encodeURIComponent(document.referrer):'';var u='sa_url='+encodeURIComponent(window.location.pathname);var q=[p,r,u].filter(Boolean).join('&');if(q)f.src=f.src+(f.src.indexOf('?')>-1?'&':'?')+q;})();</script>What the forwarding script carries
| Added to the iframe URL | Value |
|---|---|
| The host page's query string | Everything after ? on the host URL, for the video and rotation snippets; only utm_* and click ids for the route snippet. |
sa_ref | The host page's referrer, so the player records where the visitor came from. |
sa_url | The host page's path, recorded as the page the video was on. |
Inside the frame the player keeps these for the session, so a lead captured three minutes in still carries the campaign that brought the visitor.
Attribution by query string
If you build your own iframe, put the ids you have on the src yourself. The player reads these keys and nothing else:
fbp
fbc
gclid
ttclid
ttp
ga_client_id
li_fat_id
fbclid<iframe src="https://you.streamagent.io/embed/abc123?gclid=Cj0K…&fbclid=IwAR…"></iframe>Attribution by postMessage
Cookies such as _fbp and _fbc live on your domain, not on the URL. Send them into the frame after it loads with a message of type streamagent:attribution. Only the keys above are read; anything else is ignored. Values sent this way take priority over query parameters.
<iframe id="sa-abc123" src="https://you.streamagent.io/embed/abc123"></iframe>
<script>
var frame = document.getElementById('sa-abc123');
var cookie = function (name) {
var m = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return m ? m[2] : '';
};
frame.addEventListener('load', function () {
frame.contentWindow.postMessage({
type: 'streamagent:attribution',
attribution: {
fbp: cookie('_fbp'),
fbc: cookie('_fbc'),
gclid: new URLSearchParams(location.search).get('gclid') || ''
}
}, '*');
});
window.addEventListener('message', function (e) {
if (e.data && e.data.type === 'streamagent:attribution-ack') { /* received: true */ }
});
</script>- Send as early as you can after the frame loads; the player waits briefly for a message before settling on the URL values.
- The frame replies with
{ type: 'streamagent:attribution-ack', received: true }once it has applied the values. - Empty strings and unknown keys are dropped. Attribution is used for analytics, lead records and ad-platform events only.
The companion script
/embed/{shortId}/companion.js is bundled into every video embed. On load it injects the video's structured data into the host page so crawlers that never follow an iframe still see the video and its transcript. It is served with no caching and returns an empty script the moment a video is made private or non-indexable, so turning discoverability off takes effect on the next page load.
When to use the direct link instead
Email clients strip iframes and scripts, and some tools such as Notion refuse raw HTML. Use the video's direct link (/watch/{shortId}) there; it opens the full share page with the player. The Share modal also produces an email clip: a thumbnail that opens the video.
Paste notes by platform
The same notes the Share modal shows under "Where are you embedding?".
| Platform | Note |
|---|---|
| ClickFunnels | Two ways to do this -- pick what matches your skill level. Easy path (recommended for most users): Drag in a Video element. Switch the source to "Custom Embed," then paste the iframe code. Save. Works the same on ClickFunnels 2.0 and Classic. Power path: Drag in a Custom JS/HTML element instead. Click the element, hit "Open Code Editor," paste the full embed (iframe + script). Set Code Type to "3rd Party Embed Code." This is the right choice if you want the attribution script firing. |
| GoHighLevel | In the funnel/website editor, drag in a Custom JS / HTML element (also labeled "Code" on some plans). Paste the iframe code. Save and publish. For surveys or two-step funnels, paste into the page's "Custom HTML" section under Settings → Tracking if you need it on every step. |
| Webflow | Add an Embed element (the </> block). Paste the code. Publish. Attribution (UTMs, click IDs, referrer) flows through automatically. |
| WordPress | In Gutenberg, add a Custom HTML block and paste the iframe code. Or in Classic, switch to the Text tab. Plugin coming soon for one-click installs. |
| Squarespace | Heads up: Requires Core plan or higher. Personal plans block iframe rendering entirely. On a paid plan, add a Code block (not Embed), paste the iframe, and make sure the Display Source toggle is OFF (when ON, Squarespace shows the raw code as text instead of rendering it). Scripts are also gated to paid plans, so the iframe-only version above is your most reliable choice. |
| Wix | In Wix Editor or Wix Studio, add an Embed a Widget element (under Add → Embed Code). Paste the iframe code. Wix sandboxes the embed inside its own iframe, so cross-frame scripts won't reach your main page -- that's fine for the universal embed above, but if you need parent-page attribution, use Wix's Custom Code (Settings → Advanced → Custom Code) on a paid plan instead. |
| Carrd | Drag in an Embed element. Paste. Carrd auto-sizes the wrapper, so the aspect-ratio div above handles mobile correctly. |
| Framer | Insert an Embed component (or use HTML override on a frame). Paste the code. Framer respects the aspect ratio out of the box. |
| Notion | Heads up: Notion doesn't accept raw iframe HTML. Use the direct link below -- paste the link, hit Enter, choose "Embed" from the menu. Notion will embed the share page natively. |
| Kit (formerly ConvertKit) | In your landing page editor, add an HTML block (Kit, formerly ConvertKit). Paste. If you're embedding in an email broadcast or sequence, use the direct link below -- email clients strip iframes. |
| Beehiiv | On a Beehiiv landing page, add an HTML Embed block. For email posts, use the direct link below -- most email clients strip iframes and all of them strip scripts. |
| Kajabi | Edit your page → add a Custom Code element. Paste the iframe code. Kajabi blocks scripts on most pages, so iframe-only. |
| Teachable | In a lesson, use the Code block. On marketing pages, use the Custom HTML element. Iframe is the safe bet. |
| Thinkific | Add an HTML / Liquid block to your lesson or page. Paste the iframe code. |
| Ghost | In the editor, type /html to insert an HTML card. Paste. Ghost supports both iframes and scripts on most plans. |
| Custom HTML page | Paste anywhere in your HTML. The iframe is self-contained -- no other setup needed. UTMs, click IDs, and referrer are forwarded into the video automatically. |
| Email body (Klaviyo, etc) | Heads up: Email clients strip both iframes and scripts. Use the direct link below -- it opens a full share page with the player. You can wrap the link around a thumbnail image for a "click-to-play" feel. |