Skip to main content

Storefront Library

Background, Motivation and Requirements​

The Storefront Library was developed as part of the Checkout 2.0 project.

Background: With Checkout 2.0, the discount capabilities were significantly expanded and thus became more complex. Differences compared to the old discount system using Shopify Scripts include:

  • Discounts can also be applied based on variants.

  • For free products, any number of thresholds are possible. Similarly, multiple different products can be linked at a threshold using "and" or "or" logic.

  • With "conditional Discounts", a new type of discount was introduced that can cover cases such as:

    • Tiered pricing
    • BOGO (Buy one get one free)
    • Buy two products, get one free.
    • Buy one product, get x% discount on another product.
    • Buy Product A for €50, get 70% discount on Product B.
    • 40% discount on the first three units of a product, but only the standard discount of 10% from the fourth unit onwards.
    • Four for three: Buy four products, get the cheapest one free.

To display strikethrough prices in categories and on products after entering a discount code, a tool was needed that can also determine the strikethrough prices for the new discount types correctly and reliably. Everything that is taken into account in the checkout must be considered.

Due to the new complexity, it was decided from the beginning to avoid requiring a storefront developer to learn about discounting when they need to create functionality related to discounts. Therefore, it was decided to develop a library that can be used by anyone as a black box. This means: The developer can call the library's functions without having to worry about the details of the calculations. As a result, all functions needed in the discount context are in one place, avoiding a patchwork that is difficult to oversee and maintain.

Specifically, the following functions related to discounting were needed:

  • Setting, changing and removing discount codes.
  • Calculation of the discounted product price for displaying the strikethrough price.
  • Separate query of conditional discounts for a product.
  • Information for the free product assignment process:
    • Determination of thresholds.
    • Determine for each threshold whether available products exist.
    • Determination of products that should be free but have not yet been assigned.
    • Determination of free products for the next threshold.
    • Determination of all previously assigned free products.
  • Determination of information for the shipping cost bar based on standard shipping and shipping discounts:
    • Standard shipping costs
    • Standard threshold
    • Information on whether the threshold has been reached.
  • Bundle prices (for display in collections).
  • Determination of the standard discount code (usually "aktion" in DE, "promo" in NL).
  • Determination of the standard discount (percentage or amount).

Methods​

The Storefront Library returns an object named co2 that provides the following methods.

getDiscountCode​

Purpose:

Determine the currently set discount code.

Example call:

await co2.getDiscountCode();

Parameters:

None

Return value:

Discount code (string) or false (boolean). false is returned if no discount code is set.

getDiscountType​

Purpose:

Determine whether the currently set discount code is an influencer code.

Example call:

await co2.getDiscountType();

Parameters:

None

Return value:

"infl", "pub" (string) or false (boolean). Meanings:

  • "infl" => Influencer code
  • "pub" => Not an influencer code
  • false => No code set

setDiscountCode​

Purpose:

Set a discount code. For example, after input by the user in an input field.

Example call:

await co2.setDiscountCode("aktion");

Parameters:

Discount code (string)

Return value:

true or false (boolean). Meanings:

  • true => Discount code set
  • false => Discount code unknown or invalid

removeDiscountCode​

Purpose:

Remove the currently set discount code.

Example call:

await co2.removeDiscountCode();

Parameters:

None

Return value:

true (boolean). Meaning: Discount code successfully removed.

standardDiscountCode​

Purpose:

Determine the discount code of the main campaign for the current market.

Example call:

await co2.standardDiscountCode();

Parameters:

None

Return value:

Discount code (string) or false (boolean). false is returned if there is currently no main campaign.

currentCampaignCodes​

Purpose:

Determine the discount codes of the main campaign for the current market as well as information on whether influencer codes belong to this campaign.

Example call:

await co2.currentCampaignCodes();

Parameters:

None

Return value:

Object with two properties:

  • infl_codes (boolean): Whether the main campaign includes influencer codes
  • disc_codes (string[]): Discount codes of the main campaign

Example:

{
disc_codes: ["aktion", "htfit"],
infl_codes: true
}

isCurrentCampaignCode​

Purpose:

Determine whether the currently set discount code belongs to the main campaign of the current market.

Example call:

await co2.isCurrentCampaignCode();

