npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@calemly/sdk

v0.1.2

Published

React SDK for Calemly booking widgets

Readme

Calemly React SDK (@calemly/sdk)

@calemly/sdk embeds Calemly booking directly into React apps with the same multi-step widget flow used by Calemly:

  • event selection
  • slot picking
  • guest confirmation
  • conflict resolution
  • custom form fields
  • optional payment checkout
  • booking success

The package is built for production use with idempotent booking submits, short-lived signed widget token support, and graceful handling for conflict/rate-limit/offline states.

Installation

npm install @calemly/sdk

Import styles once in your app entrypoint:

import '@calemly/sdk/styles.css';

Quick Start

import '@calemly/sdk/styles.css';
import { SchedulerWidget } from '@calemly/sdk';

export default function BookingPage() {
  return (
    <SchedulerWidget
      apiBaseUrl="https://your-api.example.com/api"
      embedKey="your_embed_key"
      mode="inline"
      theme="light"
    />
  );
}

Modal Embed

<SchedulerWidget
  apiBaseUrl="https://your-api.example.com/api"
  embedKey="your_embed_key"
  mode="modal"
  ctaLabel="Book a call"
/>

Event Slug Mode (No Embed Key)

<SchedulerWidget
  apiBaseUrl="https://your-api.example.com/api"
  eventSlug="intro-call"
  org="acme-inc"
/>

Provider + Hook Composition

Use provider mode when you need custom layouts around Calemly components.

import {
  SchedulerProvider,
  SlotPicker,
  BookingForm,
  BookingSuccess,
  useBooking,
} from '@calemly/sdk';

function BookingLayout() {
  const { step, steps, eventType, selectedSlot, confirmedBooking, userTimezone, goBack } = useBooking();

  if (step === steps.SELECT_TIME) {
    return <SlotPicker />;
  }

  if (step === steps.CONFIRM) {
    return (
      <BookingForm
        eventType={eventType}
        slot={selectedSlot}
        userTimezone={userTimezone}
        onBack={goBack}
      />
    );
  }

  if (step === steps.SUCCESS) {
    return <BookingSuccess booking={confirmedBooking} eventType={eventType} userTimezone={userTimezone} />;
  }

  return null;
}

export default function App() {
  return (
    <SchedulerProvider
      apiBaseUrl="https://your-api.example.com/api"
      embedKey="your_embed_key"
      theme="system"
      stripePublishableKey="pk_live_xxx"
    >
      <BookingLayout />
    </SchedulerProvider>
  );
}

Exports

  • SchedulerWidget
  • SchedulerProvider
  • useBooking
  • BOOKING_STEPS
  • SlotPicker
  • BookingForm
  • BookingSuccess
  • CustomFormRenderer
  • validateFormAnswers
  • ConflictResolver
  • PaymentCheckout

Core Props

SchedulerWidget / SchedulerProvider

  • apiBaseUrl (required): Calemly API base URL (example: https://api.example.com/api)
  • embedKey: public embed key for widget embeds
  • eventSlug: direct event slug mode
  • org: optional org id/slug for slug mode
  • mode: inline | modal
  • theme: light | dark | system
  • timezone: override invitee timezone
  • embedOrigin: explicit embed origin override
  • autoSignedWidgetToken: auto-fetch signed token from backend (default true)
  • tokenProvider: custom server token callback (recommended)
  • stripePublishableKey: Stripe key for paid booking flows
  • cacheTtlMs: slot cache TTL
  • slotWindowDays: availability window

Callbacks

  • onBeforeBook(payload, context)
  • onBookingSuccess(booking, context)
  • onBookingError(error, context)

Example:

<SchedulerWidget
  apiBaseUrl="https://your-api.example.com/api"
  embedKey="your_embed_key"
  onBeforeBook={async (payload) => payload}
  onBookingSuccess={(booking) => {
    console.log('Booked:', booking.id);
  }}
  onBookingError={(error) => {
    console.error(error.code, error.message);
  }}
/>

Security and Token Mode

Recommended production setup: issue signed widget tokens from your server and pass them via tokenProvider.

<SchedulerWidget
  apiBaseUrl="https://your-api.example.com/api"
  embedKey="your_embed_key"
  tokenProvider={async ({ guestData, slot, eventType }) => {
    const response = await fetch('/api/booking-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ guestData, slot, eventType }),
    });

    if (!response.ok) {
      throw new Error('Failed to fetch booking token');
    }

    return response.json();
  }}
