Skip to main content
Em uma VSL, você quer que a oferta (botões/preços) só apareça depois do pitch — por exemplo, aos 40 minutos de vídeo. Isso é o delay de oferta: a oferta começa escondida e é revelada quando o vídeo atinge X segundos, com rolagem automática até ela.
Todo esse código vai dentro de um elemento HTML no canvas, junto com o player VTurb — é o lugar que roda HTML + JS custom sem filtro. Veja HTML e scripts.

Como funciona (3 camadas)

Usamos camadas redundantes de propósito: se o player falhar, o backup garante que a oferta apareça mesmo assim.
CamadaMecanismoO que faz
1VTurb displayHiddenElementsAPI nativa do player: revela .offer-wrapper quando o vídeo passa do delay. persist: true grava cookie → em recarga já mostra a oferta.
2Backup (MutationObserver + poll + timeupdate + timeout)O “cérebro”: detecta a revelação por qualquer via, e tem um timeout de segurança que revela de qualquer jeito.
3localStorageEm visitas seguintes, revela na hora sem esperar o vídeo.
O delay é contado em tempo de vídeo assistido, não no relógio — 2510 = 2510 s de reprodução (~41 min).

Passo a passo

1

1. Adicione as classes que escondem

No <style> do seu bloco (com escopo no wrapper):
.esconder, .hide { display: none !important; }
2

2. Marque a seção da oferta

Envolva toda a oferta numa seção com id="offer-section" e as classes esconder hide offer-wrapper. Coloque um <div id="scrolldown"></div> como primeiro filho (alvo da rolagem):
<section id="offer-section" class="esconder hide offer-wrapper">
  <div id="scrolldown"></div>
  <!-- cards, preços, botões, garantia... toda a oferta aqui -->
</section>
São dois alvos: a classe offer-wrapper é o que a Camada 1 revela; o id="offer-section" é o que a Camada 2 controla. A seção precisa das duas.
3

3. Coloque o player VTurb + a Camada 1

Logo após o <script> do player, adicione a Camada 1. Troque o delay e o ID do player:
<!-- player VTurb -->
<vturb-smartplayer id="vid-SEU-PLAYER" style="display:block;margin:0 auto;width:100%;max-width:400px"></vturb-smartplayer>
<script src="https://scripts.converteai.net/SUA-CONTA/players/SEU-VIDEO/v4/player.js" async></script>

<!-- Camada 1: API nativa do VTurb -->
<script>
(function () {
  var delaySeconds = SEU_DELAY_EM_SEGUNDOS;
  var player = document.getElementById("vid-SEU-PLAYER") || document.querySelector("vturb-smartplayer");
  if (!player) return;
  player.addEventListener("player:ready", function () {
    if (typeof player.displayHiddenElements === "function") {
      player.displayHiddenElements(delaySeconds, [".offer-wrapper"], { persist: true });
    }
  });
})();
</script>
4

4. Adicione a Camada 2 (o backup) no fim do bloco