Parameters:

None

Return value:

  • true: Code belongs to the main campaign
  • false: Code does not belong to the main campaign
  • undefined: No discount code is currently set

getDiscountTokens​

Purpose:

Returns the discount tokens as an array that are currently set in the cart attribute "disc_tokens". With a discount token, an additional discount can be easily activated since only a cart attribute needs to be set. The corresponding discount must be created in the campaign and marked with the token. They are intended for applications like wheel of fortune or Easter egg hunt.

Example call:

await co2.getDiscountTokens();

Parameters:

None.

Return value:

Array with the currently set discount tokens or false (if no discount tokens are set). Example:

["wheel"]

setDiscountTokens​

Purpose:

Set one or more discount tokens.

Example call:

await co2.setDiscountTokens(["wheel"]);

Parameters:

Array of strings.

Return value:

false if input is invalid or empty array. true otherwise (success).

removeDiscountTokens​

Purpose:

Remove the currently set discount tokens.

Example call:

await co2.removeDiscountTokens();

Parameters:

None.

Return value

true

itemDiscountFull​

Purpose:

Calculate the discount on a product variant for displaying the strikethrough price in collections and on the product page. All discount types are taken into account.

Example call:

await co2.itemDiscountFull(
123456789,
987654321,
[
"category-a",
"category-b",
"sale",
"featured",
"tag-1",
"tag-2"
],
2999,
1
);

Parameters:

The product properties required to calculate the discount are passed:

  • product_id (number, required),
  • variant_id (number, required),
  • tags (string[], required),
  • sub_total (number, undiscounted price in cents, required),
  • quantity (number, optional, default: 1),
  • subscription (boolean, sale with selling plan, optional, default: false)

Return value:

Object with information for displaying the strikethrough price. Example:

{
"calc": "perc",
"discPerc": 25,
"discAmt": 0,
"discPrice": 2249,
"condPerc": 30
}

Meaning of the properties:

  • calc: Can be "perc" (percentage discount) or "amt" (amount discount).
  • discPerc: Percentage if percentage discount, 0 otherwise,
  • discAmt: Discount in cents if amount discount, 0 otherwise.
  • discPrice: Discounted price in cents.
  • condPerc: Maximum possible percentage discount via conditional discounts.

itemDiscount​

Purpose:

Calculate the discount on a product variant without considering conditional discounts. This means: The discPrice property is only calculated based on the standard discount groups. However, the maximum possible percentage discount is returned for conditional discounts.

Example call:

await co2.itemDiscount(
123456789,
987654321,
[
"category-a",
"category-b",
"sale",
"featured",
"tag-1",
"tag-2"
],
2999,
1
);

Parameters:

The product properties required to calculate the discount are passed:

  • product_id (number, required),
  • variant_id (number, required),
  • tags (string[], required),
  • sub_total (number, undiscounted price in cents, required),
  • quantity (number, optional, default: 1),
  • subscription (boolean, sale with selling plan, optional, default: false)

Return value:

Object with information for displaying the strikethrough price. If no discount is found, then discPerc and discAmt are 0, and discPrice equals the sub_total parameter. Example:

{
"calc": "perc",
"discPerc": 20,
"discAmt": 0,
"discPrice": 2399,
"condPerc": 30
}

Meaning of the properties:

  • calc: Can be "perc" (percentage discount) or "amt" (amount discount).
  • discPerc: Percentage if percentage discount, 0 otherwise,
  • discAmt: Discount in cents if amount discount, 0 otherwise.
  • discPrice: Discounted price in cents.
  • condPerc: Maximum possible percentage discount via conditional discounts.

standardDiscount​

Purpose:

Calculate the discount on a product variant with the discount code of the main campaign. Used for display on the product when the user has no discount code in the cart.

Example call:

await co2.standardDiscount(
123456789,
987654321,
[
"category-a",
"category-b",
"sale",
"featured",
"tag-1",
"tag-2"
],
2999,
1
);

Parameters:

The product properties required to calculate the discount are passed:

  • product_id (number, required),
  • variant_id (number, required),
  • tags (string[], required),
  • sub_total (number, undiscounted price in cents, required),
  • quantity (number, optional, default: 1),
  • subscription (boolean, sale with selling plan, optional, default: false)

