Interactive Ticketing · Client Reference

Purchase Interface Embed Guide

The recommended way to place your Interactive Ticketing purchase page on your own website — one snippet that behaves consistently across WordPress, Squarespace, Shopify, Webflow, and most other website builders.

Note: This guide applies to Purchase Interface 2.0 and higher only. The interface version is set per event in the Dashboard (your event → General tab → Interface Version); a 1.x event behaves differently and is not covered here.

Our first recommendation is still linking out to our secure.interactiveticketing.com purchase page over embedding

Embedding keeps visitors on your site, but the purchase page always works best on its own secure domain: every payment wallet is available, sessions can't be blocked by browser privacy settings, and the page sizes itself. A styled Buy Now button or link that opens the Interactive Ticketing Purchase Page in a new tab is the right choice when:

  • Your builder sandboxes embeds (Wix) or strips the code you paste.
  • Your audience skews heavily mobile — a full-window checkout is easier to complete on a phone (see Mobile & iOS below).
  • You want Apple Pay and other secure.interactiveticketing.com domain-dependent features to work fully.

Before you start: get your purchase link

In the Dashboard, open your event, click the tab for the purchase form you want to embed, then More Options → Get Purchase Link. That link is what replaces SECURE.INTERACTIVETICKETINGURL in the snippets below.

Each purchase form has its own link. An event can have several (for example a main form, a reserved-seating form, and a parking form) — make sure you copy the link for the form you mean to embed.

Handy URL options

These work on the purchase link itself, so they work in your embed's src and in any Buy Now link or marketing link. Combine them with &.

  • ?promo=CODE — applies a promo code for the buyer as the page opens (for a promo you've created under the event's Promo Discount Codes). Handy for campaign links.
  • ?slot_date=YYYY-MM-DD — pre-selects that date on the calendar for date-specific and timed tickets.

Example: https://secure.interactiveticketing.com/2.0/XXXXXX/?promo=EARLYBIRD&slot_date=2026-12-10. The embed snippets below keep these options intact when they restore a buyer's step after a refresh.

Tracking conversions from an embed

  • Analytics that fire inside the purchase page: set Google Analytics 4 or Google Tag Manager under your event's General tab → Tracking & Conversion Plugins. They run inside the purchase page for every buyer, however the page is embedded or linked.
  • Conversions on your own domain: on the form's tab, More Options → Add External Thank You Page opens a page on your site after a completed order, with the order details available to your own pixels and tags. It opens in a new tab, so pop-up blockers can suppress it — test it in the browsers your buyers use.
  • Linking out with GA4: add secure.interactiveticketing.com to GA4's cross-domain list (Admin → Data Streams → Configure tag settings → Configure your domains) so a buyer's visit continues as one session when they click through.
  • Expect some attribution loss inside an embed: analytics cookies set inside the frame are third-party, so returning-visitor matching is weaker there. The Dashboard's own Source and Link Sharing reports are unaffected.

The recommended embed code

Paste this where your site builder accepts custom HTML. Replace SECURE.INTERACTIVETICKETINGURL with your purchase link (the version path can differ — 2.0, 2.1, and so on).

<style>
  .interactive-ticketing-frame {
    display: block;
    width: 100%;
    max-width: 100%;
    height: 2200px;
    border: 0;
    margin: 0;
  }
</style>

<iframe class="interactive-ticketing-frame"
        title="Buy Tickets"
        src="SECURE.INTERACTIVETICKETINGURL"
        allow="web-share; clipboard-write"
        loading="eager"></iframe>

