Skip to main content
Version: v1

Cart Setup

theme.liquid

<html>
<head> ... </head>
<body>
...

<!-- BEAM START -->
{% render 'beam-config' %}
**{% render 'beam-cart-setup' %}**
<!-- BEAM END -->
</body>
</html>

Base code

beam-cart-setup.liquid

<script type="module" async crossorigin>
import { registerCartIntegration } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/shopify.js";

registerCartIntegration({
apiKey: {{ settings.beam_api_key }},
storeId: {{ settings.beam_store_id }},
baseUrl: {{ settings.beam_base_url }},
domain: {{ settings.beam_store_domain }} || undefined,
});
</script>

Tracking Rebuy carts

Rebuy and Beam’s default cart tracking code can sometimes interfere with each other. To ensure a consistent experience for your users, the following snippet can be used in place of the “Base Widget” snippet above for storefronts which use Rebuy for carts.

beam-cart-setup.liquid

<script type="module" async crossorigin>
import { addBeamAttributesToCart, getCurrentCart, trackCart } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/shopify.js";
import { events, getCookieValue, createScopedLocalStorage, saveRemoteSession } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/utils.js";
import { getConfig } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/beam.js";

const beam = getConfig();
await beam.readyPromise;

let lastSelectedNonprofitId = null; // used to avoid duplicate calls
window.addEventListener(events.BeamNonprofitSelectEvent.eventName, async (event) => {
const {selectedNonprofitId, selectionId} = event.detail;
if (selectedNonprofitId !== lastSelectedNonprofitId) {
await addBeamAttributesToCart({
selectedNonprofitId,
selectionId,
cartId: await getCookieValue("cart"),
storeId: beam.storeId,
chainId: beam.chainId,
})
}
lastSelectedNonprofitId = selectedNonprofitId;
});

// Set up Rebuy event listeners; this replaces "registerCartIntegration"
document.addEventListener('rebuy:cart.change', async (event) => {
const currentCart = await getCurrentCart(beam);
await trackCart(beam, currentCart.cart);
});
</script>

Tracking custom carts

In cases where your site is using a custom cart, or the GraphQL implementation of Shopify’s API, Beam listens for cart changes differently than using registerCartIntegration as seen above. The code below is a way to do this.

The code assumes you have access to the Shopify Storefront AJAX API (/cart.js, etc.).

beam-cart-setup.liquid

Replace

  • cartItemObserveElement - this will be the element that will be watched. Make sure that this element is as close to where the Beam widget should display as possible; since any changes to that element will trigger the observer code to run, we want to make sure that the observer callback is not called unnecessarily.
<script type="module" async crossorigin>
import { addBeamAttributesToCart, getCurrentCart, trackCart } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/shopify.js";
import { events, getCookieValue, waitForElement, createScopedLocalStorage, saveRemoteSession } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/utils.esm.js";
import { getConfig } from "https://sdk.beamimpact.com/web-sdk/{{ settings.beam_sdk_version }}/dist/integrations/beam.js";

// CSS Selector for the Cart DOM element that will have a MutationObserver
const cartItemObserverTargets = [".drawer__inner", ".cart-items"];

const beam = await getConfig();
await beam.readyPromise;

let lastSelectedNonprofitId = null; // used to avoid duplicate calls
window.addEventListener(
events.BeamNonprofitSelectEvent.eventName,
async (event) => {
const {selectedNonprofitId, selectionId} = event.detail;
if (selectedNonprofitId !== lastSelectedNonprofitId) {
await addBeamAttributesToCart({
selectedNonprofitId,
selectionId,
cartId: await getCookieValue("cart"),
storeId: beam.storeId,
chainId: beam.chainId,
})
}
lastSelectedNonprofitId = selectedNonprofitId;
}
);

let pauseObserver = false; // used to control throttling of API call
const cartChangeObserver = new MutationObserver(
async (mutationsList, observer) => {
if (pauseObserver) return; // throttled
await trackCart(beam, (await getCurrentCart(beam)).cart);
pauseObserver = true; // throttle for a few ms
setTimeout(() => { pauseObserver = false }, 100);
}
);

cartItemObserverTargets.forEach(async (target) => {
const observerElement = await waitForElement(target);
if (observerElement) {
cartChangeObserver.observe(observerElement, {attributes: false, childList: true, subtree: true});
}
});

// Make sure initial cart value is registered
await trackCart(beam, (await getCurrentCart(beam)).cart);
</script>