/>

Expected token shape:

{
  "token": "signed_widget_token_here",
  "source": "widget",
  "source_client": "embed-widget-v2",
  "source_details": {
    "widget_id": "..."
  }
}

If tokenProvider is omitted and embedKey is provided, the SDK calls POST /embed/public/widget-token.

Booking Behavior Built In

  • idempotent request metadata (client_request_id)
  • slot conflict handling with alternatives
  • conflict suggestion UI for re-selecting time
  • template reuse (Book same as last time)
  • optional pre-booking brief acknowledgements (brief_ack)
  • optional custom dynamic form rendering/validation
  • optional paid event checkout (Stripe and PayPal)
  • PayPal return/capture completion handled in provider state
  • rate limit guidance (429 + Retry-After)
  • offline-safe error messages

Payment Notes

For paid events (requires_payment, payment_enabled, price_cents > 0), booking form can launch payment checkout.

  • Stripe: initialize with stripePublishableKey
  • PayPal: SDK creates order, redirects to approval, then auto-captures and finalizes booking when user returns with PayPal query params

If Stripe key is not set, checkout warns and cannot confirm card payment.

API Contract Used by SDK

  • GET /embed/public/event-types
  • POST /embed/public/widget-token
  • GET /bookings/public/event/:slug
  • GET /bookings/public/slots
  • GET /bookings/public/recent-templates
  • GET /bookings/auto-suggest
  • GET /bookings/suggestions
  • POST /bookings/public/preferences
  • DELETE /bookings/public/preferences
  • POST /bookings/public
  • GET /billing/public/event-payment/:eventTypeId
  • POST /billing/public/create-payment-intent
  • POST /billing/public/create-paypal-order
  • POST /billing/public/capture-paypal-order

Theming and Responsiveness

  • supports light, dark, and system
  • mobile-first layout in widget/form/conflict/payment flows
  • Tailwind-based SDK stylesheet emitted to dist/index.css
  • SDK styles are isolated under a .calemly-sdk scope to prevent host app CSS collisions

Local Development

From calemlysdk/:

npm install
npm run dev

Build:

npm run build

Test:

npm test

Package dry run:

npm pack --dry-run

GitHub Workflows

Repository includes SDK-specific workflows:

  • .github/workflows/sdk-ci.yml
    • runs on every push/PR/manual dispatch
    • runs SDK install, build, tests, package dry-run, and runtime dependency audit
  • .github/workflows/sdk-publish.yml
    • supports manual publish dry-runs (workflow_dispatch)
    • publishes on tag push (sdk-v* or v*)
    • validates tag/package version alignment before publish
    • publishes with npm provenance and creates GitHub Releases automatically

Publishing @calemly/sdk

Required repository setup

  1. Add NPM_TOKEN in GitHub repository secrets:
    • Settings -> Secrets and variables -> Actions -> New repository secret
  2. Use an npm token with publish access for the package scope.
  3. Ensure GitHub Actions permissions allow release creation (contents: write).

Recommended release flow (used by this repo)

  1. Confirm package.json version is correct (example: 0.1.0).
  2. Run SDK Publish manually with dry_run: true.
  3. After dry-run success, create and push tag sdk-v0.1.0.
  4. Tag push triggers live publish + GitHub Release creation.

Command example

git tag sdk-v0.1.0
git push origin sdk-v0.1.0

Troubleshooting

  • Missing scheduler setup: pass embedKey or eventSlug.
  • No slots shown: verify event type availability and timezone payload.
  • Payment form not loading: set stripePublishableKey and ensure backend billing routes are enabled.
  • Conflict errors: expected under race conditions; pick one of suggested alternatives and retry.
  • Styles look different in another app: import @calemly/sdk/styles.css once at app entry and avoid CSS pipelines that strip package CSS.