<script>
  (function () {
    var frames = document.querySelectorAll('.interactive-ticketing-frame');
    if (!frames.length) return;

    // Stop iOS Safari from zooming in when a form field is tapped
    var vp = document.querySelector('meta[name="viewport"]');
    if (vp && !/maximum-scale/.test(vp.content)) {
      vp.setAttribute('content', vp.content + ', maximum-scale=1');
    } else if (!vp) {
      vp = document.createElement('meta');
      vp.name = 'viewport';
      vp.content = 'width=device-width, initial-scale=1, maximum-scale=1';
      document.head.appendChild(vp);
    }

    // Everything below runs once per embed, so several forms on one
    // page each behave independently
    Array.prototype.forEach.call(frames, function (frame) {
      var base = frame.getAttribute('src');
      var origin = new URL(base, location.href).origin;
      var q = base.indexOf('?');
      var path = q > -1 ? base.slice(0, q) : base;
      var query = q > -1 ? base.slice(q) : '';
      var key = 'it-route:' + path;

      // Refresh-restore: if the buyer reloads the page, start the
      // purchase page at the step they were on instead of the beginning
      try {
        var saved = sessionStorage.getItem(key);
        if (saved && saved !== '/') {
          frame.src = path.replace(/\/+$/, '') + saved + query;
        }
      } catch (e) {}

      // Keep the frame at least as tall as the visible screen. The purchase
      // page's pop-ups (upsell offers, the donation prompt) size themselves
      // to the frame, so on a short step like the cart a frame shorter than
      // the screen would cut a pop-up off - especially on phones.
      var lastHeight = 0;
      function applyHeight() {
        if (!lastHeight) return;
        frame.style.height = Math.max(lastHeight + 60, window.innerHeight) + 'px';
      }
      window.addEventListener('resize', applyHeight);

      window.addEventListener('message', function (e) {
        if (e.origin !== origin || e.source !== frame.contentWindow) return;
        var data;
        try { data = JSON.parse(e.data); } catch (err) { return; }
        if (!data) return;

        // Auto-resize the frame to the purchase page's real height on
        // every step (no blank space below short steps, no inner scrolling)
        if (data.height) {
          lastHeight = data.height;
          applyHeight();
        }

        // Remember the buyer's current step (see refresh-restore above)
        if (typeof data.route === 'string') {
          try { sessionStorage.setItem(key, data.route); } catch (err) {}
        }

        // When the step changes, bring the top of the form to the top of
        // the screen (unless it is already there), so the new step - and any
        // pop-up it opens - is fully in view
        if (data.scrollIntoView === true) {
          var top = frame.getBoundingClientRect().top;
          if (top < 0 || top > 120) {
            frame.scrollIntoView({ block: 'start', behavior: 'smooth' });
          }
        }
      });
    });
  })();
</script>

