Skip to main content
Scripts

Calendly provides booking pages and embeddable scheduling widgets. Its booking flow can render inline, in a popup, or behind a floating badge button.

Use useScriptCalendly() for popup and badge widgets. For an inline booking flow, use the headless <ScriptCalendlyInlineWidget> component.

Calendly

View source

Nuxt Config Setup

Add this to your nuxt.config.ts to load Calendly globally. Alternatively you can use the useScriptCalendly composable for more control.

export default defineNuxtConfig({
  scripts: {
    registry: {
      calendly: {
        trigger: 'onNuxtReady',
      }
    }
  }
})

This config automatically enables first-party mode (bundle + proxy). See below to customise.

useScriptCalendly()

The useScriptCalendly composable lets you have fine-grain control over when and how Calendly is loaded on your site.

const { proxy } = useScriptCalendly()

Please follow the Registry Scripts guide to learn more about advanced usage.

First-Party Mode: Privacy Focused Proxy

No extra config needed. The script is bundled from your domain (faster loads, no extra DNS lookup) and runtime requests are reverse-proxied through your server with automatic anonymisation (user IPs stay hidden from Calendly, works with ad blockers). Learn more.

Mode
Bundle Proxy Partytown
Privacy
User IP addresses are anonymised. Other request data passes through.
export default defineNuxtConfig({
  scripts: {
    // ✅ First-party mode: bundled + proxied
    registry: {
      calendly: {
        trigger: 'onNuxtReady',
      },
    },
  },
})

Example

Using Calendly in a component with the proxy to send events .

<script setup lang="ts">
const { proxy } = useScriptCalendly()

// noop in development, ssr
// just works in production, client
function handleAction() {
  // use proxy methods here
}
</script>

<template>
  <div>
    <button @click="handleAction">
      Send Event
    </button>
  </div>
</template>

The generated schema also lists url, prefill, utm, and pageSettings, but the current composable does not apply those top-level values to a widget. Pass them to an initializer as shown below, or use <ScriptCalendlyInlineWidget>.

Defaults:

  • Trigger: onNuxtReady Direct composable calls load the script when the Nuxt app is ready. The inline component uses an element trigger instead.
  • Stylesheet: Inline The widget stylesheet (and its close-icon SVG) is inlined on first use, so rendering it does not request those assets from assets.calendly.com.

The asset proxy covers assets.calendly.com only. The booking iframe still connects directly to calendly.com.

Use the proxy for void calls. Use onLoaded when you need the loaded Calendly global or a stable DOM reference.

const { proxy } = useScriptCalendly()
function openBooking() {
  proxy.Calendly.initPopupWidget({
    url: 'https://calendly.com/your-name/30min',
  })
}

<ScriptCalendlyInlineWidget>

The component mounts Calendly's inline booking flow inside a host element you control.

It waits until the host element enters the viewport before loading the widget script. The default element trigger is 'visible'.

<script setup lang="ts">
const ready = ref(false)
</script>

<template>
  <ScriptCalendlyInlineWidget
    url="https://calendly.com/your-name/30min"
    @ready="ready = true"
  />
</template>

Above-the-fold loading

For an above-the-fold widget, set above-the-fold and switch the trigger to hydration. This also adds a preconnect to calendly.com.

<ScriptCalendlyInlineWidget
  url="https://calendly.com/your-name/30min"
  above-the-fold
  trigger="onNuxtReady"
/>

Prefill, UTM, and page settings

<ScriptCalendlyInlineWidget
  url="https://calendly.com/your-name/30min"
  :prefill="{ name: 'Ada Lovelace', email: '[email protected]' }"
  :utm="{ utmSource: 'website', utmMedium: 'cta', utmCampaign: 'launch' }"
  :page-settings="{ hideEventTypeDetails: true, hideGdprBanner: true }"
/>

Slots

The component exposes loading, awaitingLoad, and error slots for placeholder UX while the script trigger waits or the script load fails. The default loading slot renders an accessible spinner.

Popup and badge widgets have no host element. Open them through the composable:

const { proxy } = useScriptCalendly()
function open() {
  proxy.Calendly.initPopupWidget({
    url: 'https://calendly.com/your-name/30min',
  })
}

Prefilling invitee details and UTM parameters

All four widget initializers (initInlineWidget, initPopupWidget, initBadgeWidget, initPopupWidgetWithText) accept prefill and utm options to prepopulate the booking form and tag the booking with marketing attribution. Calendly's UTM guide covers the JavaScript option names and the supported embed types.

<script setup lang="ts">
const { proxy } = useScriptCalendly()

function bookFromCampaign(user: { name: string, email: string }) {
  proxy.Calendly.initPopupWidget({
    url: 'https://calendly.com/your-name/30min',
    prefill: {
      name: user.name,
      email: user.email,
    },
    utm: {
      utmSource: 'website',
      utmMedium: 'cta',
      utmCampaign: 'launch',
    },
  })
}
</script>
urlstring

The Calendly event URL to embed. Required for inline, popup, and badge widgets when called via the composable.

prefillobject

Pre-fill invitee fields on the booking form.

utmobject

UTM parameters appended to the booking URL for marketing attribution.

pageSettingsobject

Theme and layout overrides applied to the booking page.

parentElementstring

CSS selector for the element that hosts the inline widget. Required when the widget is initialised inline; the element should have a minimum height of around 700px so the booking iframe is fully visible.