Public API
Clone this wiki locally
Zipify OneClickUpsell (OCU) Public API
Welcome to the Zipify OneClickUpsell (OCU) Public API. This documentation will walk you through the setup and use of custom fields to extend and customize the functionality of OCU pre-purchase popup on your store.
Before using the custom fields provided in this guide, you must first include the OCU initialization code. This code establishes the necessary namespaces for the custom fields and prepares your environment for further configuration.
Initial Setup
To enable OCU API, paste the following initialization code:
((o,c,u)=>{o[c]=o[c]||{},o[u]=o[u]||{},o[c].OCU={api:o[u]}})(window,'Zipify','OCUApi');Once the initial setup is complete, you can start using the custom fields detailed in this guide. Each custom field section will provide you with its type, a description, example usage, and, in some cases, a brief explanation of its purpose.
Using Liquid for Customizations
If you're familiar with Liquid and want to leverage its capabilities for your OCU custom fields, follow these steps:
-
Create a Liquid File: Design your custom functionality in a separate Liquid file within your Shopify theme's template directory.
-
Render the Liquid File: Once your Liquid file is set up and ready to go, render it in your theme where you want the functionality to be applied. Use the following syntax:
{% render 'file-name' %}Note on fields with an Asterisk (*):
Fields marked with an asterisk (*) indicate that they are to be used in conjunction with another related field. It's essential to ensure that both fields are properly configured to achieve the desired functionality. When implementing such fields, be sure to refer to the accompanying description and example to understand their interdependent nature.
customCheckoutButton
| Type | Description |
|---|---|
string |
Specifies a selector for an element. When this element is clicked, it activates the OneClickUpsell pre-purchase popup. This is particularly useful when the checkout button is placed outside a standard form or if the form lacks the necessary attributes to automatically trigger the OCU popup. Such scenarios may arise when a store utilizes a third-party cart solution. |
Example:
Zipify.OCU.api.customCheckoutButton = 'desired selector';
// example of selectors: '.some-class', '#button-id'
customBuyNowButton
| Type | Description |
|---|---|
string |
Used to specify a particular button element in the store by its CSS selector. This ensures that OCU can correctly interact with the "Buy Now" button, especially if the default button is not detected or needs to be overridden. |
Example:
Zipify.OCU.api.customBuyNowButton = 'desired selector';
// example of selectors: '.some-class', '#button-id'
customAddToCartButton
| Type | Description |
|---|---|
string |
Specifies a selector for an element on the product page. When this element is clicked, it activates the OneClickUpsell pre-purchase popup. This is particularly useful when the "add to cart" button is placed outside a typical form or if the form doesn't have the necessary attributes to naturally trigger the OCU popup. Such situations might occur when a store uses custom pages created through page builders. |
Example:
Zipify.OCU.api.customAddToCartButton = 'desired selector';
// examples of selectors: '.add-to-cart-class', '#add-to-cart-button-id'
customAddToCartEventHandler
| Type | Description |
|---|---|
function |
Allows the addition of a custom callback function to handle the "add to cart" event. This provides developers the flexibility to introduce custom logic or behavior when an item is added to the cart, beyond the default functionality provided by the application. |
Example:
Zipify.OCU.api.customAddToCartEventHandler = (button) => {
// Insert custom code or actions here
};Extended Example:
If you want to ensure the button remains enabled and then trigger a click event after custom logic:
Zipify.OCU.api.customAddToCartEventHandler = (button) => {
button.disabled = false;
button.click(); // Alternatively: button.dispatchEvent(new PointerEvent('click', { cancelable: true, bubbles: true }));
};
customAddToCartForm
| Type | Description |
|---|---|
string |
Specifies a selector for a form on the product page that activates the OneClickUpsell pre-purchase popup. This becomes particularly useful when there are multiple buttons on a product page (e.g., a primary button and a sticky button that appears upon scrolling). It helps detect the correct form when a button is outside its associated form or lacks standard attributes. |
Example:
Zipify.OCU.api.customAddToCartForm = 'desired selector';
// examples of selectors: 'form[action="/cart/add"]', 'form[action="/cart/add"][data-type="add-to-cart-form"]'
customAddToCartFetch
| Type | Description |
|---|---|
function |
Used for adding the capability to execute additional steps and customize the implementation for the "add to cart" request. This can allow for tailored network requests and post-request behavior depending on the application's requirements. |
Example:
Zipify.OCU.api.customAddToCartFetch = ({ url, method, data }) => {
try {
// Example code demonstrating the structure
return new Promise(async (resolve) => {
// Some custom logic here
resolve({ data: cart });
});
} catch (e) {
return Promise.reject(e);
}
}Extended Example:
Zipify.OCU.api.customAddToCartFetch = ({ url, method, data }) => {
try {
const body = JSON.stringify(data);
const options = { method, body, headers: {'Content-Type': 'application/json'}};
return new Promise(async (resolve) => {
const cart = await fetch(url, options).then((res) => res.json());
resolve({ data: cart });
});
} catch (e) {
return Promise.reject(e);
}
};Note: The above examples are meant to provide a general structure. You may need to adjust them according to the specifics of your application and the exact behavior you want to achieve.
customButtonLoader
| Type | Description |
|---|---|
function |
Enables the customization of the checkout button's loading state. This can be achieved through the addition of styles, classes, or by embedding a custom loading template. This is useful to ensure consistency in design and user experience during loading states. |
Example:
Zipify.OCU.api.customButtonLoader = (event) => {
try {
// Add a custom class to the checkout button during its loading state
event.target.classList.add('desiredClassForLoadingState');
// Insert a custom loading template or spinner to the button
const loaderTemplate = '<div class="customLoaderClass"></div>';
event.target.insertAdjacentHTML('afterbegin', loaderTemplate);
} catch (e) {
console.error('Error applying custom loader:', e);
}
};
customCheckoutForm
| Type | Description |
|---|---|
string |
Specifies a selector to identify a valid form on the checkout page. This becomes crucial when there's a custom implementation of the checkout form or when traditional structures are bypassed, such as in cases where the checkout button exists outside the expected form. |
Example:
Zipify.OCU.api.customCheckoutForm = 'desired selector';
// examples of selectors: '#slidecart-checkout-form', 'form[action="/cart"]'Note: This functionality is particularly useful in scenarios where third-party solutions or custom page builders result in unconventional checkout form structures. It ensures that the OneClickUpsell application can still detect and interact with the checkout form correctly.
customCheckoutDuplicatedForm
| Type | Description |
|---|---|
string |
Specifies a selector to identify a valid duplicate form on the checkout page. This is particularly useful when there are multiple instances of checkout forms on a page, and you need to ensure the OneClickUpsell application interacts with the correct one. |
Example:
Zipify.OCU.api.customCheckoutDuplicatedForm = 'desired selector';
// examples of selectors: 'form[action="/cart"]'Note: This functionality is crucial in scenarios where there might be more than one checkout form due to design choices, third-party integrations, or other reasons. Using the correct selector ensures the application interacts with the intended form, avoiding potential conflicts or issues.
getCustomAddToCartData
| Type | Description |
|---|---|
function |
A callback that offers an opportunity to manually fetch and return product details such as variant ID, quantity, and subscription type (if applicable) when these details are not directly accessible from the form. |
Example:
Zipify.OCU.api.getCustomAddToCartData = () => {
try {
const form = document.querySelector('form[action="/cart/add"]');
const { id, quantity } = Object.fromEntries(new FormData(form));
return {
id: id,
quantity: quantity ?? 1
};
} catch (e) {
console.error(e);
return {};
}
};Example with subscription:
Zipify.OCU.api.getCustomAddToCartData = () => {
const selected = document.querySelector('selector');
if (!selected) return {};
const id = selected.value;
const purchaseType = selected.dataset.purchase_type;
if (!id) return {};
return {
id,
quantity: 1,
subscription: purchaseType === 'subscription'
};
};
preventReloadOnNavigate
| Type | Description |
|---|---|
boolean |
By default, OCU always reloads the page when using the browser's back button. The preventReloadOnNavigate field allows you to control this behavior. Disabling it can help in preserving the state and speed of cached pages. |
Example:
Zipify.OCU.api.preventReloadOnNavigate = true;
preventReloadPersistedPage
| Type | Description |
|---|---|
boolean |
Controls whether to prevent the reload of a custom persisted page when returning to it. A persisted page is one that retains its last state or location in memory. This can be useful in situations where users navigate away from a page and then return, expecting to find it in the same state. |
Example:
Zipify.OCU.api.preventReloadPersistedPage = true;
customLineItemAttributes
| Type | Description |
|---|---|
string |
Specifies a selector for a node to which OCU attributes should be added. Integrating OCU pre-purchase discounts becomes seamless, ensuring they render accurately in locations such as the cart drawer, cart page, or minicart. By pinpointing the correct node, OCU can append the necessary attributes, ensuring the discount is displayed correctly. For those seeking added flexibility in managing discounts, consider exploring the cartDiscountSelectors field. |
Example:
Zipify.OCU.api.customLineItemAttributes = 'desired selector';
/*
example of selectors:
- '.CartDrawerItem-properties, .CartItem-properties',
- '.mini-cart__item-title .line-item'
*/
excludeActionButton
| Type | Description |
|---|---|
string |
Identifies a button that should be excluded from OCU-related events. This is useful to prevent inappropriate buttons from triggering OCU popups due to incorrect automatic detection. |
Example:
Zipify.OCU.api.excludeActionButton = 'desired selector';Note: This configuration is particularly useful in cases where certain buttons have been mistakenly selected by OCU, causing them to display popups when clicked. By using this setting, OCU can be instructed to ignore and not apply its functionality to the specified button.
originFetch
| Type | Description |
|---|---|
function |
Used to revert to the original fetch method, particularly when it has been overridden by other scripts. This is crucial for OCU as it relies on the native fetch functionality for its operations. |
Example:
Zipify.OCU.api.originFetch = window.fetch;
customCartDrawerCloseButton
| Type | Description |
|---|---|
string |
Specifies a selector to identify a custom cart drawer close button, particularly useful when the cart drawer does not have a public method or other means to close. |
Example:
Zipify.OCU.api.customCartDrawerCloseButton = 'desired selector';Note: This is beneficial in situations where the cart drawer might overlap with the OCU popup due to, for instance, z-index issues. By specifying the close button, you can ensure the cart drawer is closed appropriately when needed.
axios
| Type | Description |
|---|---|
function |
Allows the overriding of the default axios instance that OCU uses for its API calls. Useful if you have a specific axios configuration in your environment. |
Example:
Zipify.OCU.api.axios = '<your axios instance>'Note: By overriding axios in this way, developers have the flexibility to customize HTTP requests to meet specific requirements or integrate with other scripts.
isWindowLocationForClickListener
| Type | Description |
|---|---|
boolean |
Utilized to elevate the priority of OCU events, especially when other apps have subscribed to the window object and interfere with them. |
Example:
Zipify.OCU.api.isWindowLocationForClickListener = true;Note: By setting this property to true, developers can ensure that the Zipify OCU application's events take precedence over events from other scripts or apps. This is particularly helpful when there's a conflict between multiple event listeners attached to the button.
isFormInvalid*
| Type | Description |
|---|---|
boolean |
Used for form validation. This property can indicate if a product could be added without fulfilling required fields. It's ideal to use this in conjunction with customFormValidate property. |
Example:
Zipify.OCU.api.isFormInvalid = verifiedFormCorrectness; // Boolean value representing form's validity.
customFormValidate*
| Type | Description |
|---|---|
function |
This is a function used for custom form validation, especially in cases where a product might be added without filling required fields. It pairs well with the isFormInvalid property for effective validation. |
Example:
Zipify.OCU.api.customFormValidate = () => {
const desiredElement = document.querySelector('.required-field');
Zipify.OCU.api.isFormInvalid = !desiredElement.checked; // Verify if the desired element is checked.
if (Zipify.OCU.api.isFormInvalid) desiredElement.style.display = 'block'; // Show the desired element if the form is invalid.
};
callbackBeforeRedirect
| Type | Description |
|---|---|
function |
Enables the execution of custom code immediately before redirecting to the checkout or cart. This can be beneficial for integrating with other apps, managing discounts, or controlling navigation behaviors based on specific conditions. |
Example:
Zipify.OCU.api.callbackBeforeRedirect = () => {
// Execute custom code
};Practical Application:
Consider a scenario where a store features both a cart drawer and an OCU product location. If the preference is to open the cart drawer rather than redirecting to a cart page, custom behavior can be implemented using this method.
Important: Always ensure this method returns a Promise that resolves with an empty object.
Extended Example:
Zipify.OCU.api.callbackBeforeRedirect = (dispatcher, event) => {
return new Promise((resolve) => {
try {
if (dispatcher.destination === 'checkout') return resolve({});
const { response, type } = event.detail;
if (!(type === 'Upgrade' && response.accepted)) return resolve({});
dispatcher._upsellAppInstance().hide();
setTimeout(() => Zipify.OCU.api.store.set('submitted', false));
} catch (e) {
resolve({});
}
});
};In this example, the callback prevents redirection to the checkout under specific conditions. Instead, it hides the upsell app instance and then ensures that the 'submitted' status in the OCU store is reset after a delay.
callbackAfterNativeClick
| Type | Description |
|---|---|
function |
Used to execute custom code after a native click callback. This can also be utilized to append attributes for discounts. |
Context:
The term "native click" refers to the default action that would occur when a button is clicked on a webpage. For instance, when a user clicks on the "Add to Cart" button, the usual behavior is to add the product to the cart. However, with Zipify's OCU, a popup might be shown first to offer the customer an upsell. After the customer accepts or declines the offer in the popup, the original action (i.e., adding the product to the cart) is then executed. This original action is termed as the "native click".
Example:
Zipify.OCU.api.callbackAfterNativeClick = () => {
// custom code goes here
}Zipify.OCU.api.callbackAfterNativeClick = () => {
setTimeout(Zipify.OCU.api.renderOCUDiscounts, 1000);
};
cartDiscountSelectors
| Type | Description |
|---|---|
object |
Used to define valid discount selectors within the cart. This is particularly helpful when default selectors are unidentifiable due to custom template implementations or when it's infeasible to add OCU data attributes. |
Example:
Zipify.OCU.api.cartDiscountSelectors = {
cartSubtotal: '.subtotal-price', // for cart subtotal
cartDiscount: '.discount-price', // for cart discount
disableWasPrice: false, // boolean value
wasTotalPrice: true, // boolean value
totalProductsPrice(lineItem) {
return `[data-line-item-key="${lineItem?.key}"] .price`;
},
productPrice(lineItem) {
return `[data-cart-item-id="${lineItem?.key}"] .price`;
},
showOriginalPrice(lineItem, state) {
const cartItem = document.querySelector(`[data-ocu-total-block-custom="${lineItem?.key}"]`);
if (!cartItem) return;
const originalItems = {
compare: cartItem.querySelector(`.compare-price`),
now: cartItem.querySelector(`.now-price`),
savings: cartItem.querySelector(`.savings-price`)
};
const ocuMoney = cartItem.querySelector('.ocu-money');
if (state) ocuMoney?.remove();
Object.values(originalItems).forEach((item) => {
if (item) item.classList.toggle('ocu-hidden', !state)
});
},
cartSubtotalCustom(subtotal) {
const isCart = '{{ template.name }}' === 'cart';
if (isCart) return;
const button = document.querySelector('a[href="/checkout"]');
if (!button) return;
button.innerHTML = button.innerHTML.replace(/\$\d+\.?\d*/, subtotal)
}
};
customRechargeUrl
| Type | Description |
|---|---|
string |
Provides the flexibility to modify the Recharge URL for the checkout process. This is especially handy when dealing with legacy Recharge. |
Example:
Zipify.OCU.api.customRechargeUrl = 'https://custom.url';
preventEventBeforeNativeClick
| Type | Description |
|---|---|
boolean |
Provides the ability to call preventDefault, stopPropagation, and stopImmediatePropagation for the event on the product location. This is particularly useful when other applications conflict with OCU and requires preventing such events. |
Example:
Zipify.OCU.api.preventEventBeforeNativeClick = true;
enableCollectionLocation*
| Type | Description |
|---|---|
boolean |
Used to add the ability to display the pre-purchase popup on the collection product page. |
Example:
Zipify.OCU.api.enableCollectionLocation = '{{ template.name }}' === 'collection';*Note: To display the OCU popup using this feature, product data from the liquid template is required. See next field: product for further details.
enableCustomPages*
| Type | Description |
|---|---|
array |
Used to add the ability to display the pre-purchase popup on custom product pages. |
Example:
Zipify.OCU.api.enableCustomPages = [
'/pages/custom-page-1',
'/pages/custom-page-2',
];Zipify.OCU.api.enableCustomPages = [
location.pathname // This will enable the feature for all custom pages.
];*Note: To display the OCU popup using this feature, product data from the liquid template is required. See next field: product for further details.
customPageName*
| Type | Description |
|---|---|
string |
Used to provide the ability to specify a custom page name for handling the display of the pre-purchase popup on a custom page. This should be used in conjunction with the enableCustomPages field. |
Example:
Zipify.OCU.api.customPageName = 'pageName';*Note: To display the OCU popup using this feature, product data from the liquid template is required. See next field: product for further details.
beforeCreate
| Type | Description |
|---|---|
function |
Provides the ability to execute a callback before rendering the pre-purchase popup. Useful for preliminary preparations. |
Example:
Zipify.OCU.api.beforeCreate = () => window.closeCart?.();
product
| Type | Description |
|---|---|
object |
Used to incorporate product data from liquid where it isn't natively accessible. This is useful for non-product pages or when the usual product context is not available. |
Example:
Zipify.OCU.api.product = {{ all_products['your-product-handle'] | json }};
moneyFormat
| Type | Description |
|---|---|
string |
Used to provide the capability to set a custom money format, especially for different currencies. |
Example:
Shopify.money_format = '\{\{amount_no_decimals_with_comma_separator\}\} Ft';
Zipify.OCU.api.moneyFormat = Shopify.money_format;
customSkipCart*
| Type | Description |
|---|---|
boolean |
Enables custom payload settings for the "Add to Cart" request in relation to the skip cart functionality. If set to true, it indicates the utilization of a custom payload. For the configuration of this payload, leverage the getCustomAddToCartData field. |
Example:
Zipify.OCU.api.customSkipCart = true;
Zipify.OCU.api.getCustomAddToCartData = (context) => {
try {
// code to get id, quantity, and payload
return { id, quantity, payload };
} catch (e) {
console.log(e);
return {};
}
};
customAllowUpsellsValidation
| Type | Description |
|---|---|
function |
Provides a mechanism to enforce upsell validation under specific conditions, especially useful when certain integrations misbehave. |
Example:
Zipify.OCU.api.customAllowUpsellsValidation = () => true;
preventRestoreXMLHttp
| Type | Description |
|---|---|
boolean |
OCU, by default, restores the XMLHttpRequest object. This setting allows you to control this behavior. When set to true, the restoration process is halted. Especially beneficial when integrating with platforms like Klickly where the default XMLHttpRequest behavior might not align with desired outcomes. |
Example:
Zipify.OCU.api.preventRestoreXMLHttp = true;
customShippingInsurance
| Type | Description |
|---|---|
object |
Enables the addition of shipping insurance to the cart through an OCU offer if a specific checkbox is selected. |
Example:
Zipify.OCU.api.customShippingInsurance = {
get enabled() {
return localStorage.getItem('insuranceAutoOn') === 'true';
},
set enabled(data) {
localStorage.setItem('insuranceAutoOn', data);
},
get price() {
return (window.SHIPPING_INSURANCE_PRICE ?? 0) * 100;
}
};
Other opportunities
| Opportunity | Description |
|---|---|
| Use liquid control flow | Liquid provides dynamic content rendering within Shopify templates. You can integrate conditions within snippets for more tailored customizations. |
Example:
{% if template.name == 'page' %}
// some code
{% endif %}Note: remember about Using Liquid for Customizations.