Post Purchase Extension
Beam supports checkout extensibility via a custom app that includes the Beam post purchase extension. The post purchase extension can be installed/updated by Beam integration engineers for partners with checkout extensibility enabled.
This extension is functionally identical to the Beam post purchase widget with a few exceptions:
- Social share redirects to a separate page instead of a modal
- Statsig needs to be enabled using a Shopify custom pixel
- Remote config not available due to CSS restrictions
Settings
When customizing the 'Thank You' or 'Order Status' page, clicking on the Beam extension opens up the settings that allow users to configure Beam extensions.
NOTE: Ensure that any settings made are applied to both pages as the values are maintained separately.
AB Testing
AB Testing can be conducted against a store with checkout extensibility enabled using a custom pixel that enables Statsig functionality in the post purchase extension using Shopify analytics events.
The Statsig custom pixel can be installed by a Beam integration engineer during AB test setup to ensure proper order/redemption tracking.
-
Open your Shopify store
-
Click on the Settings tab on the left navigation bar
-
Click on Customer Events
-
Click on
Add custom pixel
. If prompted to name the pixel, call it "Beam Statsig" -
In the next screen, select "Not required" under the Permission dropdown and "Data collected qualifies as data sale" under the Data sale dropdown
-
Paste the following code block into the Code section. The Beam team will provide you with the Statsig API key, which should be pasted into the
STATSIG_API_KEY
field in the code.
const STATSIG_API_KEY = "STATSIG_API_KEY";
const STATSIG_VERSION = 4;
const STATSIG_SCRIPT_URL = `https://cdn.jsdelivr.net/npm/statsig-js@${STATSIG_VERSION}/build/statsig-prod-web-sdk.min.js`;
const SHOPIFY_CURRENCY_SCRIPT_URL = `/services/javascripts/currencies.js`;
// Shopify currency conversions JS library
const currencyScript = document.createElement("script");
currencyScript.src = SHOPIFY_CURRENCY_SCRIPT_URL;
document.head.append(currencyScript);
// Statsig JS Library
const statsigScript = document.createElement("script");
statsigScript.src = STATSIG_SCRIPT_URL;
statsigScript.setAttribute("async", "");
document.head.append(statsigScript);
function waitFor(predicate, timeout) {
return new Promise((resolve, reject) => {
let running = true;
const check = async () => {
const res = await predicate();
if (res) return resolve(res);
if (running) setTimeout(check, 100);
};
check();
if (!timeout) return;
setTimeout(() => {
running = false;
reject();
}, timeout);
});
}
async function createStatsigClient(stableId) {
const statsigOptions = {
disableErrorLogging: true,
disableAutoMetricsLogging: true,
disableCurrentPageLogging: true,
loggingIntervalMillis: 1000,
loggingBufferMaxSize: 2,
overrideStableID: stableId ?? null,
};
try {
await waitFor(() => window.hasOwnProperty("statsig"), 5000);
await window.statsig?.initialize(STATSIG_API_KEY, {}, statsigOptions);
} catch (err) {
console.debug("🌈 Beam", "timed out waiting for Statsig to load");
}
}
function getRecurringLineItems(lineItems) {
let recurringLineItems = [];
lineItems.forEach((lineItem) => {
if (lineItem?.sellingPlanAllocation?.sellingPlan?.id) {
recurringLineItems.push(lineItem);
}
});
return recurringLineItems;
}
function convertCurrencyAmountToCurrencyCode(amount, fromCode, toCode) {
if (fromCode === toCode) {
return {
amount: parseFloat(amount),
currencyCode: fromCode,
};
}
try {
let convertedAmount = parseFloat(window.Currency.convert(amount, fromCode, toCode)?.toFixed(2));
return !isNaN(parseFloat(convertedAmount)) ? { amount: convertedAmount, currencyCode: toCode } : { amount: parseFloat(amount), currencyCode: fromCode };
} catch (error) {
console.error(
"🌈 Beam",
`error converting currency ${fromCode} to ${toCode}`,
error
);
return { amount: parseFloat(amount), currencyCode: fromCode };
}
}
async function logOrderEvent(event) {
const { currencyCode, subtotalPrice, attributes, order, lineItems } =
event.data.checkout;
const localCartTotal = subtotalPrice?.amount;
const standardizedOrderAmount = convertCurrencyAmountToCurrencyCode(
localCartTotal,
currencyCode,
"USD"
);
const standardizedCartTotal = standardizedOrderAmount?.amount;
const recurringLineItems = getRecurringLineItems(lineItems);
const beamAttribute = attributes.find((attr) => attr.key === "beam");
const beamCheckoutAttribute = attributes.find(
(attr) => attr.key === "beam_checkout_id"
);
const beamAttributeParsed =
beamAttribute && beamAttribute.value ? JSON.parse(beamAttribute.value) : {};
await createStatsigClient(beamAttributeParsed.remote_session_id);
const checkoutCompletedEventDetails = {
currencyCode,
localCartTotal,
cartTotal: standardizedCartTotal,
orderId: order.id,
hasCart: !!beamAttributeParsed.beam_cart_id || !!beamCheckoutAttribute,
hasSubscription: recurringLineItems.length > 0,
};
window.statsig?.logEvent(
"checkout_completed",
standardizedCartTotal,
checkoutCompletedEventDetails
);
console.debug("🌈 Beam", "checkout_completed", checkoutCompletedEventDetails);
}
// omit this block for integrations that leverage serverside Statsig
analytics.subscribe("checkout_completed", async (event) => {
logOrderEvent(event);
});
-
Click on
Save
on top of page (you may need to select another modal to get the Save menu to pop up) -
Click on
Connect
on the bottom right side of the page