How to add iframes in flipbooks using Google Tag Manager

The simplest way to overlay third‑party content in your flipbooks via GTM

Table of contents

Overview

If you want to display third‑party content (chatbots, forms, banners) over your Flipsnack flipbooks, use Google Tag Manager (GTM) to inject a lightweight overlay. You’ll manage everything from GTM without editing the flipbook itself.

Important: Overlays appear on top of the flipbook player, not inside the flipbook pages. They can show automatically (banner) or on demand (button → modal).

How to create a Custom HTML tag in GTM

Before pasting any of the code examples, you’ll need to create a Custom HTML tag inside your Google Tag Manager container.

Screenshot 2025-08-27 at 13.25.14-mh

  1. Log in to Google Tag Manager and select the container used for your flipbooks.

  2. In the left-hand menu, click Tags.

  3. Click New → name your tag (for example, Flipbook iframe overlay).

  4. Click Tag Configuration → choose Custom HTML.

  5. Paste the code snippet provided in this guide.

  6. Scroll down to Triggering → click + to add a new trigger.

    • Choose Page View.

    • Select DOM Ready (recommended).

    • (Optional) Add a filter so it only fires on your flipbook URLs (e.g., Page URL contains flipsnack.com).

  7. Click Save.

  8. When you’re ready, click Submit and Publish in GTM to apply your changes.

Tip: Always preview your container changes with GTM’s Preview mode before publishing. This lets you confirm the overlay works correctly on your flipbook link.

Step-by-step instructions

Quick start (2 minutes): Paste‑and‑go overlay

Simplest path: Copy this into a Custom HTML tag in GTM, set the trigger to DOM Ready, and change only YOUR_FORM_URL.

<script>
(function(){
  // Change just this:
  var YOUR_FORM_URL = 'https://yourform.typeform.com/to/abc123'; // ⬅️ only change this

  try { if (window.self !== window.top) return; } catch(e) { return; }
  if (window.__fsOverlayOnce) return; window.__fsOverlayOnce = true;

  function inject(){
    if (document.getElementById('fs-quick-overlay')) return;
    var box = document.createElement('div');
    box.id = 'fs-quick-overlay';
    box.style.cssText = 'position:fixed;bottom:12px;right:12px;width:300px;height:400px;'+
                        'background:#fff;box-shadow:0 0 10px rgba(0,0,0,.3);z-index:2147483647;';

    var iframe = document.createElement('iframe');
  iframe.src = YOUR_FORM_URL;
    iframe.style.cssText = 'width:100%;height:100%;border:none;';

    var close = document.createElement('button');
    close.type='button';close.textContent='×';
    close.setAttribute('aria-label','Close');
    close.style.cssText='position:absolute;top:6px;right:6px;background:#000;color:#fff;border:none;'+
                        'cursor:pointer;padding:4px 8px;font-size:14px;line-height:1;';
    close.addEventListener('click', function(){ box.remove(); });

    box.appendChild(iframe); box.appendChild(close);
    (document.body||document.documentElement).appendChild(box);
  }
  if (document.readyState==='loading') document.addEventListener('DOMContentLoaded', inject); else inject();
})();
</script>

That’s it. No other edits needed. To move the box, change bottom/right values; to resize, change width/height.

Optional (more control): Overlay with simple settings

Paste this one-file overlay script in GTM (Custom HTML, trigger: DOM Ready)

Why this is easy: All the settings you might change live in the CONFIG block at the top.

