Preloading carts

Creating storefronts with products already added to the shopping cart.

Preloaded carts is a feature that allows storefront sessions to be created with certain products already added to the shopping cart. The logic may vary depending on the use case, for instance you may want to load a session with the last order made by some user or you want to send some set of products on sale already added to cart.

In order to get this feature working we'll need to follow a couple of steps:

  • Identify what items are going to be loaded to the cart
  • Set the cart items identifiers in the session metadata

Identifying items to load in the cart

In order to include cart item IDs into a Storefront, you need to follow a specifc pattern.

🚧

The pattern to include cart item IDs may change in the future. If it does, this document will be updated and the changes will be announced

Let's understand this pattern with an example of simple products first. Imagine the following products available for a storefront:

[
  {
      "_id": ObjectId("5fbc26458ef6b7c6596f6b66"),
      "name": "Bottle of Water",
      "sku": "YALO000013",
      "description": "Branded water",
      "ranking": 6,
      "imageURL": [
        "https://storage.googleapis.com/storefront-default-products/YALO000010.png"
      ],
      "size": 1,
      "type": "SINGLE",
      "minItems": 0,
      "maxItems": 1,
      "items": []
  },
  {
      "_id": ObjectId("5fbc26458ef6b759696f6b67"),
      "name": "Stickers",
      "sku": "YALO000014",
      "description": "25 units of Stickers",
      "ranking": 7,
      "imageURL": [
        "https://storage.googleapis.com/storefront-default-products/YALO000013.png"
      ],
      "size": 1,
      "type": "SINGLE",
      "minItems": 0,
      "maxItems": 1,
      "items": []
  },
  {
      "_id": ObjectId("5fbc26458ef6b791656f6b65"),
      "name": "Tags",
      "sku": "YALO000012",
      "description": "Tags",
      "ranking": 5,
      "imageURL": [
        "https://storage.googleapis.com/storefront-default-products/YALO000006.png"
      ],
      "size": 1,
      "type": "SINGLE",
      "minItems": 0,
      "maxItems": 1,
      "items": []
  }
]

