Embed Core
Purpose and Scope
Embed Core is the vanilla JavaScript runtime that makes a Cal Link appear inside another web page. It is the lowest-level embed package: framework integrations and snippets can depend on it, but it is responsible for the browser-side embed behavior itself. The package README describes it as the core script that embeds Cal Link on any webpage, regardless of framework, and points developers to JavaScript installation guidance and local examples for usage validation. In practice, use this page when you need to understand what the runtime owns before changing snippet, React, loader, or iframe behavior.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/index.ts, packages/embeds/embed-core/package.json
The core package should be treated as a browser runtime rather than a server-side library. Its package metadata publishes @calcom/embed-core with a built JavaScript entry at ./dist/embed/embed.js and TypeScript declarations at ./dist/index.d.ts, while the TypeScript source entry re-exports the SDK event surface and embed surface from ./src/sdk-event and ./src/embed. That export shape is intentionally small: consumers interact with the package through the shared embed API and event primitives, while implementation details stay behind the compiled distribution.
Sources: packages/embeds/embed-core/index.ts, packages/embeds/embed-core/package.json
Relevant Source Files
packages/embeds/embed-core/README.md- Reader-facing package documentation for usage, development, tests, production shipping, compatibility requirements for embedded pages, and known limitations.packages/embeds/embed-core/index.ts- Public TypeScript barrel for the package, re-exporting the SDK event and embed modules that make up the core API surface.packages/embeds/embed-core/package.json- Package contract for name, version, distribution files, build scripts, dev scripts, test scripts, linting, type checking, and publish-time environment behavior.
Runtime Responsibilities
Embed Core coordinates the parent-page experience around an embedded Cal booking page. The README calls out iframe-related responsibilities through its compatibility guidance: pages intended for embedding should define a main class on the element containing the page content, with no auto margins. That convention lets the iframe height adjust to visible content and establishes the click boundary used by modal behavior. This is an important contract between the host page, the embedded booking page, and the runtime, because incorrect layout markup can produce unnecessary scrolling or unexpected modal closing behavior.
Sources: packages/embeds/embed-core/README.md
The README also documents that getEmbedIframe and addEmbedListeners work as a team, but with an explicit limitation: they support opening an embed on a fresh load, while opening an embed, closing it, and then opening another embed is not supported yet. That note is more than a test warning. It describes a runtime lifecycle constraint that developers should preserve when debugging modal reuse, iframe state, or event listener registration. If you are changing close/reopen behavior, first decide whether you are maintaining the documented fresh-load assumption or deliberately implementing the unsupported reopening path.
Sources: packages/embeds/embed-core/README.md
Public Package Contract
| Contract item | Source-backed value | Why it matters |
|---|---|---|
| Package name | @calcom/embed-core | Identifies the npm package consumed by other embed tooling. |
| Version in source | 1.5.3 | Shows the package is versioned independently for distribution. |
| Description | This is the vanilla JS core script that embeds Cal Link | Defines the package’s scope in package metadata. |
| Runtime entry | ./dist/embed/embed.js | Browser-facing built artifact declared as main. |
| Type declarations | ./dist/index.d.ts | TypeScript consumers use generated declarations from the build. |
| Published files | dist | Only built output is included in the package files list. |
| Source exports | ./src/sdk-event, ./src/embed | The public TypeScript barrel exposes SDK events and embed behavior. |
The build and distribution scripts reinforce that the package is compiled before consumption. The build script removes dist, sets NEXT_PUBLIC_EMBED_FINGER_PRINT from the current Git commit, sets NEXT_PUBLIC_EMBED_VERSION from the package version, then runs the internal build pipeline. That internal pipeline generates Tailwind output, runs Vite, emits declaration files into dist, and copies the web app’s public embed assets into the package distribution. For production hosting, the README states that dist/embed.umd.js should be made servable at http://cal.com/embed.js, which explains why build output paths and public URLs are part of the runtime contract.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/package.json
Development Flow
Local development is centered on the package’s Vite server and generated styles. The README says to run yarn dev, then test the embed in the automatically opened page at http://localhost:3100/embed/. It also identifies a dedicated routing playground at http://localhost:3100/embed/routing-playground.html for prerendering behavior with a headless router demo. The package scripts show what that command does: it generates Tailwind CSS, watches Tailwind changes, builds in development mode, and serves Vite on port 3100 with a strict port and host binding.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/package.json
Common commands for working on the package are:
yarn workspace @calcom/embed-core dev
yarn workspace @calcom/embed-core dev-no-open
yarn workspace @calcom/embed-core dev-https
yarn workspace @calcom/embed-core build
yarn workspace @calcom/embed-core type-check
yarn workspace @calcom/embed-core lintUse the HTTPS and no-auto-open variants when reproducing host-site behavior that differs from the default local page. The package scripts also expose dev-real for a direct Vite dev server on port 3100, separate from the generated Tailwind-and-build workflow. The README’s DX note says hot reload does not work with CSS files in the way this package uses Vite, so style-related changes should be verified carefully rather than assuming the browser has reloaded the correct CSS artifact. When working with embed visual behavior, rebuilding can be part of the verification loop.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/package.json
Testing and Verification
Embed Core has its own Playwright-oriented test scripts, but they depend on a running Cal web application and the embed-core development server. The README instructs developers to ensure the main app is already running on port 3000, start the embed-core server on port 3100 with yarn dev, and then run yarn embed-tests-quick from another terminal. The package metadata maps embed-tests-quick to QUICK=true yarn embed-tests, and embed-tests runs Playwright using playwright/config/playwright.config.ts. This means test failures can come from either the embed runtime, the web app, or the required two-server setup.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/package.json
# terminal 1: main Cal web app on port 3000
# example from the monorepo workflow, if available in your environment
yarn dx
# terminal 2: embed-core development server on port 3100
yarn workspace @calcom/embed-core dev
# terminal 3: quick embed test run
yarn workspace @calcom/embed-core embed-tests-quickSnapshot maintenance is called out as a known automation concern: the README notes that automation tests use booking-page snapshots containing the current month, which requires regenerating snapshots every month. The package includes embed-tests-update-snapshots:ci, which runs the quick tests with snapshot updates. Treat snapshot changes cautiously. A calendar snapshot can change because of time-dependent UI rather than a runtime regression, but the same tests also exercise lifecycle assumptions such as iframe creation, listeners, and fresh-load behavior.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/package.json
Implementation Constraints and Known Gaps
The README’s known-bugs section is useful design input for future changes. It lists unsupported browsers, a desired booking shell for applying common embed changes, accessibility and UI/UX issues, loader customization gaps, branding questions, automation-test improvements, CSS bundling details, iframe-to-parent log forwarding, embed error tracking, color scheme simplification, and release compatibility risks between embed-iframe.js and embed.js. These are not random TODOs; they describe areas where the core runtime crosses product UI, browser compatibility, packaging, and debuggability boundaries.
Sources: packages/embeds/embed-core/README.md
When changing Embed Core, start with the public contract and lifecycle assumptions before editing behavior. Confirm whether your change affects the exported SDK event or embed modules, the generated dist artifacts, the required main layout convention, or the two-server Playwright workflow. Then verify locally through the 3100 demo page and the quick embed tests. If your work touches package publishing, use the package scripts as the source of truth for build inputs, fingerprinting, version injection, and publish-time environment variables.
Sources: packages/embeds/embed-core/README.md, packages/embeds/embed-core/index.ts, packages/embeds/embed-core/package.json
Related Pages and Next Steps
After understanding this package, read the embeds overview to see how core relates to snippet and React integrations, then read the embed snippet and React embed pages if your change starts outside the vanilla runtime. For runtime changes, keep a browser demo, the main web app, and the quick Playwright tests available so you can validate parent-page behavior, iframe behavior, and package output together. For release work, inspect the publishing and loaders page because the core package’s built files, public embed URL, and compatibility with iframe assets are part of the release surface.