Return value:

Object with information about the discount on a product when applying the standard discount. If no discount is found, then discPerc and discAmt are 0, and discPrice equals the sub_total parameter. Example:

{
"calc": "perc",
"discPerc": 20,
"discAmt": 0,
"discPrice": 2399
}

Meaning of the properties:

  • calc: Can be "perc" (percentage discount) or "amt" (amount discount).
  • discPerc: Percentage if percentage discount, 0 otherwise,
  • discAmt: Discount in cents if amount discount, 0 otherwise.
  • discPrice: Discounted price in cents.

conditionalDiscounts​

Purpose:

Returns the conditional discounts where the condition settings or discount settings (or both) relate to the product/product variant.

Example call:

await co2.conditionalDiscounts(
123456789,
987654321,
[
"category-a",
"category-b",
"sale",
"featured"
]
);

Parameters:

  • product_id (number, required)
  • variant_id (number, required)
  • tags (string[], required)

Return value:

Returns an object with the properties rule_applies and condition_applies. If no conditional discounts are found, both arrays are empty. Meaning of the arrays:

  • An entry in condition_applies means that the condition matches the product.
  • An entry in rule_applies means that the discount is applicable to the product.

In the example, it is defined that you get a 50% discount on Product A (product ID 111111111) when you buy Product B (product ID 222222222):

{
"rule_applies": [],
"condition_applies": [
{
"quant": 1,
"count": 0,
"disc_perc": 50,
"base": "prods",
"tags": [],
"ex_tags": [],
"product_items": [
111111111
],
"product_variant_items": [],
"multi_apply": "multiply",
"cond_base": "prods",
"cond_tags": [],
"cond_ex_tags": [],
"cond_product_items": [
222222222
],
"cond_product_variant_items": [],
"cond_minimum": "quant",
"cond_quant": 1,
"cond_threshold": 0,
"cond_count": 1,
"cond_sub_total": 0,
"cond_threshold_used": 0,
"cond_text": ""
}
]
}

An entry in the rule_applies or condition_applies array has the following properties. Note that all fields beginning with "cond_" belong to the condition part, while the other fields define the discount.

  • quant: Number of products for which the discount applies (number). This value must be considered together with the multi_apply field. If multi_apply is "once", then the discount is only applied quant times. In the example, this would mean that the customer only gets 50% on Product A once, no matter how many units of Product B they buy. Here, however, the setting is "multiply". This means: If the customer buys n units of Product B, they also get the discount on Product A n times. There is also the setting "unlimited", which is used, for example, with tiered pricing where the discount applies unlimited times.
  • count: Number of products in the cart to which the discount has been applied (number).
  • disc_perc: Discount in % (number).
  • base: The products to be discounted can be defined by specifying products ("prods"), variants ("vars") or tags ("tags") (string).
  • tags: Array of tags if base == "tags" (string[]).
  • ex_tags: Array of exclusion tags if base == "tags" (string[]).
  • kind: Set for conditional discounts that are tiered pricing. Then has the value "tiered_pricing". Otherwise the property does not exist.
  • product_items: Array of product IDs if base == "prods" (number[]).
  • product_variant_items: Array of variant objects if base == "vars". Each object has two properties: pid (product ID) and vids (variant IDs).
  • multi_apply: "once", "multiply" or "unlimited" (string).
  • cond_base: Refers to the products of the condition and can be "prods", "vars" or "tags" analogous to base (string).
  • cond_tags: Array of tags if cond_base == "tags" (string[]).
  • cond_ex_tags: Array of exclusion tags if cond_base == "tags" (string[]).
  • cond_product_items: Array of product IDs if cond_base == "prods" (number[]).
  • cond_product_variant_items: Array of variant objects if cond_base == "vars".
  • cond_minimum: Expresses whether the condition refers to a minimum quantity ("quant") or a minimum amount ("threshold") (string).
  • cond_quant: Minimum quantity if cond_minimum == "quant" (number). 0 otherwise.
  • cond_threshold: Minimum amount if cond_minimum == "threshold" (number). 0 otherwise.
  • cond_count: Number of products in the cart that meet the condition if cond_minimum == "quant" (number). 0 otherwise.
  • cond_sub_total: Sum of the discounted prices of products that meet the condition if cond_minimum == "threshold" (number). 0 otherwise.
  • cond_threshold_used: If cond_minimum == "threshold" and the rule could be applied, then the threshold that was used when applying (number).
  • cond_text: Information text for output on the product (string).

