Calendly
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.
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.
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:
onNuxtReadyDirect 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
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>
urlstringThe Calendly event URL to embed. Required for inline, popup, and badge widgets when called via the composable.
prefillobjectPre-fill invitee fields on the booking form.
utmobjectUTM parameters appended to the booking URL for marketing attribution.
pageSettingsobjectTheme and layout overrides applied to the booking page.
parentElementstringCSS 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.