Cole este script no final do elemento HTML (antes de fechar o wrapper). Troque SEU_DELAY_EM_SEGUNDOS e vid-SEU-PLAYER — os mesmos valores da Camada 1:
<script>
(function () {
  var SECONDS_TO_DISPLAY = SEU_DELAY_EM_SEGUNDOS;
  var alreadyDisplayedKey = "offer_revealed_v4_" + SECONDS_TO_DISPLAY;
  var revealDone = false;
  var PLAYER_ID = "vid-SEU-PLAYER";
  var OFFER_ID = "offer-section";

  function unlockOfferDom() {
    var el = document.getElementById(OFFER_ID);
    if (!el) return;
    el.classList.remove("esconder", "hide");
    el.style.removeProperty("display");
    el.style.removeProperty("visibility");
  }
  function offerLooksVisible() {
    var w = document.getElementById(OFFER_ID);
    if (!w) return false;
    var cs = window.getComputedStyle(w);
    if (cs.display === "none" || cs.visibility === "hidden" || Number(cs.opacity) === 0) return false;
    return w.getBoundingClientRect().height > 0;
  }
  function afterReveal() {
    if (revealDone) return;
    revealDone = true;
    unlockOfferDom();
    try { localStorage.setItem(alreadyDisplayedKey, "true"); } catch (e) {}
    var sd = document.getElementById("scrolldown");
    if (sd) {
      setTimeout(function () {
        try { sd.scrollIntoView({ behavior: "smooth", block: "start" }); } catch (e) {}
      }, 400);
    }
    try { document.dispatchEvent(new Event("offerRevealed")); } catch (e) {}
  }
  function init() {
    try {
      if (localStorage.getItem(alreadyDisplayedKey) === "true") {
        unlockOfferDom(); setTimeout(afterReveal, 0); return;
      }
    } catch (e0) {}
    var wrap = document.getElementById(OFFER_ID);
    if (!wrap) return;

    var obs = new MutationObserver(function () {
      if (offerLooksVisible()) { obs.disconnect(); afterReveal(); }
    });
    try { obs.observe(wrap, { attributes: true, attributeFilter: ["class", "style"] }); } catch (eObs) {}

    var pollVis = setInterval(function () {
      if (revealDone) { clearInterval(pollVis); return; }
      if (offerLooksVisible()) { clearInterval(pollVis); afterReveal(); }
    }, 350);

    var spTry = 0;
    function bindSmartplayer() {
      if (revealDone) return;
      try {
        if (typeof smartplayer !== "undefined" && smartplayer.instances && smartplayer.instances.length) {
          var host = document.getElementById(PLAYER_ID);
          var inst = null;
          for (var i = 0; i < smartplayer.instances.length; i++) {
            var cand = smartplayer.instances[i];
            if (!cand) continue;
            try { if (cand.host === host || cand.el === host) { inst = cand; break; } } catch (e1) {}
          }
          if (!inst) inst = smartplayer.instances[0];
          inst.on("timeupdate", function () {
            if (revealDone) return;
            if (inst.smartAutoPlay) return;
            var t = inst.video && typeof inst.video.currentTime === "number" ? inst.video.currentTime : 0;
            if (t >= SECONDS_TO_DISPLAY) afterReveal();
          });
          return;
        }
      } catch (e2) {}
      if (++spTry < 200) setTimeout(bindSmartplayer, 250);
    }
    bindSmartplayer();

    setTimeout(function () { if (!revealDone) afterReveal(); }, (SECONDS_TO_DISPLAY + 90) * 1000);
  }
  if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
  else init();
})();
</script>
5

5. (Opcional) Countdown após revelar

Se a oferta tem um contador de escassez (.countdown), este script o anima quando a oferta aparece:
<script>
document.addEventListener("offerRevealed", function () {
  var root = document.getElementById("offer-section");
  if (!root) return;
  var nodes = root.querySelectorAll(".countdown");
  for (var i = 0; i < nodes.length; i++) {
    (function (el) {
      var m = el.textContent.trim().match(/\d+/);
      if (!m) return;
      var val = parseInt(m[0], 10);
      var timer = setInterval(function () {
        if (val > 48) { val = Math.max(val - 6, 48); el.textContent = String(val); }
        else { clearInterval(timer); }
      }, 8000);
    })(nodes[i]);
  }
});
</script>

Os 3 valores que precisam bater

Estes valores têm que ser idênticos nas Camadas 1 e 2:
  • SEU_DELAY_EM_SEGUNDOS — o mesmo número nas duas camadas.
  • vid-SEU-PLAYER — o id do <vturb-smartplayer>.
  • A seção da oferta com id="offer-section" e a classe offer-wrapper.

Delay por tempo puro (sem vídeo)

Se a página não tem VSL e você só quer revelar após X segundos de relógio:
<script>
setTimeout(function () {
  var el = document.getElementById("offer-section");
  if (el) el.classList.remove("esconder", "hide");
}, 10000); // 10000 ms = 10 s
</script>

Testar antes de subir

1

Use delay 10 primeiro

Coloque 10 no lugar do delay real e publique um teste — não espere 40 minutos para validar.
2

Simule uma primeira visita (console do navegador)

localStorage.removeItem('offer_revealed_v4_10');
location.reload();
3

Confira se a oferta apareceu e rolou

Depois de ~10 s de vídeo, a oferta deve aparecer e a página rolar até ela. Depois, troque o delay para o valor real.
A chave do localStorage é específica do delay (offer_revealed_v4_10 para o teste, offer_revealed_v4_2510 para produção) — trocar o delay já invalida a persistência antiga.

Erros comuns

SintomaCausaCorreção
Oferta aparece antes do vídeoFaltou .esconder/.hide na seção ou o delayMarque a seção e ligue as 3 camadas
Oferta nunca apareceID do player errado ou Camada 2 ausenteConfira PLAYER_ID e cole a Camada 2
Oferta some ao recarregarO persist/localStorage já resolve; confira que os valores batem
Não rolou até a ofertaFaltou <div id="scrolldown"> como primeiro filhoAdicione o #scrolldown
Nada aparece / o player não carregaPlayer e delay em lugares separadosMantenha player + oferta + delay no mesmo elemento HTML