Ad & Integrations > Scheduling

Calendly

How to embed Calendly into your SuperFunnel pages or quizzes.

Overview

You can embed a Calendly booking widget directly inside a SuperFunnel page or quiz step using a Custom Code snippet. This lets visitors schedule a call without leaving your funnel.

Data entered only in Calendly is not captured by SuperFunnel

The Calendly widget is an embedded iframe, so anything a visitor types into Calendly (name, email, answers to Calendly's questions) happens outside the SuperFunnel app and is not recorded as lead data.

The recommended pattern below fixes this: collect the details in SuperFunnel fields, then pass them to Calendly so the visitor doesn't retype anything — and SuperFunnel keeps the lead.

Plan requirements

The embed, prefill, auto-resize, and auto-advance all work on any Calendly plan (including Free). Color customization (background_color, text_color, primary_color) requires Calendly's Standard plan or above — on the Free plan those parameters silently fail and the widget may render blank.

To retain lead data, collect name, email, and any other details in SuperFunnel form fields earlier in the funnel. The embed script reads them with SuperFunnel's getValue() helper and appends them to the Calendly URL as prefill parameters. The visitor sees their info already filled in and only has to pick a time.

Add this as a Body custom code snippet (or place it in an HTML block on the step). Replace the data-url with your own Calendly link, and replace the SuperFunnel field names (fullName, email, phone) with your own field names.

<div class="calendly-inline-widget"
  data-url="https://calendly.com/{your-username}/{30min}?hide_gdpr_banner=1"
  style="min-width:320px; height:700px;">
</div>

<script>
  (function() {
    var widget = stepElement.querySelector('.calendly-inline-widget');
    if (!widget) return;

    // 1. Read answers already collected in SuperFunnel.
    //    getValue('fieldName') returns the value of a SuperFunnel field.
    function val(field) {
      try {
        return typeof getValue === 'function' ? (getValue(field) || '') : '';
      } catch (e) {
        return '';
      }
    }

    // Map SuperFunnel fields → Calendly prefill params.
    // name + email are built-in; a1, a2... map to Calendly's custom
    // questions in the order they appear on your event.
    var prefill = {
      name: val('fullName'),
      email: val('email'),
      a1: val('phone')
    };

    // 2. Append the non-empty values to the Calendly URL (URL-encoded)
    //    BEFORE the widget loads, so they show up prefilled.
    var base = widget.getAttribute('data-url');
    var sep = base.indexOf('?') === -1 ? '?' : '&';
    var qs = Object.keys(prefill)
      .filter(function(k) { return prefill[k]; })
      .map(function(k) { return k + '=' + encodeURIComponent(prefill[k]); })
      .join('&');
    if (qs) widget.setAttribute('data-url', base + sep + qs);

    // 3. Auto-resize the widget and (in a quiz) auto-advance after booking.
    function handleMessage(e) {
      if (!e.data || typeof e.data.event !== 'string') return;

      if (e.data.event === 'calendly.page_height') {
        var h = e.data.payload && e.data.payload.height;
        if (h && h > 0) widget.style.height = h + 'px';
      }

      if (e.data.event === 'calendly.event_scheduled') {
        setTimeout(function() {
          nextStep();
        }, 1500);
      }
    }
    window.addEventListener('message', handleMessage);

    // 4. Inject Calendly's script AFTER the data-url is finalized.
    setTimeout(function() {
      if (!document.querySelector('script[src="https://assets.calendly.com/assets/external/widget.js"]')) {
        var script = document.createElement('script');
        script.src = 'https://assets.calendly.com/assets/external/widget.js';
        script.async = true;
        document.body.appendChild(script);
      }
    }, 500);

    return function() {
      window.removeEventListener('message', handleMessage);
    };
  })();
</script>

Field names and question order must match

  • The string you pass to getValue('...') must match the field name configured on your SuperFunnel field (the data-sf-field value).
  • name and email are Calendly's built-in invitee fields. If your event collects first and last name separately, use first_name and last_name instead.
  • Custom Calendly questions are labelled a1a10, in the order they appear on your Calendly event. Confirm the order matches what you're passing.

Booking without losing the lead

Even with prefill, the booking confirmation itself still happens in Calendly. To act on confirmed bookings inside SuperFunnel, combine this with the auto-advance step below, or send Calendly bookings to your CRM via Calendly's own integrations.

What not to do

Don't paste Calendly's default embed code

The copy-paste snippet Calendly gives you (and any <script src="..."> or <link> tag dropped straight into your HTML) won't work inside SuperFunnel. Load Calendly from an inline <script> function.

A few things the pattern above takes care of for you — keep them if you adapt it:

  • getValue('fieldName') reads a value the visitor entered into a SuperFunnel field — this is how the embed prefills Calendly with data they already gave you.
  • stepElement refers to the current step. Scoping querySelector to it (rather than the whole page) avoids picking up a widget from another step.
  • The short delay before loading Calendly's script lets the step finish rendering, and makes sure the prefilled link is set first.

Theming the widget

Calendly supports color customization via URL query parameters. Append them to your Calendly link (alongside any prefill params):

https://calendly.com/{your-username}/{30min}?hide_gdpr_banner=1&background_color=ffffff&text_color=1a1a1a&primary_color=4f6ef7

hide_gdpr_banner=1 hides Calendly's GDPR cookie banner.

Make sure text_color contrasts with your page

If you're not sure which text color to use, omit text_color entirely and let Calendly use its default.

Auto-advance after booking (quizzes)

Calendly fires a calendly.event_scheduled postMessage when a visitor completes a booking. The pattern above listens for it and calls nextStep() to move the quiz forward automatically. The 1500ms delay lets Calendly show its confirmation screen briefly before the quiz advances.

Editor preview

Prefill, auto-resize, and auto-advance may not all be visible in the SuperFunnel editor preview, which renders steps in a constrained iframe. Test on the published page.

Full step example

A complete quiz step: SuperFunnel fields capture the lead, then the embed prefills Calendly with those values.

<div>
  <!-- Intro banner -->
  <div style="border-radius: 16px; padding: 24px; margin-bottom: 32px; display: flex; align-items: flex-start; gap: 16px; background: #f5f6fa; border: 1px solid #e3e6ef;">
    <div style="width: 52px; height: 52px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; background: #4f6ef7; color: #fff;">📅</div>
    <p style="font-size: 14px; line-height: 1.6; margin: 0; color: #4a4f63;">You're almost done! Add your details and pick a time that works for you.</p>
  </div>

  <h2 style="font-size: 26px; font-weight: 700; margin: 0 0 6px; color: #1a1a1a;">Schedule your consultation</h2>

  <!-- SuperFunnel fields: these are what SuperFunnel records as the lead -->
  <input data-sf-field="fullName" data-sf-required="true" placeholder="Full name"
    style="width:100%; padding:12px 14px; margin-bottom:12px; border:1px solid #e3e6ef; border-radius:10px; font-size:15px; color:#1a1a1a;" />
  <input data-sf-field="email" data-sf-type="email" data-sf-required="true" placeholder="Email"
    style="width:100%; padding:12px 14px; margin-bottom:24px; border:1px solid #e3e6ef; border-radius:10px; font-size:15px; color:#1a1a1a;" />

  <!-- Calendly widget, prefilled from the fields above -->
  <div class="calendly-inline-widget"
    data-url="https://calendly.com/your-username/30min?hide_gdpr_banner=1&primary_color=4f6ef7"
    style="min-width:320px; height:700px;">
  </div>

  <script>
    (function() {
      var widget = stepElement.querySelector('.calendly-inline-widget');
      if (!widget) return;

      function val(field) {
        try {
          return typeof getValue === 'function' ? (getValue(field) || '') : '';
        } catch (e) {
          return '';
        }
      }

      var prefill = {
        name: val('fullName'),
        email: val('email')
      };

      var base = widget.getAttribute('data-url');
      var sep = base.indexOf('?') === -1 ? '?' : '&';
      var qs = Object.keys(prefill)
        .filter(function(k) { return prefill[k]; })
        .map(function(k) { return k + '=' + encodeURIComponent(prefill[k]); })
        .join('&');
      if (qs) widget.setAttribute('data-url', base + sep + qs);

      function handleMessage(e) {
        if (!e.data || typeof e.data.event !== 'string') return;

        if (e.data.event === 'calendly.page_height') {
          var h = e.data.payload && e.data.payload.height;
          if (h && h > 0) widget.style.height = h + 'px';
        }

        if (e.data.event === 'calendly.event_scheduled') {
          setTimeout(function() {
            nextStep();
          }, 1500);
        }
      }
      window.addEventListener('message', handleMessage);

      setTimeout(function() {
        if (!document.querySelector('script[src="https://assets.calendly.com/assets/external/widget.js"]')) {
          var script = document.createElement('script');
          script.src = 'https://assets.calendly.com/assets/external/widget.js';
          script.async = true;
          document.body.appendChild(script);
        }
      }, 500);

      return function() {
        window.removeEventListener('message', handleMessage);
      };
    })();
  </script>
</div>

Summary

Embed Calendly with the inline <script> pattern, but always capture the lead in SuperFunnel fields first — then prefill Calendly with getValue() so the visitor doesn't retype and SuperFunnel keeps the data. Pick colors that contrast with your page (color customization needs Calendly's Standard plan), and in a quiz let the widget auto-resize and advance the moment a booking is confirmed.