Saltar al contenido principal

Embed de campaña y ranking público

Esta guía es para desarrolladores web de marcas que quieren:

  1. incrustar una campaña de IncentIA (registro, acceso, subida de fotos) en su propia landing; y
  2. mostrar el ranking público de la campaña, leído como JSON.

{platform} es el host de IncentIA que te facilitamos (por ejemplo https://staging.incentia.app). {slug} es el identificador de la campaña (por ejemplo yatekomo-es).

1. Incrustar la campaña​

Pega una etiqueta donde quieras que aparezca la campaña:

<script src="{platform}/embed/landing.js"
data-slug="yatekomo-it"
data-lang="it"
data-height="600"></script>
AtributoObligatorioQué hace
data-slugsíSlug de la campaña. Sin él no se pinta nada.
data-langnoDos letras minúsculas (^[a-z]{2}$, p. ej. es, it). Cualquier otro valor se ignora.
data-heightnoAltura inicial del iframe en píxeles. Por defecto 600.
data-modenoform muestra solo el formulario de participación (sin cabecera ni secciones de marketing). Cualquier otro valor se ignora.
data-primarynoColor de marca del formulario, como #RRGGBB (^#[0-9a-fA-F]{6}$). Otro formato se descarta.
data-accentnoColor de acento, con el mismo formato que data-primary.

Qué hace el cargador:

  • Inserta un <iframe> justo antes de la etiqueta <script>, a todo el ancho y sin borde. Apunta a {platform}/landing/c/{slug}?embed=1, más &lang=, &compact=1, &primary= y &accent= si defines los atributos correspondientes. El host de la plataforma sale del src del propio script, así que la misma etiqueta sirve en staging y en producción.
  • El iframe lleva sandbox="allow-scripts allow-forms allow-same-origin allow-popups allow-popups-to-escape-sandbox", title="IncentIA" y loading="lazy".
  • La página de la campaña envía {type: "incentia:resize", height} a tu página cada vez que cambia la altura de su contenido. El cargador ajusta el iframe y no aparece barra de desplazamiento interna. Solo se aplican alturas numéricas positivas.
  • En modo embed la campaña oculta su propia cabecera y pie. La estructura de la página la pones tú.
  • Animaciones: si la landing usa el editor v2 con animaciones de entrada, funcionan dentro del iframe y se disparan cuando el bloque entra en la pantalla de tu página (el navegador mide la visibilidad con el viewport del documento padre), sin que cambies nada en el cargador. Los efectos al pasar el ratón también. Respetan "reducir movimiento" del visitante. Para comprobar tu página sin animaciones, añade ?motion=0 a la dirección del iframe (puedes probarlo abriendo {platform}/landing/c/{slug}?embed=1&motion=0). Con compact=1 (solo formulario) evita animar el formulario.

Idioma​

data-lang prevalece sobre el idioma guardado o del navegador del visitante. Solo se aplica si la campaña está configurada en ese idioma; si no, se usa el primer idioma de la campaña.

Consentimiento de cookies (opcional)​

Si tu web tiene su propio gestor de consentimiento, pasa la decisión del visitante al embed para no preguntarle dos veces:

window.IncentiaLandingEmbed.setConsent(consentObject);

Al cargarse, la página incrustada pide el consentimiento al cargador (incentia:cookie-consent:query). El cargador responde con incentia:cookie-consent:state solo a ese iframe. Si nunca llamas a setConsent, la página incrustada muestra su propio diálogo de consentimiento pasados unos 800 ms. Solo acepta consentimientos retransmitidos desde orígenes que hayamos autorizado (ver §3).

Qué ve el participante​

El embed muestra un flujo de cuenta con cuatro pantallas:

  • Registro: alias (3–30 caracteres: letras, dígitos, _, . y -), email, contraseña (dos veces) y aceptación de los términos (el enlace de términos se abre en una pestaña nueva).
  • Acceso.
  • Contraseña olvidada: envía un email con un enlace para restablecerla.
  • Inicio: tras acceder. Aquí el participante sube sus fotos.

Las reglas de subida se definen en cada campaña. Por ejemplo, en las campañas YaTeKomo:

  • Solo JPEG (.jpg / .jpeg) cuando la campaña lo exige. Otros formatos se rechazan antes de subirse.
  • Tamaño máximo en MB: lo fija la campaña y se muestra en pantalla. El tope de la plataforma es de unos 7,5 MB.
  • Número de lote cuando la campaña lo exige: texto libre de hasta 32 caracteres sin contar espacios. Se guarda en mayúsculas.

Los enlaces de restablecer contraseña del email abren {platform}/landing/c/{slug}/reset-password como página normal de nivel superior, no dentro de tu iframe. Tras fijar la nueva contraseña, el participante vuelve a tu landing y accede. La página de restablecimiento no redirige, porque no sabe qué página incrustó la campaña.

2. API del ranking público​

GET {platform}/api/public/campaign/{slug}/ranking

Anónima, sin clave API. Respuesta 200:

{
"total": 1342,
"top": [
{ "alias": "lucia_92", "participacion": 100 },
{ "alias": "marco.r", "participacion": 64 }
]
}
  • total: número de fotos válidas enviadas en la campaña. No cuentan las rechazadas, las duplicadas ni las de participantes bloqueados.
  • top: los N primeros participantes con alias (N se fija por campaña, de 1 a 50, por defecto 5), ordenados por número de envíos válidos. Los empates los gana quien subió antes.
  • participacion depende del modo de la campaña:
    • percentOfFirst: round(100 × envíos / envíos_del_primero), así que la primera entrada siempre es 100.
    • percentOfTotal: round(100 × envíos / total, 2), el porcentaje sobre todas las subidas contadas (10 de 100 → 10); decimal de hasta 2 cifras.
    • position: la posición, de 1 a N.
  • Nunca se devuelven identificadores, emails ni números de lote.

Comportamiento:

TemaDetalle
FrescuraEl resultado se guarda en caché 60 s. Las respuestas llevan Cache-Control: public, max-age=60. Consultar más de una vez por minuto no aporta nada.
CORSAccess-Control-Allow-Origin solo se envía si el Origin de la petición coincide exactamente con un origen autorizado. Devuelve ese origen, nunca *. Todas las respuestas llevan Vary: Origin.
CredencialesNunca se permiten. No envíes cookies (credentials: "omit", el valor por defecto de fetch entre orígenes).
PreflightNo hace falta. Un GET sin cabeceras personalizadas es una petición "simple". No añadas Authorization, Content-Type ni cabeceras X-*. (Si lo necesitas, OPTIONS responde 204 con las mismas cabeceras CORS.)
Desactivado / desconocido404 con {"error": "not_found"}. Cubre un slug desconocido, un ranking desactivado y una campaña en borrador, cancelada o fuera de sus fechas de inicio y fin (el ranking desaparece cuando termina la campaña).
Límite de peticionesVentana fija por IP de cliente y campaña (por defecto 100 peticiones/minuto), más un tope agregado por IP en todas las campañas (por defecto 60 peticiones/minuto). Al superar cualquiera recibes 429.

Ejemplo con fetch​

async function loadRanking() {
const res = await fetch('{platform}/api/public/campaign/yatekomo-es/ranking');
if (!res.ok) return null; // 404 = ranking desactivado; 429 = baja el ritmo
return res.json(); // { total, top: [{ alias, participacion }] }
}

Ejemplo en HTML estático​

<ol id="ranking"></ol>
<p>Total: <span id="ranking-total">–</span></p>
<script>
fetch('{platform}/api/public/campaign/yatekomo-it/ranking')
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (data) {
if (!data) return;
document.getElementById('ranking-total').textContent = data.total;
var list = document.getElementById('ranking');
data.top.forEach(function (e) {
var li = document.createElement('li');
li.textContent = e.alias + ' – ' + e.participacion; // textContent: los alias son texto del usuario
list.appendChild(li);
});
});
</script>

