Giftie
Advanced Shopify integration

Recording cart refresh

Refresh a custom Shopify cart after Giftie adds a video or audio recording line.

Most Shopify merchants use Giftie's configured defaults and do not need to choose a strategy here. These details are for developers adapting Giftie to a custom cart drawer, framework store, or unusual theme lifecycle.

This page covers the video/audio recording add-on managed by the standard recording controller. It does not describe greeting-card sessions or their cart flow.

Cart refresh belongs to the Giftie Shopify integration or to your custom host code. It is not performed by window.Giftie itself.

Released default path

After a recording line is added successfully on a non-cart surface, the standard video-message controller currently:

  1. dispatches any outbound cart-update DOM event names supplied by the integration;
  2. calls window.giftieRefreshCartUI() when that function exists and stops the fallback path if it resolves; otherwise
  3. fetches /cart?view=drawer and /cart.js, replaces the common cart item and totals elements, and updates common cart-count elements; and
  4. reloads the page if that DOM refresh fails.

Under defaults, giftieRefreshCartUI is therefore auto-detected only on non-cart surfaces. On a cart page, the released controller reloads before it reaches that default callback path unless an enabled advanced custom-function strategy points to a function that exists on window.

These selectors and theme APIs are best-effort implementation behavior, not a guarantee that every Shopify theme updates without configuration. Test the actual product page, cart drawer, and cart page.

Manual strategies

When Use Defaults is disabled in Giftie admin, the released Shopify theme integration runs only the enabled advanced strategies. This configuration belongs to the Shopify app and is not an SDK constructor option.

Notification strategies run before the DOM strategy:

  • Pub/sub calls the theme's global publish() function.
  • Custom events dispatch configured CustomEvent names on document with { source, cartData } in detail.
  • Custom function calls a named function on window with the cart-add response. Errors are logged and do not stop the configured DOM phase.

Then the selected DOM behavior runs:

  • Page reload reloads immediately and takes priority.
  • Section rendering, auto calls a configured cart drawer's renderContents() with inline sections when available, otherwise fetches section HTML, then falls back to the legacy DOM refresh.
  • Section rendering, legacy fetches the drawer view and cart JSON and replaces the common selectors.
  • With both page reload and section rendering disabled, the configured path performs notifications only.

In the current release, the open drawer option is applied in the explicit legacy path and the auto path's legacy fallback. It is not applied after a successful direct renderContents() call. If your theme requires the drawer to open after that path, do it in a custom bridge after rendering has completed.

Framework store or EventBus bridge

Framework storefronts should put their own state/event APIs behind a small adapter. The custom function should await fresh cart state and its application before it opens the drawer:

// Implement these methods with your framework store or EventBus.
// replace() must resolve after consumers have applied the new cart state.
const storefrontCartBridge = {
  async replace(cart) {
    await cartStore.replace(cart)
  },
  async openDrawer() {
    await cartDrawerController.open()
  },
}

window.giftieRefreshCartUI = async function giftieRefreshCartUI() {
  try {
    const response = await fetch('/cart.js', {
      headers: { Accept: 'application/json' },
      credentials: 'same-origin',
    })

    if (!response.ok) {
      throw new Error(`Cart refresh failed (${response.status})`)
    }

    const cart = await response.json()
    await storefrontCartBridge.replace(cart)
    await storefrontCartBridge.openDrawer()
  } catch (error) {
    console.error('Unable to refresh the cart', error)
    window.location.reload()
  }
}

cartStore and cartDrawerController are placeholders for APIs your storefront owns. An EventBus adapter should resolve replace() only after its listener acknowledges that the cart state has been applied and rendered; a fire-and-forget event can otherwise open the drawer with stale contents.

On non-cart surfaces with defaults enabled, the controller detects this function automatically. To use it on a cart page, disable Use Defaults and enable the advanced Custom function strategy with this function name. If the bridge should be the only UI updater, also disable Page reload and Section rendering; otherwise the configured DOM phase still runs after the custom function.

With a notification-only configuration, Giftie logs a custom-function failure but has no enabled DOM fallback. The bridge must own recovery itself, such as the reload in this example or an application-controlled retry/error state.

Shopify-theme renderContents() bridge

For Shopify themes whose drawer exposes renderContents(), define the function before Giftie adds to cart:

window.giftieRefreshCartUI = async function giftieRefreshCartUI(cartAddResponse) {
  const drawer = document.querySelector('cart-drawer')

  if (!drawer || typeof drawer.renderContents !== 'function') {
    window.location.reload()
    return
  }

  if (cartAddResponse?.sections) {
    await drawer.renderContents(cartAddResponse)
    return
  }

  const requestedSections =
    typeof drawer.getSectionsToRender === 'function'
      ? drawer.getSectionsToRender()
      : drawer.sectionsToRender
  const sectionIds = Array.isArray(requestedSections)
    ? requestedSections.map(section => section.sectionID || section.id).filter(Boolean)
    : []

  if (sectionIds.length === 0) {
    window.location.reload()
    return
  }

  const sections = await fetch(
    `${window.location.pathname}?sections=${sectionIds.join(',')}`,
  ).then(response => {
    if (!response.ok) throw new Error(`Section refresh failed (${response.status})`)
    return response.json()
  })

  await drawer.renderContents({ sections })
}

The argument is optional in either bridge. The default compatibility path calls giftieRefreshCartUI() without arguments; the advanced configured path passes the cart-add response and can continue to its configured DOM strategy afterward.

Make the function resolve only after the visible cart is consistent. await works with both synchronous and promise-returning renderContents() methods, but it can only wait for completion that the theme method represents. If the method returns before its render is committed, add a theme-specific rendered signal before resolving.

Throwing in the default non-cart path activates Giftie's legacy fallback. In the configured path, a custom-function failure is logged and the enabled DOM phase continues; when no DOM strategy is enabled, there is no Giftie fallback.

Copyright © 2026