With these set of products in mind (data doesn't include all product fields), imagine we want to preload two sets of stickers and one bottle of water. For simple products, the cart item ID is only the product ID, so you need to form an array of objects, like the one shown below, containing the cartId and quantity properties ,

[
  {
    "cartId": "5fbc26458ef6b759696f6b67"
    "quantity": 2
  },
  {
    "cartId": "5fbc26458ef6b7c6596f6b66",
    "quantity": 1
  }
]

This is all you need for simple products in the first step.

Now with customized products, the cartId changes because we need to support nested products, in order to do that, let's consider the following data sample:

[
  {
    "_id": ObjectId("5fbc26468ef6b724f56f6b70"),
    "name": "Playera Blanca",
    "sku": "YALO000001",
    "description": "Playera blanca",
    "ranking": 1,
    "imageURL": [
      "https://storage.googleapis.com/storefront-default-products/YALO000001.png"
    ],
    "size": 1,
    "type": "CUSTOM",
    "minItems": 0,
    "maxItems": 1,
    "items": [
      "5fbc26468ef6b78bad6f6b6d"
    ]
  },
  {
    "_id": ObjectId("5fbc26468ef6b79f876f6b71"),
    "name": "Bolsa",
    "sku": "YALO000006",
    "description": "Bolsa Reciclable",
    "ranking": 1,
    "imageURL": [
      "https://storage.googleapis.com/storefront-default-products/YALO000009.png"
    ],
    "size": 1,
    "type": "CUSTOM",
    "minItems": 0,
    "maxItems": 1,
    "items": [
      "5fbc26468ef6b7c77b6f6b6e"
    ]
  },
  {
    "_id": ObjectId("5fbc26468ef6b76c4a6f6b72"),
    "name": "Camisa Polo",
    "sku": "YALO000017",
    "description": "Camisa tipo polo",
    "ranking": 10,
    "imageURL": [
      "https://storage.googleapis.com/storefront-default-products/YALO000015.png"
    ],
    "size": 1,
    "type": "CUSTOM",
    "minItems": 0,
    "maxItems": 1,
    "items": [
      "5fbc26468ef6b71df96f6b6f"
    ]
  }
]

These products have a type CUSTOM and a nested array of items (product IDs) which let developers know that they are customized products. The UI runs a GraphQL query called productsPricedPerCollection which returns the whole data nested like in the following example:

{
  "data": {
    "productsPricedPerCollection": [
      {
        "id": "5fbc26468ef6b771046f6b73",
        "name": "Clothes",
        "enabledPrice": true,
        "productsPriced": [
          {
            "id": "5fbc26468ef6b724f56f6b70",
            "name": "White shirt",
            "sku": "YALO000001",
            "description": "White shirt",
            "category": "Clothes",
            "ranking": 1,
            "imageURL": [
              "https://storage.googleapis.com/storefront-default-products/YALO000001.png"
            ],
            "clientType": "",
            "showDescription": null,
            "price": 50,
            "type": "CUSTOM",
            "customizations": [
              {
                "id": "5fbc26468ef6b78bad6f6b6d",
                "name": "Size",
                "sku": "YALO000002",
                "description": "",
                "category": "",
                "ranking": 1,
                "imageURL": [""],
                "clientType": "",
                "price": 0,
                "showDescription": null,
                "size": 1,
                "type": "RADIO",
                "minItems": 0,
                "maxItems": 1,
                "conditionalAppearance": null,
                "customizations": [
                  {
                    "id": "5fbc26458ef6b7b8926f6b60",
                    "name": "Large",
                    "sku": "YALO000005",
                    "description": "large (l)",
                    "category": "Size",
                    "ranking": 1,
                    "imageURL": [""],
                    "clientType": "",
                    "price": 0,
                    "showDescription": null,
                    "size": 1,
                    "type": "RADIO",
                    "minItems": 0,
                    "maxItems": 1,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5fbc26458ef6b719436f6b5f",
                    "name": "Medium",
                    "sku": "YALO000004",
                    "description": "medium (m)",
                    "category": "Size",
                    "ranking": 1,
                    "imageURL": [""],
                    "clientType": "",
                    "price": 0,
                    "showDescription": null,
                    "size": 1,
                    "type": "RADIO",
                    "minItems": 0,
                    "maxItems": 1,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5fbc26458ef6b710eb6f6b5e",
                    "name": "Small",
                    "sku": "YALO000003",
                    "description": "small (s)",
                    "category": "Size",
                    "ranking": 1,
                    "imageURL": [""],
                    "clientType": "",
                    "price": 0,
                    "showDescription": null,
                    "size": 1,
                    "type": "RADIO",
                    "minItems": 0,
                    "maxItems": 1,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  }
                ],
                "__typename": "Product"
              }
            ],
            "__typename": "Product"
          }
        ],
        "__typename": "Collection"
      }
    ]
  }
}

So, what you need to know here is that the property customizations is recursive in order to support n levels of products. The pattern for the cartId we follow is {productId}_{categoryId1}-{customizationId1}-{customizationId2}-..._{categoryId2}-{customizationId1}-..._{categoryN}-{customizationN}-.... Let's imagine we want to preload a "White shirt of medium size". First, we need to identify first the IDs:

White shirt => productId: 5fbc26468ef6b724f56f6b70
Size => categoryId: 5fbc26468ef6b78bad6f6b6d
Medium => customizationId1: 5fbc26458ef6b719436f6b5f

In order to preload 3 units of this white shirt of medium size, we would end up with the following preloaded cart:

[
  {
    "cartId": "5fbc26468ef6b724f56f6b70_5fbc26468ef6b78bad6f6b6d-5fbc26458ef6b719436f6b5f",
    "quantity": 3
  }
]

Following the same criteria, we can go with a deeply nested example in order to illustrate better the cartId pattern. Consider the following customized product data sample:

{
  "data": {
    "productsPricedPerCollection": [
      {
        "id": "5f03919de6f02447c0073ecc",
        "name": "Pollo campero",
        "enabledPrice": true,
        "productsPriced": [
          {
            "id": "5f3ac61817a40508ab15ce4d",
            "name": "MenΓΊ SΓΊper Campero",
            "sku": "w41136",
            "description": "3 Piezas de Pollo, 2 acompaΓ±amiento, 1 complemento y bebida",
            "category": "Pollo campero",
            "ranking": 2,
            "imageURL": [
              "https://www.campero.com/iCadImagesMNC/Productos/w41136.png"
            ],
            "clientType": "City",
            "showDescription": true,
            "price": 57.5,
            "type": "CUSTOM",
            "customizations": [
              {
                "id": "5f3ac53c4789fe08ab83d757",
                "name": "Pieza Pollo Super",
                "sku": "",
                "description": "Piezas de pollo",
                "category": "Pieza Pollo",
                "ranking": 1,
                "imageURL": [],
                "clientType": "City",
                "price": 0,
                "showDescription": false,
                "size": 3,
                "type": "COUNTER",
                "minItems": 3,
                "maxItems": 3,
                "conditionalAppearance": null,
                "customizations": [
                  {
                    "id": "5f038856ab55cb47c09fb6eb",
                    "name": "pieza tradicional",
                    "sku": "43056",
                    "description": "Pieza de pollo tradicional",
                    "category": "Pieza Pollo",
                    "ranking": 1,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 3,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6ec",
                    "name": "pieza extracrujiente",
                    "sku": "43057",
                    "description": "Pieza de pollo extracrujiente",
                    "category": "Pieza Pollo",
                    "ranking": 2,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 3,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6ed",
                    "name": "pieza parrilla al limΓ³n",
                    "sku": "43058",
                    "description": "Pieza de pollo parrilla al limΓ³n",
                    "category": "Pieza Pollo",
                    "ranking": 3,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 3,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  }
                ],
                "__typename": "Product"
              },
              {
                "id": "5f3ac53c4789fe08ab83d758",
                "name": "AcompaΓ±amientos Super",
                "sku": "",
                "description": "AcompaΓ±amiento",
                "category": "AcompaΓ±amientos",
                "ranking": 2,
                "imageURL": [],
                "clientType": "City",
                "price": 0,
                "showDescription": false,
                "size": 2,
                "type": "CHECKBOX",
                "minItems": 0,
                "maxItems": 0,
                "conditionalAppearance": null,
                "customizations": [
                  {
                    "id": "5f038856ab55cb47c09fb6ee",
                    "name": "papas fritas medianas",
                    "sku": "41067",
                    "description": "papas fritas medianas",
                    "category": "AcompaΓ±amiento",
                    "ranking": 1,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 2,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6ef",
                    "name": "ensalada de repollo",
                    "sku": "41066",
                    "description": "ensalada de repollo",
                    "category": "AcompaΓ±amiento",
                    "ranking": 2,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 2,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6f0",
                    "name": "purΓ© de papa",
                    "sku": "41348",
                    "description": "purΓ© de papa",
                    "category": "AcompaΓ±amiento",
                    "ranking": 3,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 2,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6f1",
                    "name": "ensalada verde con limΓ³n",
                    "sku": "41408",
                    "description": "ensalada verde con limΓ³n",
                    "category": "AcompaΓ±amiento",
                    "ranking": 4,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 2,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6f2",
                    "name": "papas waffle grande",
                    "sku": "44357",
                    "description": "papas waffle grande",
                    "category": "AcompaΓ±amiento",
                    "ranking": 5,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 4,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 2,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6f3",
                    "name": "papas fritas grandes",
                    "sku": "41347",
                    "description": "papas fritas grandes",
                    "category": "AcompaΓ±amiento",
                    "ranking": 6,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 4,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 2,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  }
                ],
                "__typename": "Product"
              },
              {
                "id": "5f0389a40173cd47c0bd3cca",
                "name": "Bebidas",
                "sku": "",
                "description": "Bebida",
                "category": "Bebida",
                "ranking": 3,
                "imageURL": [],
                "clientType": "City",
                "price": 0,
                "showDescription": false,
                "size": 0,
                "type": "RADIO",
                "minItems": 0,
                "maxItems": 1,
                "conditionalAppearance": null,
                "customizations": [
                  {
                    "id": "5f038856ab55cb47c09fb6f4",
                    "name": "pepsi",
                    "sku": "44464",
                    "description": "pepsi",
                    "category": "Bebida",
                    "ranking": 1,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 1,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6f5",
                    "name": "tΓ© lipton limΓ³n",
                    "sku": "43902",
                    "description": "tΓ© lipton limΓ³n",
                    "category": "Bebida",
                    "ranking": 2,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 0,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 1,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  },
                  {
                    "id": "5f038856ab55cb47c09fb6f6",
                    "name": "belight rosa jamaica",
                    "sku": "27148",
                    "description": "belight rosa jamaica",
                    "category": "Bebida",
                    "ranking": 3,
                    "imageURL": [],
                    "clientType": "City",
                    "price": 2.5,
                    "showDescription": false,
                    "size": 0,
                    "type": "SINGLE",
                    "minItems": 0,
                    "maxItems": 1,
                    "conditionalAppearance": null,
                    "__typename": "Product"
                  }
                ],
                "__typename": "Product"
              }
            ],
            "__typename": "Product"
          }
        ],
        "__typename": "Collection"
      }
    ]
  }
}

For this example, we have a different set of options in order to customize our products. So let's say we want 2 "MenΓΊ SΓΊper Campero" with "piezas tradicionales" and "pieza extracrujiente" flavors with "papas fritas medianas" and "purΓ© de papas" as sides and finally a "pepsi" drink. Let's identify the IDs:

MenΓΊ SΓΊper Campero => productId: 5f3ac61817a40508ab15ce4d
Pieza Pollo SΓΊper => categoryId: 5f3ac53c4789fe08ab83d757
Pieza tradicional => customizationId: 5f038856ab55cb47c09fb6eb
Pieza Extracrujiente => customizationId: 5f038856ab55cb47c09fb6ec
AcompaΓ±amientos SΓΊper => categoryId: 5f3ac53c4789fe08ab83d758 
Papas fritas medianas => customizationId: 5f038856ab55cb47c09fb6ee
PurΓ© de papa => customizationId: 5f038856ab55cb47c09fb6f0
Bebidas => categoryId: 5f0389a40173cd47c0bd3cca
Pepsi => customizationId: 5f038856ab55cb47c09fb6f4

The cartId form fill look a bit long but follows the same pattern:

[
  {
    "cartId": "5f3ac61817a40508ab15ce4d_5f3ac53c4789fe08ab83d757-5f038856ab55cb47c09fb6eb-5f038856ab55cb47c09fb6ec_5f3ac53c4789fe08ab83d758-5f038856ab55cb47c09fb6ee-5f038856ab55cb47c09fb6f0_5f0389a40173cd47c0bd3cca-5f038856ab55cb47c09fb6f4",
    "quantity": 2
  }
]

πŸ“˜

Preloaded Cart generation

In this doc we took a look at the manual steps (algorithm) to generate the preloaded cart, however this is expected to be run in a process before sending the storefront link in the workflow interacting with the end user. For instance, if it's a last order preloaded, cartIds are saved in the order which will avoid you to generate this cartIds, when sending sale offers you may consider reading the products data and form this IDs.

Adding preloaded cart to storefront session

This step is a simple one, since the session is created by running a GraphQL mutation called createOrderConfig, which looks like this:

mutation createCamperoSessionWithEmptyCart {
  createOrderConfig(data:{
    botSlug: "campero",
    channelID: "+5215591413100",
    channelName: "whatsapp",
    userID: "5516453380",
    collections: [
      "5f03919de6f02447c0073ecc",
      "5f3ad0ae66b15408abb3b984"
    ],
    ttl: 0,
    metadata: null
  }) {
    id
  }
}

In order to add the preloaded cart to the order config, we'll need to add a cart property to the metadata field:

mutation createCamperoSessionWithPreloaderCart {
  createOrderConfig(data:{
    botSlug: "campero",
    channelID: "+5215591413100",
    channelName: "whatsapp",
    userID: "5516453380",
    collections: [
      "5f03919de6f02447c0073ecc",
      "5f3ad0ae66b15408abb3b984"
    ],
    ttl: 0,
    metadata: "{\"cart\":[{\"cartId\": \"5fbc26458ef6b759696f6b67\",\"quantity\": 2},{\"cartId\":\"5fbc26458ef6b7c6596f6b66\",\"quantity\":1}]}"
  }) {
    id
  }
}

And that's it. Now you can use the Order Config ID returned to open your storefront with a session containing a preloaded cart. Enjoy :tada:

πŸ“˜

Order Config Metadata Type

As you may guess from the code, the metadata field is a stringified version of an object containing a "cart" property with the array we formed in the previous step. Since this is expected to be run programmatically you won't be affected by putting a plain readable object inside a JSON.stringify() like method in your programming language of choice.


Did this page help you?