--- title: Customize a cart handler description: >- Customize a cart handler to perform different tasks and return different cart fields. source_url: html: >- https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler md: >- https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md --- ExpandOn this page * [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#requirements) * [Customize the return cart fields](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#customize-the-return-cart-fields) * [Add custom methods to cart handler](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#add-custom-methods-to-cart-handler) * [Override existing cart handler methods](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#override-existing-cart-handler-methods) # Customize a cart handler The cart handler is an interface that allows you to easily make cart query and mutation requests to the Storefront API. It creates a new cart if one doesn't already exist, and provides default built-in cart queries. This guide shows you how to customize a cart handler. You can customize a cart handler to return different cart query fields, override existing cart query functions, and add new cart query functions. *** ## Requirements * You've completed the [quickstart guide](https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started). * You've [set up a cart handler](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/setup). *** ## Customize the return cart fields The `createCartHandler` includes a default query fragment. Pass a custom `cartQueryFragment` if you need additional data from the Storefront API. See the [default `CartApiQuery` fragment](https://github.com/Shopify/hydrogen/blob/main/packages/hydrogen/src/cart/queries/cartGetDefault.ts) for reference. In this example, we added the `note` field. ## File ## server.js ##### JavaScript ```jsx const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), cartQueryFragment: CART_QUERY_FRAGMENT, // Your custom cart query fragment }); /** * cartQueryFragment requirements: * * - Must be named `CartApiQuery` * - Only have access to the following query variables: * - $cartId: ID! * - $country: CountryCode * - $language: LanguageCode * - $numCartLines: Int **/ const CART_QUERY_FRAGMENT = `#graphql fragment CartApiQuery on Cart { note id checkoutUrl totalQuantity buyerIdentity { countryCode customer { id email firstName lastName displayName } email phone } lines(first: $numCartLines) { edges { node { id quantity attributes { key value } cost { totalAmount { amount currencyCode } amountPerQuantity { amount currencyCode } compareAtAmountPerQuantity { amount currencyCode } } merchandise { ... on ProductVariant { id availableForSale compareAtPrice { ...CartApiMoney } price { ...CartApiMoney } requiresShipping title image { ...CartApiImage } product { handle title id } selectedOptions { name value } } } } } } cost { subtotalAmount { ...CartApiMoney } totalAmount { ...CartApiMoney } totalDutyAmount { ...CartApiMoney } totalTaxAmount { ...CartApiMoney } } note attributes { key value } discountCodes { applicable code } } fragment CartApiMoney on MoneyV2 { currencyCode amount } fragment CartApiImage on Image { id url altText width height } `; ``` ##### TypeScript ```jsx const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), cartQueryFragment: CART_QUERY_FRAGMENT, // Your custom cart query fragment }); /** * cartQueryFragment requirements: * * - Must be named `CartApiQuery` * - Only have access to the following query variables: * - $cartId: ID! * - $country: CountryCode * - $language: LanguageCode * - $numCartLines: Int **/ const CART_QUERY_FRAGMENT = `#graphql fragment CartApiQuery on Cart { note id checkoutUrl totalQuantity buyerIdentity { countryCode customer { id email firstName lastName displayName } email phone } lines(first: $numCartLines) { edges { node { id quantity attributes { key value } cost { totalAmount { amount currencyCode } amountPerQuantity { amount currencyCode } compareAtAmountPerQuantity { amount currencyCode } } merchandise { ... on ProductVariant { id availableForSale compareAtPrice { ...CartApiMoney } price { ...CartApiMoney } requiresShipping title image { ...CartApiImage } product { handle title id } selectedOptions { name value } } } } } } cost { subtotalAmount { ...CartApiMoney } totalAmount { ...CartApiMoney } totalDutyAmount { ...CartApiMoney } totalTaxAmount { ...CartApiMoney } } note attributes { key value } discountCodes { applicable code } } fragment CartApiMoney on MoneyV2 { currencyCode amount } fragment CartApiImage on Image { id url altText width height } `; ``` Provide `cartMutateFragment` to customize what data is returned from mutation queries. See the [default `CartApiMutation` fragment](https://github.com/Shopify/hydrogen/blob/main/packages/hydrogen/src/cart/queries/cart-fragments.ts) for reference. In this example, we added the `checkoutUrl` field. ## File ## server.js ##### JavaScript ```jsx const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), cartMutateFragment: CART_MUTATE_FRAGMENT, // Your custom cart mutate fragment }); /** * cartMutateFragment requirements: * * - Must be named `CartApiMutation` * - Only have access to the following query variables: * - $cartId: ID! * - $country: CountryCode * - $language: LanguageCode **/ const CART_MUTATE_FRAGMENT = `#graphql fragment CartApiMutation on Cart { id totalQuantity checkoutUrl } `; ``` ##### TypeScript ```jsx const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), cartMutateFragment: CART_MUTATE_FRAGMENT, // Your custom cart mutate fragment }); /** * cartMutateFragment requirements: * * - Must be named `CartApiMutation` * - Only have access to the following query variables: * - $cartId: ID! * - $country: CountryCode * - $language: LanguageCode **/ const CART_MUTATE_FRAGMENT = `#graphql fragment CartApiMutation on Cart { id totalQuantity checkoutUrl } `; ``` *** ## Add custom methods to cart handler If you have common cart operations that you would like to reuse across your app, you can add custom methods to your cart handler. For example, add and remove an item from the cart at the same time. ## File ## server.js ##### JavaScript ```jsx const cartQueryOptions = { storefront, getCartId: cartGetIdDefault(request.headers), }; const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), customMethods: { editInLine: async (addLines, removeLineIds, optionalParams) => { // Using Hydrogen default cart query methods // Add line items await cartLinesAddDefault(cartQueryOptions)(addLines, optionalParams); // Remove line items return await cartLinesRemoveDefault(cartQueryOptions)( removeLineIds, optionalParams, ); } }, }); ``` ##### TypeScript ```jsx import {type CartQueryOptions} from '@shopify/hydrogen'; const cartQueryOptions: CartQueryOptions = { storefront, getCartId: cartGetIdDefault(request.headers), }; const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), customMethods: { editInLine: async (addLines, removeLineIds, optionalParams) => { // Using Hydrogen default cart query methods // Add line items await cartLinesAddDefault(cartQueryOptions)(addLines, optionalParams); // Remove line items return await cartLinesRemoveDefault(cartQueryOptions)( removeLineIds, optionalParams, ); } }, }); ``` *** ## Override existing cart handler methods Hydrogen provides out of the box multiple methods for interacting with the cart. You can override any default method with your own logic. For example, you can override the `updateAttributes` to do something custom with cart attributes: The default cart handler includes basic cart logic. If you override these methods, you need to implement the cart logic as well. For example when adding a line item to a cart, you would need to implement the logic needed to create a cart with the line item. The following methods include create cart logic:: * `addLines` - If a cart doesn't exist, then create a cart with the line items. * `setMetafields` - If a cart doesn't exist, then create a cart with the metafields applied. * `updateAttributes` - If a cart doesn't exist, then create a cart with the attributes applied. * `updateBuyerIdentity` - If a cart doesn't exist, then create a cart with the buyer identity applied. * `updateDiscountCode` - If a cart doesn't exist, then create a cart with the discount applied. * `updateNote` - If a cart doesn't exist, then create a cart with the note applied. ## File ## server.js ##### JavaScript ```jsx const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), customMethods: { updateAttributes: async (attributes, optionalParams) => { // Do something with attributes // Make a mutation query to update cart attributes const {cartAttributesUpdate} = await options.storefront.mutate(CART_ATTRIBUTES_UPDATE_MUTATION, { variables: { cartId: optionalParams?.cartId || options.getCartId(), attributes, }, }); return cartAttributesUpdate; }, }, }); export const CART_ATTRIBUTES_UPDATE_MUTATION = `#graphql mutation cartAttributesUpdate( $cartId: ID! $attributes: [CartAttributeInput!]! ) { cartAttributesUpdate(cartId: $cartId, attributes: $attributes) { cart { id } } } `; ``` ##### TypeScript ```jsx const cart = createCartHandler({ storefront, getCartId: cartGetIdDefault(request.headers), setCartId: cartSetIdDefault(), customMethods: { updateAttributes: async (attributes, optionalParams) => { // Do something with attributes // Make a mutation query to update cart attributes const {cartAttributesUpdate} = await options.storefront.mutate<{ cartAttributesUpdate: CartQueryData; }>(CART_ATTRIBUTES_UPDATE_MUTATION, { variables: { cartId: optionalParams?.cartId || options.getCartId(), attributes, }, }); return cartAttributesUpdate; }, }, }); export const CART_ATTRIBUTES_UPDATE_MUTATION = `#graphql mutation cartAttributesUpdate( $cartId: ID! $attributes: [CartAttributeInput!]! ) { cartAttributesUpdate(cartId: $cartId, attributes: $attributes) { cart { id } } } `; ``` *** * [Requirements](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#requirements) * [Customize the return cart fields](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#customize-the-return-cart-fields) * [Add custom methods to cart handler](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#add-custom-methods-to-cart-handler) * [Override existing cart handler methods](https://shopify.dev/docs/storefronts/headless/hydrogen/cart/customize-cart-handler.md#override-existing-cart-handler-methods)