The embed widget covers most use cases out of the box. This article covers the deeper customisation options.
CSS variables
The widget exposes CSS variables you can override:
| Variable | Default | Purpose |
|---|---|---|
--mm-primary-color | #1a1813 | Button and accent color |
--mm-primary-fg | #fff | Text on primary color |
--mm-bg | #fff | Widget background |
--mm-fg | #1a1813 | Default text color |
--mm-muted-fg | #5a5550 | Secondary text |
--mm-border | #e5e1d8 | Card borders |
--mm-radius | 1rem | Border radius |
--mm-font-family | system-ui | Typeface |
--mm-spacing | 1rem | Padding density |
--mm-shadow | minimal | Card shadow |
Set them on the container div:
<div id="movementors-embed" style="
--mm-primary-color: #c4533c;
--mm-radius: 0;
--mm-font-family: 'Helvetica Neue', sans-serif;
"></div>
Or in your site's stylesheet:
#movementors-embed {
--mm-primary-color: #c4533c;
--mm-radius: 0;
}
Multiple widgets per page
You can have multiple widget instances on the same page. Each needs a unique container ID and a corresponding data-target on the script.
<script src="https://movementors.com/embed.js" data-studio="your-slug" data-mode="single" data-class="yoga-flow" data-target="mm-featured" async></script>
<div id="mm-featured"></div>
<!-- elsewhere on the same page -->
<script src="https://movementors.com/embed.js" data-studio="your-slug" data-mode="list" data-target="mm-full-list" async></script>
<div id="mm-full-list"></div>
Both widgets share the same script load (browser deduplicates), but render in their own containers.
Filter the embedded view
The widget config page lets you filter what gets shown. You can also override via data-* attributes:
| Attribute | Effect |
|---|---|
data-location | Filter to a specific location slug |
data-category | Filter to a category slug (e.g. "yoga") |
data-teacher | Filter to a specific teacher (slug for platform mentor, ID for custom) |
data-limit | Cap the number of classes shown |
data-from | Show classes starting after this date (ISO format) |
data-to | Show classes starting before this date |
Example: a homepage widget showing only "next 7 days" yoga classes at your main location:
<script src="https://movementors.com/embed.js"
data-studio="your-slug"
data-mode="grid"
data-category="yoga"
data-location="main-studio"
data-limit="6"
async></script>
<div id="movementors-embed"></div>
Event tracking
The widget fires custom events you can listen for:
movementors:loaded: widget DOM is ready.movementors:class-viewed: user clicked a class card.movementors:booking-started: user opened the booking form.movementors:booking-completed: booking succeeded.movementors:booking-failed: booking failed.
Listen via:
window.addEventListener('movementors:booking-completed', (e) => {
console.log('booking completed', e.detail);
// e.detail contains: { bookingId, classId, classTitle, amountCents, currency }
});
Useful for:
- Google Analytics: fire a conversion event when a booking completes.
- Facebook Pixel: track booking completions.
- Internal analytics: log to your own backend.
CSP integration
If your site has Content Security Policy, you need to allow MoveMentors in these directives:
Content-Security-Policy:
script-src 'self' https://movementors.com;
frame-src https://movementors.com;
connect-src 'self' https://movementors.com https://api.stripe.com;
img-src 'self' https://*.movementors.com https://res.cloudinary.com data:;
The widget itself uses iframe sandboxing internally; your CSP just needs to allow the framing.
Authentication handoff
The widget supports a "preauth" mode: if a user is already logged into your site, you can pass them through to MoveMentors without re-asking for their name and email.
<script src="https://movementors.com/embed.js"
data-studio="your-slug"
data-prefill-name="Jane Doe"
data-prefill-email="jane@example.com"
async></script>
<div id="movementors-embed"></div>
The values pre-fill the booking form. The user can edit them; this is a convenience, not a security boundary. (Do not assume the user is "logged in" just because you pre-filled values; the actual booking still requires email confirmation.)
Server-side rendering
The widget is client-side only. There is no server-side rendered (SSR) version that emits HTML for SEO purposes.
If you want your booking page to be indexed by search engines with full class content visible to crawlers, link to the corresponding MoveMentors class detail pages (which ARE server-side rendered) rather than relying on the widget for SEO.
For visible "next 5 classes" on your homepage that crawlers should see, consider also linking to the MoveMentors directory; the widget gives the booking UI, the link gives SEO juice.
Performance
The widget bundle is ~80KB gzipped. It loads asynchronously (the async attribute) so does not block your page rendering.
Initial render: ~1-2 seconds on a decent connection.
After load:
- Class card interactions: instant (client-side state).
- Booking form open: instant.
- Booking submission: depends on payment method (Stripe Checkout adds ~1 second redirect overhead).
If your site is performance-critical, you might prefer to lazy-load the widget (only mount it after user interaction). Pattern:
<button id="open-booking">Browse classes</button>
<div id="movementors-embed"></div>
<script>
document.getElementById('open-booking').addEventListener('click', () => {
const s = document.createElement('script');
s.src = 'https://movementors.com/embed.js';
s.dataset.studio = 'your-slug';
s.async = true;
document.body.appendChild(s);
});
</script>
The widget loads only on click. Trade-off: a small extra delay for users who click.
Mobile considerations
The widget is responsive. It adapts:
- Single-column layout below 640px.
- Touch-friendly tap targets (44×44 minimum).
- Booking form uses native mobile keyboards (numeric for prices, email for emails).
If your site has a mobile-specific layout (different from desktop), the widget can be configured per layout: use different data-mode attributes on the desktop vs mobile script tags, gated by CSS media queries.
Common questions
Can I get a fully white-label version with my logo and no MoveMentors branding? Enterprise customers can request this. The default includes a small "powered by MoveMentors" footer.
Can I run the widget on multiple domains? Yes. The widget does not whitelist domains. Anyone with your studio slug can embed.
Can I prevent other people from embedding my widget? Not currently. The widget pulls public class data; anyone who knows your slug can embed. We may add domain allow-listing as an enterprise feature.
Can I customise the booking form fields? Not currently. The fields are the same as the MoveMentors site. Field customisation is on the roadmap.
Will widget bookings count toward my MoveMentors visibility / ranking? Yes. A booking is a booking regardless of source. Embed-sourced bookings count toward your studio's totals, your reviews aggregate the same, etc.
Next steps
- Embed widget: the basics.
- Embed widget not loading: diagnostic.