Docs · Player · SDK
Treisa Player — Guía de integración de embeds (SDK v2)
Versión del loader: /v2/player.js · Versión del bridge postMessage: treisa.player.v1 / treisa.host.v1
Esta guía explica cómo incrustar un video de Treisa Flow en tu sitio, qué permite la CSP de tu página, cómo recibir eventos y comandar el player, cómo integrar tu banner de cookies (CMP) con la telemetría del player, y cómo diagnosticar errores.
1. Quickstart
Pega esto donde quieras el video (reemplaza EMBED_KEY por la key que te da
Treisa Flow en Player → Embeds → Copiar snippet):
<!-- Treisa Player — embed -->
<div data-treisa-player="EMBED_KEY"></div>
<script async src="https://player.treisaflow.com/v2/player.js"></script>
Requisitos:
- Dominio registrado. En Treisa Flow, agrega el dominio de tu sitio en
Player → Dominios (ejemplo:
misitio.com, sinhttps://). Sin un dominio registrado, el player responde error de dominio no autorizado. - Flag del workspace activo (
treisa_player_external_embed_enabled) — lo activa el equipo de Treisa. - El video debe estar publicado y en estado
ready.
Configuración opcional por atributo data-* (todos opcionales, validados; un
valor inválido se ignora con un aviso en consola):
| Atributo | Valores | Default | Para qué |
|---|---|---|---|
data-aspect | 16/9, 9/16, 4/3, 3/4, 1/1 | 16/9 | Proporción del contenedor (VSLs verticales usan 9/16). |
data-analytics | true, false, wait | true | false: nunca envía analítica. wait: espera tu CMP (ver §5). |
data-on-event | nombre de función global | — | Callback del host, ej. data-on-event="onTreisaEvent". Ver §4. |
data-color | #rrggbb | #0a0a0a | Color del placeholder antes de cargar. |
data-radius | píxeles | 12px | Redondeo del contenedor. |
Nota: si inyectas el snippet dinámicamente después de cargar
player.js, llamawindow.TreisaPlayer.scan()para detectar los divs nuevos. Cuando el script se carga conasync, el origen del player se toma del propio script; solo en inyecciones sincurrentScriptse usa el defaulthttps://player.treisaflow.com.
2. Guía de seguridad (CSP)
Directrices que tu página necesita para permitir el embed (lo único que tu
documento carga del player, según el código del loader y de la página /e/):
script-src https://player.treisaflow.com;
frame-src https://player.treisaflow.com
script-src: solo si usas el snippet con script (loader v2). El loader es un archivo estático servido desde el player host. Con CSP basada en nonces, añade tunonce-...al tag<script>del snippet.frame-src: siempre — el video se reproduce dentro de un iframe deplayer.treisaflow.com. En navegadores antiguos el alias legado eschild-src; si lo declaras, mantenlo igual queframe-src.connect-src: NO requerido para tu página. Todas las conexiones del player ocurren desde dentro del iframe, no desde tu documento: el boot (/api/v1/video/playback/embed/...), el manifest y la analítica van same-origin al player host.- Media:
https://stream.mux.com(HLS del video) yhttps://image.mux.com(thumbnails) corren dentro del iframe; conframe-srcbasta, tu CSP no necesita permitirlos. - Pixels de marketing (solo si activas
data-marketing-consent): los SDK de Meta/Google/TikTok también se cargan dentro del iframe — tu página no necesita abrirlesscript-src/connect-src. - El loader inyecta
<link rel="preconnect"|"dns-prefetch">al player host y ahttps://stream.mux.com: son hints de rendimiento, ninguna directiva CSP los bloquea. - Los eventos/comandos viajan por
postMessage, sin directiva CSP propia. Tu listener debe validarevent.origin(ver §4.1).
Ejemplo de header mínimo para una página que solo embebe el player:
Content-Security-Policy: script-src 'self' https://player.treisaflow.com; frame-src https://player.treisaflow.com
3. Iframe plano (CSP sin scripts de terceros)
Si tu CSP no permite scripts de terceros, usa la variante sin script:
<iframe
src="https://player.treisaflow.com/e/EMBED_KEY"
title="Treisa Player"
allow="autoplay; fullscreen; encrypted-media; picture-in-picture"
allowfullscreen
referrerpolicy="strict-origin-when-cross-origin"
sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-presentation"
style="width:100%;aspect-ratio:16/9;border:0"></iframe>
La variante iframe no tiene callbacks ni atributos de configuración (usa
los valores por defecto), pero los eventos y comandos postMessage siguen
funcionando, porque viven dentro de la página /e/ del player.
4. Callbacks y comandos (postMessage)
4.1 Eventos del player → tu sitio (treisa.player.v1)
Escucha en tu página:
window.addEventListener("message", function (event) {
if (event.origin !== "https://player.treisaflow.com") return; // ¡siempre valida!
var ev = event.data;
if (!ev || ev.source !== "treisa-player" || ev.v !== 1) return;
// ev.embedKey, ev.type, ev.ts, ev.data
});
Tipos de evento: ready, error, play, pause, complete, cta_click,
form_submit, analytics_off. El campo data según el tipo:
| type | data |
|---|---|
ready | { title: string | null } |
error | { code: string; message: string } — códigos en §6 |
cta_click / form_submit | { interactionId: string; label: string | null } |
play / pause | { positionSec: number } |
complete | { positionSec: number } |
analytics_off | — |
Con el loader v2 también puedes usar callbacks directos sin addEventListener:
// Opción A: atributo — Treisa llama window.onTreisaEvent(ev) por cada evento
<div data-treisa-player="EMBED_KEY" data-on-event="onTreisaEvent"></div>
// Opción B: programático — devuelve una función para dejar de escuchar
var off = window.TreisaPlayer.on("EMBED_KEY", function (ev) { /* ... */ });
// off(); // unsubscribe
API pública del loader: window.TreisaPlayer = { scan, origin, version: 2, on }.
4.2 Comandos de tu sitio → player (treisa.host.v1)
var iframe = document.querySelector('div[data-treisa-player] iframe');
iframe.contentWindow.postMessage(
{ source: "treisa-host", v: 1, embedKey: "EMBED_KEY", cmd: "play" },
"https://player.treisaflow.com" // nunca "*"
);
| cmd | args | efecto |
|---|---|---|
play / pause | — | Control de medios. |
mute / unmute | — | Silenciar / reactivar audio. |
seek | { sec: number } | Mueve la posición; respeta los bloqueos de avance del video (no puede saltarse lockSeek). |
setAnalytics | { enabled: boolean } | Enciende/apaga la analítica del embed en caliente (ver §5). |
Los comandos son de control de medios: no devuelven datos; la información solo fluye del player hacia tu sitio vía eventos.
5. Consentimiento (CMP) × analítica
La analítica del player no lleva datos personales (identificadores opacos),
por eso el default es true. Si tu CMP requiere consentimiento previo:
- Publica el embed con
data-analytics="wait"(el player retiene toda telemetría desde el boot). - Cuando el usuario acepta, envía el comando:
iframe.contentWindow.postMessage(
{ source: "treisa-host", v: 1, embedKey: "EMBED_KEY", cmd: "setAnalytics", args: { enabled: true } },
"https://player.treisaflow.com"
);
- Si el usuario rechaza:
data-analytics="false", osetAnalyticsconenabled:falseen caliente (el player deja de enviar y emite el eventoanalytics_off). Lo ya enviado no se puede retractar.
Formularios con datos personales: los leads del player piden su propio
checkbox de consentimiento explícito (tf-lead-v1) validado en el servidor.
Ese flujo es independiente del interruptor de analítica y nunca se afecta con
setAnalytics.
6. Diagnóstico de errores
El evento error (y la API de playback) usa códigos estables:
| code | HTTP | Causa y qué revisar |
|---|---|---|
EMBED_INVALID_KEY | 400 | La key no es un UUID — copia el snippet de nuevo. |
EMBED_NOT_FOUND | 404 | El embed fue borrado (revocado) o la key no existe. |
EMBED_UNPUBLISHED | 403 | El video está despublicado — publícalo en Treisa Flow. |
EMBED_DISABLED_FLAG | 403 | El flag externo del workspace está apagado — contacta a Treisa. |
EMBED_DOMAIN_NOT_ALLOWED | 403 | Tu dominio no está registrado/verificado en Player → Dominios. Incluye allowlist vacía. |
EMBED_NOT_READY | 409 | El video sigue procesándose — espera a que esté ready. |
EMBED_NO_PLAYBACK | 409 | Sin fuente de reproducción disponible — contacta a Treisa. |
Nota: el rate limit público (120 req/min por IP) puede devolver 429 transitorio si la página dispara muchísimos boots simultáneos.
7. Cache y estabilidad del snippet
/v2/player.jses inmutable por ruta: servido conCache-Control: public, max-age=300, stale-while-revalidate=86400. Tu CDN puede cachearlo; las actualizaciones de Treisa no rompen snippets copiados.- El snippet nunca cambia de formato (promesa ADR-006): el mismo div +
script sigue funcionando para siempre. Mejoras futuras van en
/v3/. /v1/player.jsestá congelado tal como se entregó históricamente; los snippets viejos siguen funcionando sin lazy-load ni callbacks.
8. Verificación de dominios
Registrar un dominio en Player → Dominios ya no es una autodeclaración:
cada dominio nace pending con un challenge de ownership y el playback
público es fail-closed — solo se sirve desde dominios verificados (o sus
subdominios) además de los hosts del propio player. Con la allowlist vacía o
sin un match, el embed responde EMBED_DOMAIN_NOT_ALLOWED (403).
Cómo se verifica (challenge)
El botón Verificar del panel evalúa dos caminos en orden fijo; basta con que uno pase:
- DNS TXT (camino principal): registro TXT en
_treisa-challenge.<tu-dominio>cuyo valor exacto es el token que el panel muestra y deja copiar (tf-verify=<32 hex>). La propagación DNS puede tardar 24–48 h. - Meta tag (fallback inmediato): si el TXT todavía no responde, se
fetchea
https://<tu-dominio>/(solo HTTPS, máximo 3 redirects, budget total 6 s) y se busca en el HTML de la raíz un<meta name="treisa-domain-verification" content="tf-verify=<token>">con elcontentexacto.
La verificación es revocable: Re-verificar re-evalúa el challenge, y
si el dominio ya no lo responde (TXT borrado, meta quitado), pasa a failed
y el playback público se corta. Sin referrer del host no hay match — ver
Apéndice.
Estados e historial
| Estado | Significado |
|---|---|
pending | Recién registrado: challenge emitido (challenge_token), sin intento exitoso aún. |
verified | Un challenge pasó. verification_method registra cómo: dns_txt, meta_tag o grandfathered (dominios verificados antes de que existiera el challenge). |
failed | El último intento no pasó — el panel muestra método, código y hora del último intento. |
Cada intento (una fila por método probado) queda en el historial de checks
del dominio (icono de historial en el panel; últimos 20, retención 90 días)
con método, código cerrado (dns_txt_ok, dns_txt_mismatch,
dns_txt_absent, meta_ok, meta_absent, meta_fetch_error, …) y detalle.
Entre verificaciones hay un throttle de 30 s (HTTP 429 si reintenta antes).
Notas: localhost e IPs literales pueden estar en la allowlist en dev pero
no son verificables (el challenge los rechaza); un dominio de un solo label
tampoco se acepta.
9. Guías de instalación por plataforma
Paso a paso con los nombres de menú reales de cada plataforma para pegar el snippet del panel (Player → Embeds → Copiar snippet), un ejemplo con el snippet exacto y notas de CSP/troubleshooting por plataforma. El snippet es uno solo (el de §1 y §3); las guías solo cambian dónde se pega:
| Plataforma | Guía |
|---|---|
| HTML plano | HTML plano |
| WordPress (+Elementor) | WordPress + Elementor |
| ClickFunnels | ClickFunnels |
| GoHighLevel | GoHighLevel |
| Shopify | Shopify |
| Systeme.io | Systeme.io |
En todas las guías EMBED_KEY representa la key de tu embed y el host
https://player.treisaflow.com es el player host por defecto (el
playerHost con el que el panel genera el snippet); si tu player se sirve en
otro dominio, el snippet copiado del panel ya trae el host correcto. El panel
de Embeds enlaza estas guías desde el bloque "Instalar donde quieras".
Apéndice: límites conocidos
- Si el navegador del visitante suprime el referrer por completo (extensiones
o políticas estrictas), los eventos postMessage no se emiten — el iframe
necesita capturar el origen de tu página. El fallback es
data-on-eventoTreisaPlayer.on(callbacks del loader, no dependen del referrer). - Múltiples embeds de la misma key en una página: cada uno reproduce y
emite eventos; los eventos llevan
embedKeypero no distinguen instancia. - Videos verticales: usa
data-aspect="9/16"para evitar letterbox.