Pinta siempre alias como texto, nunca como HTML.

3. Qué tienes que enviarnos​

La lista de orígenes que incrustarán la campaña o consultarán el ranking (la usamos tanto para el CORS del ranking como para la retransmisión del consentimiento), uno por landing (ES, IT, hosts de staging o previsualización):

  • formato: https://host o https://host:puerto;
  • solo esquema y host, sin ruta ni barra final (https://www.example.it, no https://www.example.it/promo/);
  • www.example.it y example.it son orígenes distintos: envía los dos si se sirven ambos.

4. Solución de problemas​

SíntomaCausa probableQué hacer
Iframe en blanco o rechazadoLa Content-Security-Policy de tu página bloquea el host de la plataforma (script-src o frame-src/child-src), o un proxy o CMS inyecta X-Frame-Options: SAMEORIGIN o frame-ancestors en la respuesta del iframe.Añade {platform} a script-src y frame-src. Mira en la consola del navegador qué directiva se bloquea.
El iframe se queda en 600 px o tiene barra de desplazamientoSe copió el <script> sin cargar landing.js, o algún script bloquea los eventos message.Usa la etiqueta de §1 tal cual. Sube data-height como alternativa.
Error de CORS en el rankingTu origen exacto no está en la lista autorizada (www o sin www, puerto, http o https), o añadiste una cabecera personalizada que provoca un preflight.Envíanos el origen exacto (§3). Usa un GET simple.
El ranking devuelve 404Slug incorrecto, ranking sin activar o campaña no activa (antes del inicio o después del fin).Revisa el slug y pídenos que lo activemos.
Idioma incorrectoFalta data-lang, no son dos letras minúsculas o la campaña no está configurada en ese idioma.Usa data-lang="es" o "it".
El enlace de términos no hace nadaLos términos se abren en una pestaña nueva. Algunos navegadores o contenedores bloquean ventanas emergentes desde iframes con sandbox.Permite las ventanas emergentes en tu sitio y prueba en una pestaña normal del navegador.
Aparece el diálogo de consentimiento aunque el visitante ya eligióNo se llamó a setConsent, o se llamó después de que el iframe lo pidiera.Llama a IncentiaLandingEmbed.setConsent(...) en cuanto tu gestor de consentimiento resuelva.

5. Probar contra staging​

  • Cargador: https://staging.incentia.app/embed/landing.js
  • Campañas: yatekomo-es (castellano) y yatekomo-it (italiano)
<script src="https://staging.incentia.app/embed/landing.js" data-slug="yatekomo-es" data-lang="es"></script>
<script src="https://staging.incentia.app/embed/landing.js" data-slug="yatekomo-it" data-lang="it"></script>
curl -i -H "Origin: https://tu-host-de-pruebas.example" \
https://staging.incentia.app/api/public/campaign/yatekomo-es/ranking

Comprueba que aparecen HTTP 200, Vary: Origin, Cache-Control: public, max-age=60 y Access-Control-Allow-Origin: https://tu-host-de-pruebas.example. Esta última cabecera solo aparece cuando hemos añadido tu origen de pruebas. Los datos de staging se reinician sin aviso. Usa solo emails de prueba.