Why each line is there

  • width: 100% (not 100vw) 100vw measures the full viewport including the scrollbar, which causes a small horizontal scroll on desktop, and it misbehaves inside builders that place content in positioned or transformed containers. 100% fills whatever column your builder gives the embed and never overflows.
  • height: 2200px This is the fallback height, used only until the auto-resize script takes over. 2200px comfortably fits most forms, so if the script is ever stripped by your site builder, nothing is cut off. Avoid scrolling="no" — if the form ever exceeds the height, customers with it would have no way to reach the checkout button.
  • display: block; border: 0; margin: 0 Iframes are inline elements by default, which adds a small mystery gap beneath them, and some browsers still draw a legacy border. These three lines zero all of that out. No negative margins — those fight the builder's own layout.
  • allow="web-share; clipboard-write" Browsers deny these two capabilities to embedded pages unless your page delegates them. This line is what makes the purchase page's share button work in the embed: web-share lets it open the native iOS/Android share sheet, and clipboard-write lets the copy-link fallback work everywhere else. Without it, tapping share inside the embed does nothing.
  • title="Buy Tickets" Screen readers announce this when a visitor reaches the frame. Required for accessibility compliance and costs nothing.
  • loading="eager" Ticket sales are the point of the page — never lazy-load the purchase form. Some builders inject loading="lazy" by default; stating eager prevents that.
  • The viewport fix (first part of the script) On iPhones, Safari zooms the whole page in whenever a visitor taps a form field whose text is smaller than 16px — and it doesn't zoom back out. Adding maximum-scale=1 to your page's viewport tag stops that auto-zoom. Visitors can still pinch-zoom manually (iOS ignores the cap for deliberate zooming), so accessibility is preserved. The script edits your existing viewport tag rather than replacing it, so your builder's other settings survive.
  • Auto-resize (the height messages) The purchase page broadcasts its real height to the page embedding it on every step. The script listens for those messages (from the purchase page's domain only) and sets the frame's height to match, so short steps have no blank space below them and long steps never need inner scrolling. The frame is also never made shorter than the visible screen: the purchase page's pop-ups (upsell offers, the donation prompt) size themselves to the frame, so on a short step like the cart a frame shorter than the screen would cut a pop-up off — most noticeably on phones. If the message can't be delivered, the frame simply stays at the fallback height.
  • Refresh-restore (the route messages) The purchase page also tells the embedding page which step the buyer is on. The script remembers it for the current browser tab and, if the buyer reloads the page, starts the purchase page at that step instead of at the beginning. Their cart and details already survive a reload on their own; this just puts them back where they were. The memory is per tab and clears when the tab closes, and your page's URL is never modified.
  • Scroll to the form on step changes When the buyer advances a step, the script brings the top of the form to the top of the screen, so the new step — and any pop-up it opens, like an upsell offer on the cart — is fully in view instead of leaving them staring at the bottom of the previous step. It only scrolls when the form isn't already at the top, and the purchase page only asks for it on step changes, so it never jumps on first load.
  • Works with more than one embed on a page Every part of the script runs once per frame, and each frame only listens to messages from its own purchase page. If you embed two forms on one page (say a main form and a parking form), each sizes and restores itself independently.

Full-width "breakout" variant

If your theme confines content to a narrow column and you want the ticket form to span the whole browser window, this variant breaks it out. Use it only when the page's content column is horizontally centered — in themes with sidebars or off-center layouts it will shove the frame off-screen.

<style>
  .interactive-ticketing-frame {
    display: block;
    width: 100vw;
    max-width: 100vw;
    height: 2200px;
    border: 0;
    margin-left: calc(50% - 50vw);
  }
</style>

<iframe class="interactive-ticketing-frame"
        title="Buy Tickets"
        src="SECURE.INTERACTIVETICKETINGURL"
        allow="web-share; clipboard-write"
        loading="eager"></iframe>

<script>
  (function () {
    var frames = document.querySelectorAll('.interactive-ticketing-frame');
    if (!frames.length) return;

    // Stop iOS Safari from zooming in when a form field is tapped
    var vp = document.querySelector('meta[name="viewport"]');
    if (vp && !/maximum-scale/.test(vp.content)) {
      vp.setAttribute('content', vp.content + ', maximum-scale=1');
    } else if (!vp) {
      vp = document.createElement('meta');
      vp.name = 'viewport';
      vp.content = 'width=device-width, initial-scale=1, maximum-scale=1';
      document.head.appendChild(vp);
    }

    // Everything below runs once per embed, so several forms on one
    // page each behave independently
    Array.prototype.forEach.call(frames, function (frame) {
      var base = frame.getAttribute('src');
      var origin = new URL(base, location.href).origin;
      var q = base.indexOf('?');
      var path = q > -1 ? base.slice(0, q) : base;
      var query = q > -1 ? base.slice(q) : '';
      var key = 'it-route:' + path;

      // Refresh-restore: if the buyer reloads the page, start the
      // purchase page at the step they were on instead of the beginning
      try {
        var saved = sessionStorage.getItem(key);
        if (saved && saved !== '/') {
          frame.src = path.replace(/\/+$/, '') + saved + query;
        }
      } catch (e) {}

      // Size the frame to the exact usable page width. CSS 100vw includes
      // the scrollbar, which causes a small left-right scroll; clientWidth
      // does not, so this removes the horizontal scrollbar entirely.
      function setWidth() {
        var w = document.documentElement.clientWidth;
        frame.style.width = w + 'px';
        frame.style.maxWidth = w + 'px';
        frame.style.marginLeft = 'calc(50% - ' + (w / 2) + 'px)';
      }
      setWidth();
      window.addEventListener('resize', setWidth);

      // Keep the frame at least as tall as the visible screen. The purchase
      // page's pop-ups (upsell offers, the donation prompt) size themselves
      // to the frame, so on a short step like the cart a frame shorter than
      // the screen would cut a pop-up off - especially on phones.
      var lastHeight = 0;
      function applyHeight() {
        if (!lastHeight) return;
        frame.style.height = Math.max(lastHeight + 60, window.innerHeight) + 'px';
      }
      window.addEventListener('resize', applyHeight);

      window.addEventListener('message', function (e) {
        if (e.origin !== origin || e.source !== frame.contentWindow) return;
        var data;
        try { data = JSON.parse(e.data); } catch (err) { return; }
        if (!data) return;

        // Auto-resize the frame to the purchase page's real height on
        // every step (no blank space below short steps, no inner scrolling)
        if (data.height) {
          lastHeight = data.height;
          applyHeight();
          // A height change can add or remove the page's vertical
          // scrollbar, which changes the usable width, and the window
          // 'resize' event does NOT fire for that - so re-measure now.
          requestAnimationFrame(setWidth);
        }

        // Remember the buyer's current step (see refresh-restore above)
        if (typeof data.route === 'string') {
          try { sessionStorage.setItem(key, data.route); } catch (err) {}
        }

        // When the step changes, bring the top of the form to the top of
        // the screen (unless it is already there), so the new step - and any
        // pop-up it opens - is fully in view
        if (data.scrollIntoView === true) {
          var top = frame.getBoundingClientRect().top;
          if (top < 0 || top > 120) {
            frame.scrollIntoView({ block: 'start', behavior: 'smooth' });
          }
        }
      });
    });
  })();
</script>

Use this instead of the standard snippet, not alongside it. Beyond the CSS, this variant's script also sizes the frame to the exact usable page width: CSS 100vw alone includes the scrollbar's width, which adds a small left-right scroll on desktop — the script measures the true width instead, eliminating it (the CSS acts as the no-script fallback). Because a taller step can make the page's vertical scrollbar appear (which itself narrows the usable width), the script re-measures the width every time the height changes, not only on window resize. The standard 100% snippet is still the safer default; reach for this only when the design demands edge-to-edge, and only on themes whose content column is horizontally centered.

The breakout controls the frame. The layout inside the purchase page is a Dashboard setting: on the form's tab, Customize Interface offers full-width layouts (for example "Modern – Full Width"). For a true edge-to-edge look, set both.

Mobile & iOS

Most ticket buyers are on phones, so a few iPhone-specific points are worth knowing before you choose between embedding and linking out.

  • Apple Pay only appears when the purchase page is opened directly, and only in Safari. It does not appear inside an embed. Google Pay works inside the embed.
  • Layout. The snippet's viewport fix prevents the iOS input-zoom problem. The horizontal-scroll protections in the breakout variant are desktop concerns; iOS uses overlay scrollbars that don't affect layout.

Recommendation: if Apple Pay matters to your audience, link out. If you embed, test the entire flow on a real iPhone — including in a Private tab, which applies Safari's strictest privacy rules — all the way through to the confirmation screen.

Notes per website provider

ProviderWhere the code goes & what to watch
WordPress (self-hosted)Add a Custom HTML block in the page editor and paste the full snippet. Everything works, script included.
WordPress.comSame Custom HTML block, but plans below Business strip <script> tags — the iframe and CSS will work, the iOS zoom fix and auto-resize won't. Upgrade, or accept the fallback height.
SquarespaceUse a Code Block. Scripts in code blocks require the Business plan or higher; on Personal plans, keep just the <style> and <iframe> parts.
ShopifyAdd a Custom Liquid section (or custom HTML section in older themes) and paste the snippet as-is.
WebflowUse an Embed component. Embeds only render on the published site, not in the designer preview.
WixWix's "Embed HTML" widget wraps your code in a second sandboxed frame on a Wix domain, which blocks the payment permissions and breaks sizing. Don't embed on Wix — use a Buy Tickets button that opens the secure page directly (see our first recommendation above).
Weebly / GoDaddyUse the Embed Code element. Test on a phone after publishing; if the script was stripped, the zoom fix and auto-resize won't apply.

Quick do & don't

DoTest the published page on a real phone: tap the promo-code field (no zoom), add a ticket, refresh once (you should return to the same step), and confirm the bottom of the form isn't cut off.
DoUse Make Test Purchase while the event is in Test status to walk your embed through checkout before going live.
DoIncrease the fallback height value rather than enabling inner scrolling if your builder strips the script.
Don'tUse scrolling="no" — it can strand customers above the checkout button.
Don'tLazy-load the frame or place it inside tabs/accordions that delay loading — payment libraries initialize on load.
Don'tNest the embed inside another iframe (page-builder "HTML widgets" sometimes do this invisibly — Wix, some GoDaddy elements). If the address bar of the widget preview shows a builder domain, link out instead.