Add a booking widget to any website
Embed real-time scheduling on your site with three lines of code. No iframe. Your styles, your fonts, your brand.
<!-- Works on any website -->
<script src="https://cdn.astrocal.dev/widget.js"></script>
<div id="booking"></div>
<script>
Astrocal.open({
eventTypeId: 'evt_abc123',
mode: 'inline',
target: '#booking'
})
</script>How the widget works
Widget loads
The script fetches your event type configuration and available time slots from the Astrocal API. No server-side code required on your end.
Visitor picks a slot
The widget renders a calendar with real-time availability pulled from your connected Google Calendar. Visitors choose a date, time, and fill in their details.
Booking confirmed
The booking is created via the API. Calendar invites go out, confirmation emails send, webhooks fire to your backend, and your onSuccess callback runs.
Set up your booking widget in minutes
Install the widget
Add one script tag to your site, or install @astrocal/widget via npm. No build step required for the script tag route.
<script src="https://cdn.astrocal.dev/widget.js"></script>Create an event type
Define duration, availability windows, and buffer times. The API returns an event type ID you'll pass to the widget.
curl -X POST https://api.astrocal.dev/v1/event-types \
-H "Authorization: Bearer ak_live_..." \
-d '{"name": "30 Min Call", "duration_minutes": 30}'Render the widget
Call Astrocal.open() with your event type ID and a target element. The widget handles availability, time zones, and booking creation.
Astrocal.open({
eventTypeId: 'evt_abc123',
mode: 'inline',
target: '#booking'
})Go live
Bookings sync to your calendar, confirmation emails go out, and webhooks fire to your backend. Nothing else to configure.
Why teams choose the Astrocal widget
Not an iframe
The widget renders in a Shadow DOM container on your page. Customize it to match your brand via CSS custom properties.
Full theme control
Pass a theme object to override primary colour, background, border radius, and font family. Or configure the widget's appearance via the theme object and CSS custom properties.
Real-time availability
Slots reflect your actual Google Calendar. No stale data, no double-bookings. Only genuinely free times are shown.
Payments built in
Stripe is integrated. Clients pay at the point of booking, deposit or full amount. No redirect to a separate checkout page.
onSuccess callback
When a booking is confirmed, your JavaScript gets called with the full booking object. Redirect, update your UI, or fire analytics.
Three integration paths
Script tag for any website. npm package for bundled apps. React component for component-based UIs. Same API across all three.
API endpoints
/v1/availabilityCheck available time slots for an event type over a date range{
"slots": [
{
"start": "2026-03-28T09:00:00Z",
"end": "2026-03-28T09:30:00Z"
},
{
"start": "2026-03-28T09:30:00Z",
"end": "2026-03-28T10:00:00Z"
},
{
"start": "2026-03-28T10:00:00Z",
"end": "2026-03-28T10:30:00Z"
}
]
}/v1/bookingsCreate a new booking for a selected time slot{
"event_type_id": "evt_abc123",
"start_time": "2026-03-28T09:00:00Z",
"invitee": {
"name": "Jane Smith",
"email": "jane@example.com"
},
"metadata": {
"source": "website-widget"
}
}{
"id": "bk_a1b2c3d4",
"status": "confirmed",
"start_time": "2026-03-28T09:00:00Z",
"end_time": "2026-03-28T09:30:00Z",
"invitee": {
"name": "Jane Smith",
"email": "jane@example.com"
},
"cancel_url": "https://api.astrocal.dev/v1/bookings/bk_a1b2c3d4/cancel?token=...",
"reschedule_url": "https://api.astrocal.dev/v1/bookings/bk_a1b2c3d4/reschedule?token=..."
}Key parameters
| Name | Type | Default | Description | Required |
|---|---|---|---|---|
| eventTypeId | string | — | Your event type UUID. Find it in the dashboard or via GET /v1/event-types. | |
| mode | 'inline' | 'popup' | — | inline renders in-page. popup opens a modal overlay on trigger. Default: inline. | — |
| target | string | — | CSS selector for the container element. Required when mode is inline. | — |
| theme | object | — | Override design tokens: primary, background, fontFamily, borderRadius. | — |
| onSuccess | function | — | Callback fired when a booking is confirmed. Receives the full booking object. | — |
| locale | string | — | BCP 47 locale code for widget copy. Defaults to the browser locale. | — |
| metadata | object | — | Key-value pairs attached to every booking. Useful for attribution and tracking. | — |
Simple, transparent pricing
Start for free. Upgrade as you grow. No hidden fees, no per-seat pricing.
Free
For prototyping
- 10 bookings/month
- 1 calendar connection
- 30 req/min API rate
- Calendar sync
- Email notifications
Starter
For small teams
- 50 bookings/month
- 3 calendar connections
- 60 req/min API rate
- Everything in Free
- Custom branding
Pro
Most PopularFor growing teams
- 500 bookings/month
- 20 calendar connections
- 500 req/min API rate
- Everything in Starter
- Priority support
Business
For scaling up
- 5,000 bookings/month
- 100 calendar connections
- 2,000 req/min API rate
- Everything in Pro
- Dedicated support
No per-seat pricing. Ever. See full pricing →
Frequently asked questions
Keep reading
Google Calendar sync
Connect your calendar so the widget always shows real-time availability.
Read moreUse CaseAppointment reminders
Reduce no-shows with automated email reminders before each booking.
Read moreCore ProductAll features
See everything Astrocal offers, from availability rules to webhooks and payments.
Read moreAdd scheduling to your site today
One script tag. Real-time availability. Payments included. Free to start.