calcom/cal.com
embeds
Purpose
packages/embeds/* is the family of packages that lets external sites embed a Cal.diy booking flow without iframing the marketing site themselves. There are three published packages:
@calcom/embed-core— the JavaScript runtime that handles iframe creation, routing, modal/floating button modes, and message passing@calcom/embed-react— a React wrapper aroundembed-core@calcom/embed-snippet— a tiny snippet that publishers paste into their site to bootstrapembed-core
Together they implement the public cal('init', ...) API that lives on embed.cal.com.
Directory layout
packages/embeds/
├── embed-core/
│ ├── src/
│ │ ├── EmbedElement.ts / EmbedElement.test.ts # Base custom element
│ │ ├── FloatingButton/
│ │ ├── Inline/
│ │ ├── ModalBox/
│ │ ├── embed-iframe/ # The iframe-side runtime
│ │ ├── embed-iframe.ts
│ │ ├── embed.css
│ │ ├── constants.ts
│ │ └── __tests__/
│ ├── playwright/
│ ├── public/
│ ├── package.json
│ └── ...
├── embed-react/ # React component wrapping embed-core
│ ├── src/ # <Cal /> + <CalProvider /> components
│ ├── package.json
│ └── ...
├── embed-snippet/ # Tiny snippet — generates the cal() global function
│ ├── src/
│ ├── package.json
│ └── ...
├── README.md # Architecture overview
├── LIFECYCLE.md # Detailed lifecycle for each embed mode
├── embed-handshake.mermaid # Handshake sequence (Mermaid source)
├── embed-message-protocol.mermaid
├── inline-embed-lifecycle.mermaid
├── modal-embed-lifecycle.mermaid
├── modal-prerendering-flow.mermaid
└── vite.config.jsThe mermaid files are checked into the repo as the canonical lifecycle diagrams; they are referenced from the package READMEs.
Modes
| Mode | Surface | Component |
|---|---|---|
| Inline | An in-page iframe stretched to the host element | EmbedElement + Inline/ |
| Modal | A full-screen modal with backdrop | ModalBox/ |
| Floating button | A persistent button that opens the modal on click | FloatingButton/ |
| Pre-render | Pre-renders the iframe behind the scenes for instant display | modal-prerendering-flow.mermaid |
How it works
sequenceDiagram
participant Host as Host site
participant Snippet as embed-snippet
participant Core as embed-core
participant Iframe as Cal.diy iframe (apps/web)
Host->>Snippet: <script src="/wikis/cal-com/packages/embed.js">
Snippet->>Host: window.cal = ...
Host->>Core: cal("init", "user/event")
Core->>Iframe: Insert iframe + postMessage handshake
Iframe-->>Core: ack + slot picker rendered
Host->>Core: cal("on", "bookingSuccessful", cb)
Iframe->>Core: postMessage("bookingSuccessful", payload)
Core->>Host: invoke registered callbackembed-iframe.ts runs inside the embedded page (loaded from apps/web). It listens for postMessage commands from embed-core and reports lifecycle events (loaded, slotPicked, bookingSuccessful, etc.). The full message protocol is documented in embed-message-protocol.mermaid.
Integration points
apps/web/modules/embed/— server-side helpers that detect when a request is coming from an embed and adjust SSR accordingly (apps/web/app/WithEmbedSSR.tsx).packages/embeds/embed-core/playwright/— the embed Playwright suite, run via.github/workflows/e2e-embed.yml.packages/platform/atoms— atoms internally use a similar iframe approach for the React<Booker />-as-embed-on-third-party-sites story.
Publishing
The root package.json has dedicated scripts:
yarn withEmbedPublishEnv workspace @calcom/embed-core build
yarn workspaces foreach --from="@calcom/embed*" npm publish --access=publicThe withEmbedPublishEnv wrapper sets NEXT_PUBLIC_EMBED_LIB_URL=https://app.cal.com/embed/embed.js and NEXT_PUBLIC_WEBAPP_URL=https://app.cal.com so the published bundle points at production.
Entry points for modification
- Add a new public command: edit
packages/embeds/embed-core/src/embed.tsand update the message protocol diagram +LIFECYCLE.md. - New mode: subclass
EmbedElementand add a directory undersrc/(mirror theInline/andModalBox/examples). Wire it into the dispatch inembed.ts. - iFrame-side change: edit
embed-iframe.tsandembed-iframe/. Verify with the Playwright suite (yarn e2e:embed).
Related pages
- Web → embed module — where the iframe-side wires in
- platform — atoms reuse the embed concept for React consumers
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.