<script>
(function(){
  // ================== SIMPLE CONFIG ==================
  var CONFIG = {
    formUrl: 'https://yourform.typeform.com/to/abc123', // <— change to your URL
    size:   { width: '300px', height: '400px' },        // <— change size
    pos:    { bottom: '10px', right: '10px' },          // <— change position
    zIndex: 2147483647                                  // stays above player
  };
  // ==================================================

  // 1) Run only in top window (avoid inner iframes)
  try { if (window.self !== window.top) return; } catch(e) { return; }

  // 2) Prevent duplicates
  if (window.__fsOverlayInjected) return; 
  window.__fsOverlayInjected = true;

  function css(obj){ return Object.keys(obj).map(function(k){return k+':'+obj[k]}).join(';'); }

  function inject(){
    if (document.getElementById('fs-iframe-overlay')) return;

    var wrap = document.createElement('div');
    wrap.id = 'fs-iframe-overlay';
    wrap.setAttribute('role','dialog');
    wrap.style.cssText = [
      'position:fixed',
      'background:#fff',
      'border:none',
      'box-shadow:0 0 10px rgba(0,0,0,0.3)',
      'width:'+CONFIG.size.width,
      'height:'+CONFIG.size.height,
      'z-index:'+CONFIG.zIndex,
      css(CONFIG.pos)
    ].join(';');

    var iframe = document.createElement('iframe');
    iframe.src = CONFIG.formUrl;
    iframe.title = 'Embedded form';
    iframe.style.cssText = 'width:100%;height:100%;border:none;';

    var btn = document.createElement('button');
    btn.type = 'button';
    btn.setAttribute('aria-label','Close overlay');
    btn.textContent = '×';
    btn.style.cssText = 'position:absolute;top:6px;right:6px;background:#000;color:#fff;border:none;cursor:pointer;padding:4px 8px;font-size:14px;line-height:1;';
    btn.addEventListener('click', function(){ wrap.remove(); });

    wrap.appendChild(iframe);
    wrap.appendChild(btn);
    (document.body || document.documentElement).appendChild(wrap);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', inject);
  } else {
    inject();
  }
})();
</script>

GTM settings

  • Tag type: Custom HTML

  • Trigger: Page View → DOM Ready (fallback: Window Loaded)

  • Filter: Limit to your flipbook URLs (e.g., Page URL contains your flipbook path)

  • Firing options (if available): Once per page


Google Tag Manager Custom HTML tag showing a simple CONFIG block for the overlay

Optional: Add iframe as a modal pop-up

Prefer a modal that opens on demand? Choose one of the two easy options below.

Auto-open modal (script-only)

Paste as Custom HTML in GTM (trigger: DOM Ready). Change only the CONFIG.formUrl if needed.

<script>
(function(){
  var CONFIG = { formUrl: 'https://yourform.typeform.com/to/abc123' };

  try { if (window.self !== window.top) return; } catch(e) { return; }
  if (window.__fsPopupInjected) return; window.__fsPopupInjected = true;

  function create(){
    if (document.getElementById('fs-popup')) return;
    var wrap = document.createElement('div');
    wrap.id = 'fs-popup';
    wrap.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;'+
                         'background:rgba(0,0,0,0.5);z-index:2147483647;display:flex;justify-content:center;align-items:center;';

    var inner = document.createElement('div');
    inner.style.cssText = 'position:relative;width:400px;height:500px;background:#fff;padding:10px;';

    var iframe = document.createElement('iframe');
    iframe.src = CONFIG.formUrl;
    iframe.style.cssText = 'width:100%;height:100%;border:none;';

    var btn = document.createElement('button');
    btn.type = 'button';
    btn.setAttribute('aria-label','Close popup');
    btn.textContent = '×';
    btn.style.cssText = 'position:absolute;top:10px;right:10px;background:#000;color:#fff;border:none;cursor:pointer;padding:4px 8px;font-size:16px;line-height:1;';
    btn.addEventListener('click', function(){ wrap.remove(); });

    inner.appendChild(iframe);
    inner.appendChild(btn);
    wrap.appendChild(inner);
    (document.body || document.documentElement).appendChild(wrap);
  }

  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', create); else create();
})();
</script>

Add a persistent top banner (recommended)

Use this option when you want a clear, non-intrusive way to let readers open a form. The banner sits at the top of the flipbook player and includes a CTA that launches the modal. No edits are needed inside the flipbook.

GTM → Custom HTML (trigger: DOM Ready)