freeProductThresholds​

Purpose:

Determine the free product thresholds for display in the cart.

Example call:

await co2.freeProductThresholds();

Parameters:

None

Return value:

Array with the free product thresholds in cents (number[]). The array is empty if there are no free products. Example:

[5000, 7500, 10000]

Meaning: Thresholds in cents.

thresholdAvailabilities​

Purpose:

Determine product availability for free product thresholds. Used for display in the cart.

Example call:

await co2.thresholdAvailabilities();

Parameters:

None

Return value:

Array of objects with free product threshold and product availability. Example:

[
{
"thresh": 5000,
"available": true
},
{
"thresh": 7500,
"available": true
},
{
"thresh": 10000,
"available": true
}
]

Meaning:

  • thresh: Free product threshold (number).
  • available: Available products exist (boolean).

freeProductKeys​

Purpose:

Determine the item keys of free products in the cart.

Example call:

await co2.freeProductKeys();

Parameters:

None

Return value:

Array with the item keys of free products (string[]). The array is empty if there are no free products. Example:

[
"111111111:abc123def456ghi789",
"222222222:jkl012mno345pqr678",
"333333333:stu901vwx234yz567"
]

Meaning: Item keys with which free products can be identified in the cart.

unredeemedFreeProducts​

Purpose:

Determine the free products that the customer is entitled to but are not yet in the cart. Sold-out products are not returned.

Example call:

await co2.unredeemedFreeProducts();

Parameters:

None

Return value:

Array with free product objects. The array is empty if there are no free products. Example:

[
{
"threshold": 5000,
"sub_total": 7553,
"unredeemedQty": 1,
"base": "prods",
"productItems": [
"product-a",
"product-b"
],
"productVariantItems": [],
"addAutomatically": false
},
{
"threshold": 5000,
"sub_total": 7553,
"unredeemedQty": 2,
"base": "vars",
"productItems": [],
"productVariantItems": [
{
"handle": "product-c",
"variant_ids": [
111111111
]
},
{
"handle": "product-d",
"variant_ids": [
222222222,
333333333,
444444444
]
}
],
"addAutomatically": false
},
{
"threshold": 7500,
"sub_total": 7553,
"unredeemedQty": 1,
"base": "prods",
"productItems": [
"product-e"
],
"productVariantItems": [],
"addAutomatically": true
}
]

Meaning:

The objects have the following properties:

  • threshold: Threshold in cents (number),
  • sub_total: Current cart total in cents (number),
  • unredeemedQty: Quantity the customer should receive (number),
  • base: Can be "prods" (products) or "vars" (variants).
  • For "prods", the productItems array contains the handles of the alternative products.
  • For "vars", the productVariantItems array is relevant. It then contains an object for each alternative product with "handle" (product handle) and "variant_ids" (allowed variant IDs).
  • addAutomatically: Whether the product should be automatically added to the cart (boolean).

nextFreeProducts​

Purpose:

Determine the free products that the customer receives at the next threshold that has not yet been reached.

Example call:

await co2.nextFreeProducts();

Parameters:

None

Return value:

Object with information about the next threshold that has not yet been reached. If there is no (more) threshold, then false is returned. Example:

{
"threshold": 10000,
"sub_total": 7553,
"items": [
{
"threshold": 10000,
"sub_total": 7553,
"unredeemedQty": 1,
"base": "prods",
"productItems": [
"product-f"
],
"productVariantItems": [],
"addAutomatically": true
}
]
}

Meaning:

The object properties have the following meaning:

  • threshold: Next threshold in cents (number),
  • sub_total: Current cart total in cents (number),
  • items: Array with free product objects. The structure is identical to the array returned by unredeemedFreeProducts.

freeProductData​

Purpose:

Determine the data of all products that are defined as free products for the current campaign. For each product, all available variants are returned.

Example call:

await co2.freeProductData();

Parameters:

None

Return value:

