intermediate
bookings
widget
embed

Embedding the Widget

Drop the Levy Bookings widget on your own website with a single <script> tag, in inline, modal, or floating-button modes

Levy Fleets TeamMay 18, 20269 min read

Embedding the Widget

The Levy Bookings widget is a tiny dependency-free JavaScript bundle (around 6 KB uncompressed) that loads from widget.levyelectric.com/v1.js and injects a secure iframe pointing to your hosted booking page. You can drop it onto any site that lets you paste an HTML snippet.

It works on:

  • Squarespace
  • Wix
  • Webflow
  • Shopify
  • WordPress (any theme that supports a Custom HTML block)
  • Hand-coded HTML / Next.js / React / Astro / Hugo / Jekyll

The script snippet

The fastest way to get the snippet is from the dashboard:

  1. Open Dashboard > Bookings > Widgets > {your widget}.
  2. Click Get embed code.
  3. Pick the mode (inline, modal, or floating-button).
  4. Copy the snippet and paste it into your site.

The snippet looks like this:

<!-- Inline embed -->
<div id="levy-bookings"></div>
<script
  src="https://widget.levyelectric.com/v1.js"
  data-slug="front-beach-bikes"
  data-mode="inline"
  data-target="#levy-bookings"
  data-theme="light"
  async
></script>

Embed modes

The widget supports three rendering modes, controlled by the data-mode attribute.

Inline

The widget injects an iframe directly into a target element on your page. Use this when you have a dedicated "Book a bike" page and you want the booking flow to feel like a native section.

<div id="levy-bookings"></div>
<script
  src="https://widget.levyelectric.com/v1.js"
  data-slug="front-beach-bikes"
  data-mode="inline"
  data-target="#levy-bookings"
  async
></script>

The iframe auto-resizes as the customer progresses through the steps — no fixed height needed. A ResizeObserver inside the iframe emits levy:resize messages and the host script adjusts.

The widget injects a hidden iframe and opens it as a centered overlay modal when the customer clicks any element with data-levy-book="open". Use this when you want a "Book now" button anywhere on your site.

<button data-levy-book="open">Book a bike</button>

<script
  src="https://widget.levyelectric.com/v1.js"
  data-slug="front-beach-bikes"
  data-mode="modal"
  async
></script>

You can have multiple data-levy-book="open" triggers — every one of them opens the same modal.

Floating button

The widget injects a fixed "Book now" button in the bottom-right corner of every page that includes the snippet. Use this when you want a persistent call-to-action across the whole site (homepage, blog posts, product pages).

<script
  src="https://widget.levyelectric.com/v1.js"
  data-slug="front-beach-bikes"
  data-mode="floating-button"
  data-button-label="Book a bike"
  data-button-position="bottom-right"
  async
></script>

Data attribute reference

All configuration is on the <script> tag itself, using data-* attributes. The host script reads them once at load.

AttributeRequiredDefaultDescription
srcyesMust be https://widget.levyelectric.com/v1.js. Use v1 for a stable contract.
data-slugyesYour widget slug, e.g. front-beach-bikes. Matches the hosted URL.
data-modeyesinlineinline, modal, or floating-button.
data-targetinline only#levy-bookingsCSS selector for the host element. Must exist on the page when the script loads.
data-themenolightOne of light, dark, minimal. Overrides the widget's default theme.
data-button-labelfloating-button onlyBook nowText on the floating button.
data-button-positionfloating-button onlybottom-rightbottom-right, bottom-left, top-right, top-left.
data-localenobrowserForce en, es, fr, de, or pt. Otherwise inferred from the customer's browser.
data-utm-sourcenoUTM parameters passed into the booking. Useful for attribution.
data-pixel-ga4noForward conversion events to a GA4 measurement ID.
data-pixel-metanoForward conversion events to a Meta Pixel ID.
asyncrecommendedAdd async so the script does not block your page render.

Conversion events

The widget bridges conversion events back to the parent page through postMessage. You can listen for them directly to forward into any analytics tool:

<script>
  window.addEventListener('message', (event) => {
    if (event.origin !== 'https://widget.levyelectric.com') return;
    if (event.data?.type === 'levy:event') {
      const { eventName, payload } = event.data;
      // eventName: 'booking_started' | 'model_selected' | 'payment_succeeded' | ...
      console.log('Levy booking event:', eventName, payload);
    }
  });
</script>

If you set data-pixel-ga4 or data-pixel-meta, the host script forwards the events for you automatically.

Custom domains

You can serve the booking page at your own domain (book.frankebikes.com) instead of fleets.levyelectric.com/book/{slug}:

  1. In your DNS provider, add a CNAME from book.frankebikes.com to cname.levyelectric.com.
  2. Open a support ticket from the dashboard with the desired domain. We provision the TLS certificate and routing within one business day.
  3. Update your widget's Public URL in the dashboard. Existing embed snippets keep working — the CNAME also passes the iframe.

Squarespace specifics

Squarespace blocks <script> tags in standard text blocks. To embed:

  1. Edit any page.
  2. Add a Code block (not a text block).
  3. Paste the snippet, click Apply.
  4. Make sure Display Source is off so the snippet executes.

For the floating-button mode, paste the snippet into Settings > Advanced > Code Injection > Footer. It then runs on every page of your Squarespace site.

Wix specifics

  1. From the editor, click Add Elements (+) > Embed Code > Embed HTML.
  2. Paste the snippet.
  3. Resize the placeholder to roughly the dimensions you expect the iframe to take.

For floating-button mode, use Settings > Custom Code > Add Custom Code and paste into the footer.

WordPress specifics

In a Custom HTML block (Gutenberg) or a Text widget (Classic), paste the snippet directly. If you use a page builder (Elementor, Divi, Beaver Builder), use that builder's HTML widget.

For the floating-button mode, paste into your theme's footer (or use a plugin like Insert Headers and Footers) so the script loads on every page.

Shopify specifics

  1. Open Themes > Edit code.
  2. Open layout/theme.liquid.
  3. Paste the floating-button snippet just before </body>. The button now appears on every storefront page.

For an inline embed on a specific page, add a Custom Liquid section to that page and paste the inline snippet.

Performance

The host script is around 6 KB uncompressed and loads with async. The iframe itself lazy-loads (loading="lazy") and does not begin fetching Stripe.js until the customer reaches the payment step. Total time-to-interactive on a 3G simulation is under 200 ms.

If your site is privacy-restricted (Brave Shields, uBlock Origin, Firefox Total Cookie Protection), the iframe still works because we route everything through widget.levyelectric.com (not a tracking domain) and use first-party cookies inside the iframe.

Allowed origins

Before the widget will accept POST requests from your site, you must add the exact origin to the widget's Allowed origins list:

https://www.frankebikes.com
https://frankebikes.com

If your domain redirects from non-www to www (or vice versa), add both. If you preview on a staging URL, add that too. Origins are matched exactly (scheme + host + port). The hosted page (/book/{slug}) is always allowed and does not need an origin entry.

GET requests (availability, quote, config) are CORS-open to any origin — only POST requests (create booking, submit waiver) need to be on the allowlist.

Apple Pay

Apple Pay inside iframes is supported because we host the iframe on widget.levyelectric.com, which is registered as a verified merchant domain for every subaccount's Stripe connected account. No additional setup needed.