<script>
(function(){
  var CONFIG = {
    formUrl: 'https://yourform.typeform.com/to/abc123', // change to your URL
    bannerText: 'Need help? Open form',                 // CTA label
    bannerHeight: 64,                                   // px
    zIndex: 2147483647
  };

  try { if (!/\.flipsnack\.com$/i.test(location.hostname)) return; } catch(e) { return; }
  if (window.__fsBannerOnce) return; window.__fsBannerOnce = true;

  function ensureModal(){
    if (document.getElementById('fs-popup')) return;
    var wrap=document.createElement('div');
    wrap.id='fs-popup';
    wrap.style.cssText='display:none;position:fixed;top:0;left:0;width:100%;height:100%;'+
      'background:rgba(0,0,0,0.5);z-index:'+CONFIG.zIndex+';justify-content:center;align-items:center;';
    var inner=document.createElement('div');
    inner.style.cssText='position:relative;width:420px;height:560px;background:#fff;padding:10px;';
    var iframe=document.createElement('iframe');
    iframe.src=CONFIG.formUrl; iframe.style.cssText='width:100%;height:100%;border:none;';
    var btn=document.createElement('button');
    btn.type='button'; btn.setAttribute('aria-label','Close'); btn.textContent='×';
    btn.style.cssText='position:absolute;top:10px;right:10px;background:#000;color:#fff;border:none;cursor:pointer;padding:4px 8px;font-size:16px;line-height:1;';
    btn.addEventListener('click', function(){ wrap.style.display='none'; });
    inner.appendChild(iframe); inner.appendChild(btn); wrap.appendChild(inner);
    (document.body||document.documentElement).appendChild(wrap);
  }

  function showModal(){ ensureModal(); var el=document.getElementById('fs-popup'); if(el) el.style.display='flex'; }

  function injectBanner(){
    if (document.getElementById('fs-top-banner')) return;
    var bar=document.createElement('div');
    bar.id='fs-top-banner';
    bar.style.cssText='position:fixed;left:0;right:0;top:0;height:'+CONFIG.bannerHeight+'px;'+
      'display:flex;align-items:center;justify-content:center;background:#111;color:#fff;'+
      'font:500 14px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;z-index:'+CONFIG.zIndex+';';

    var cta=document.createElement('button');
    cta.type='button'; cta.textContent=CONFIG.bannerText;
    cta.style.cssText='margin-left:8px;padding:8px 12px;border:none;border-radius:6px;background:#00AEEF;color:#fff;cursor:pointer;';
    cta.addEventListener('click', showModal);

    var close=document.createElement('button');
    close.type='button'; close.textContent='×'; close.setAttribute('aria-label','Dismiss banner');
    close.style.cssText='position:absolute;right:10px;top:50%;transform:translateY(-50%);background:transparent;color:#fff;border:none;cursor:pointer;font-size:18px;';
    close.addEventListener('click', function(){ bar.remove(); });

    bar.appendChild(cta); bar.appendChild(close);
    (document.body||document.documentElement).appendChild(bar);
  }

  function init(){ injectBanner(); ensureModal(); }
  if (document.readyState==='loading') document.addEventListener('DOMContentLoaded', init); else init();
})();
</script>

Additional tips / FAQs

Can I target different flipbooks with different forms? Yes. In GTM, use URL-based triggers and duplicate the tag with different CONFIG.formUrl values.

Can I delay the overlay? Yes. Wrap the inject()/create() call in setTimeout(function(){ ... }, 8000) (for 8s).

Can I track interactions inside the iframe? Only if you control the iframe source and add tracking code there.

Common use-cases

  • Chat widgets (Intercom, Zendesk)

  • Feedback or survey forms (Typeform, Google Forms)

  • Campaign banners and offers

  • Lead capture and conversions

Troubleshooting

Overlay/modals don’t show

  • Confirm GTM publishes and the trigger = DOM Ready.

  • Check that the tag fires only on your flipbook URLs.

  • Open DevTools → Elements to see whether the node exists.

It loads twice

  • Keep the top-window guard and global flags included above (window.self===window.top, __fsOverlayInjected, __fsPopupInjected).

  • Optional in GTM: create a JS – IsInIframe variable and add it as a Trigger Exception.

Overlay covers player controls

  • Tweak size/position in CONFIG (e.g., bigger bottom/right values).

Iframe refused to connect

  • The source may set X-Frame-Options/CSP to block embedding. Try another provider or host your own page.

Next steps

Useful resources

Need expert support?

Our team is here to help. Connect with our team experts or message us via the in-app chat for a personalized assistance.