Bird Pickup & Delivery Bird Pickup & Delivery
Back to Developer
Developer

Integrating the Bird Widget in a Shopify Headless Storefront

Updated July 17, 2026

The Bird Pickup & Delivery scheduler runs on any storefront — Hydrogen, React, Vue, or plain HTML. You add one stylesheet and one script, set your shop domain, and call mount(). There is no theme app extension, no build step, and no npm package to install.

See it running: the live demo storefront mounts the real widget on a mock product page and cart, with a copy-paste configuration reference. It’s the fastest way to confirm the exact behavior before you wire it into your own build.

Requirements

  • The Bird Pickup & Delivery app must be installed and enabled in your Shopify admin.
  • You need your *.myshopify.com domain (for example your-store.myshopify.com).

That’s it — the widget fetches its settings, translations, timezone, and availability rules automatically from your Bird configuration.

Quick start

Add the stylesheet, set window.BirdApp.config, then load the bundle. The config must be set before the bundle runs.

<!-- 1. styles + config, then the bundle -->
<link rel="stylesheet" href="https://cdn.birdchime.com/widget/bird.bundle.css">
<script>
  window.BirdApp = { config: { shop: 'your-store.myshopify.com' } };
</script>
<script src="https://cdn.birdchime.com/widget/bird.bundle.js" defer></script>

Then, once the bundle is ready, mount the widget into a container element and keep it fed with your cart:

// 2. mount once ready (mount is async)
await window.BirdApp.ready;
const handle = await window.BirdApp.widget.mount(el);

// 3. keep the cart in sync — pass your Storefront cart as-is
window.BirdApp.sdk.setCart(cart);

The window.BirdApp object

The bundle exposes a single global with four members. You set config; the bundle fills in the rest.

window.BirdApp = {
  config,   // you set this — { shop, locale?, customer? }
  ready,    // Promise<sdk | null> — await before mounting
  sdk,      // BirdSDK instance (or null) — sdk.setCart(cart)
  widget,   // { mount(container, options?) }
}

Configuration

Set window.BirdApp.config before the bundle loads. Only shop is required.

💡
Field Required Notes
shop Yes Your *.myshopify.com domain
locale No Defaults to 'en'
customer No { id, tags, loggedIn } — needed only if the merchant uses customer-tag availability rules

Mounting the widget

Call widget.mount(container, options?), which returns a Promise<MountHandle | null>.

  • Cart widget (default) — mount with no options. It reads the cart you provide via sdk.setCart.

    const cart = await window.BirdApp.widget.mount(cartEl);
    
  • Product widget — pass { type: 'product', item }, where item describes the product/variant being viewed. The item’s tags and collectionIds let per-product availability rules apply.

    const product = await window.BirdApp.widget.mount(productEl, {
      type: 'product',
      item: {
        productId, variantId, sku,
        quantity: 1, price,
        tags: [], collectionIds: [],
      },
    });
    

The returned handle is { destroy(), isMounted(), remount? }. It resolves to null if mounting couldn’t complete — check the browser console.

A selection made on the product page carries into the cart automatically, because both widgets share one sdk instance.

Keeping the cart in sync

Call sdk.setCart(cart) on load and whenever the cart changes (add, remove, quantity update). Pass your Storefront-API cart object as-is — the widget reads the line items, totals, and attributes it needs from it.

window.BirdApp.sdk.setCart(cart);

Hydrogen / React example

window.BirdApp exists only in the browser, so mount inside an effect that runs after render — never during server render.

import { useEffect, useRef } from 'react';

function BirdCartWidget({ cart }) {
  const ref = useRef(null);

  useEffect(() => {
    let handle;
    (async () => {
      const sdk = await window.BirdApp.ready;
      if (!sdk) return; // init failed — see console
      sdk.setCart(cart);
      handle = await window.BirdApp.widget.mount(ref.current);
    })();
    return () => handle?.destroy();
  }, []);

  // push cart changes into the widget
  useEffect(() => {
    window.BirdApp?.sdk?.setCart(cart);
  }, [cart]);

  return <div ref={ref} />;
}

Notes

  • Browser-only. window.BirdApp is client-side only. Never reference it during server render — in Hydrogen, mount inside a useEffect.
  • ready never rejects. On init failure it resolves to null (and mount() then resolves to null). Check for null — don’t rely on .catch().
  • Non-blocking. The bundle loads with defer and is served from a CDN, so it never blocks your page render.

Was this article helpful?