Array with free products. The array is empty if there are no free products. Example (abbreviated):

[
{
"id": 123456789,
"title": "Sample Product",
"handle": "sample-product",
"productType": "Product Type",
"image": "https://cdn.example.com/image.png",
"variants": [
{
"id": 987654321,
"title": "Default Title",
"price": 1990,
"image": "https://cdn.example.com/image.png"
}
]
}
]

Meaning:

The product objects have the following properties:

  • id: Product ID (number)
  • title: Product title (string)
  • handle: Product handle (string)
  • productType: Product type (string)
  • image: URL of featured image (string)
  • variants: Array with all available variant objects. Properties are:
    • id: Variant ID (number)
    • title: Variant title (string)
    • price: Variant price in cents (number)
    • image: URL of variant image (string)

shippingData​

Purpose:

Determine the information about shipping costs that is relevant for display in the cart.

Example call:

await co2.shippingData("DE", []);

Parameters:

  • country (string, required): Country code, e.g.: "DE".
  • customerTags (string[], required): Customer tags if logged in, empty array otherwise.

Return value:

Object with information about shipping costs. Basis for graphical display in the cart. Example:

{
"standardPrice": 490,
"standardThreshold": 5500,
"campaignThreshold": 2500,
"sub_total": 12950,
"freeShipping": true
}

Meaning:

  • standardPrice: Standard shipping costs for the passed country (number).
  • standardThreshold: Standard threshold for the passed country (number).
  • campaignThreshold: Shipping cost threshold of the current campaign, depending on country and customer tags, among other things (number).
  • sub_total: Subtotal in the cart without excluded products (number).
  • freeShipping: Whether shipping is free (boolean).

bundleDataForCollection​

Deprecated

This method has been replaced by bundleDataForCollectionProduct.

Purpose:

Determine the prices of multiple bundles when they are displayed in a collection.

Example call:

await co2.bundleDataForCollection([
123456789,
234567890,
345678901,
456789012,
567890123,
678901234
]);

Parameters:

  • bundleIds (number[], required): Array of bundle product IDs.

Return value:

For each bundle referenced by ID, information about price and availability is returned. Example:

[
{
"id": 123456789,
"available": true,
"price": 2990,
"bundleDiscPrice": 2990
},
{
"id": 234567890,
"available": true,
"price": 2990,
"bundleDiscPrice": 2990
}
]

Meaning:

An array of bundle objects is returned, each with four properties:

  • id: Product ID of the bundle parent (number).
  • available: Whether the bundle is available (boolean). That is: Whether none of the products in the bundle are sold out.
  • price: Price sum of the products contained in the bundle (number).
  • bundleDiscPrice: If a price reduction is defined on the bundle, this is the correspondingly reduced price (number). Additionally, there can be a campaign discount on the bundle, which is not considered here.

bundleDataForCollectionProduct​

Purpose:

Determine the prices and availability of multiple bundles when they are displayed in a collection. Due to the component-based structure, the bundle information is requested per product. Internally, the Storefront Library loads all potential bundles once on the first call and then returns the corresponding data.

Example call:

await co2.bundleDataForCollectionProduct(123456789);

Parameters:

  • bundleId (number, required): Bundle product ID.

Return value:

For each bundle referenced by ID, information about price and availability is returned. Additionally, information about the type of bundle discount is returned, which is needed for displaying the corresponding badge. Example:

{
"id": 123456789,
"available": true,
"calc": "perc",
"discountAmount": 0,
"discountPercent": 10,
"price": 2990,
"bundleDiscPrice": 2990
}

Meaning:

A bundle object is returned with the following properties:

  • id: Product ID of the bundle parent (number).
  • available: Whether the bundle is available (boolean). That is: Whether none of the products in the bundle are sold out.
  • calc: Whether the discount is absolute or percentage ("perc" or "amt").
  • discountAmount: Amount of the absolute discount, already delivered by the Storefront library in the currently set shop currency (number).
  • discountPercent: Amount of the percentage discount (number).
  • price: Price sum of the products contained in the bundle (number).
  • bundleDiscPrice: If a price reduction is defined on the bundle, this is the correspondingly reduced price (number). Additionally, there can be a campaign discount on the bundle, which is not considered here.