--- title: Updating to 2024-10 description: > Some checkouts may be created with [cart instructions](/docs/api/checkout-ui-extensions/apis/cart-instructions) that prevent buyers from making certain changes to their checkout. As of version `2024-07`, UI extensions must check for instructions before calling select APIs, to properly handle checkouts where those APIs are not available. > Caution: As of **July 22nd, 2024**, all UI extensions on this version will render in **draft order** invoice checkouts. As draft order invoice checkouts have restrictions on what buyers can edit, UI extensions in draft order invoice checkouts will be subject to cart instructions. api_version: 2024-10 api_name: checkout-ui-extensions source_url: html: >- https://shopify.dev/docs/api/checkout-ui-extensions/2024-10/instructions-update md: >- https://shopify.dev/docs/api/checkout-ui-extensions/2024-10/instructions-update.md --- # Updating to 2024-10 Some checkouts may be created with [cart instructions](https://shopify.dev/docs/api/checkout-ui-extensions/apis/cart-instructions) that prevent buyers from making certain changes to their checkout. As of version `2024-07`, UI extensions must check for instructions before calling select APIs, to properly handle checkouts where those APIs are not available. Caution As of **July 22nd, 2024**, all UI extensions on this version will render in **draft order** invoice checkouts. As draft order invoice checkouts have restrictions on what buyers can edit, UI extensions in draft order invoice checkouts will be subject to cart instructions. *** ## Required instruction checking You will need to check for cart instructions before calling the following APIs: | Extension API | As of July 2024 | | - | - | | applyAttributeChange() | Attributes cannot be modified on draft order checkouts. | | applyShippingAddressChange() | Buyers cannot change the address on a draft order checkout if it has fixed shipping rates. | | applyDiscountCodeChange() | By default, discounts cannot be modified in draft order checkouts. Merchants must allow it via a setting on the draft order. | | applyCartLinesChange() | Cart lines cannot be modified on draft order checkouts. | | applyMetafieldChange() | Cart metafields cannot be modified on draft order checkouts. Metafields can still be modified. | | applyNoteChange() | Notes cannot be modified on draft order checkouts. | Caution If you don't check for instructions, the APIs will return an error when they're not available in a given checkout [Learn more - Cart Instructions API](https://shopify.dev/docs/api/checkout-ui-extensions/apis/cart-instructions) *** ## Checking for cart instructions Use the cart instructions API to determine if the affected APIs are available in checkout. Changes to applyAttributeChange() Check `instructions.attributes.canUpdateAttributes` before calling `applyAttributeChange()`. Changes to applyShippingAddressChange() Check `instructions.delivery.canSelectCustomAddress` before calling `applyShippingAddressChange()`. When `true`, this instruction implies that extensions can change the shipping address. Changes to applyDiscountCodeChange() Check `instructions.discounts.canUpdateDiscountCodes` before calling `applyDiscountCodeChange()`. Changes to applyCartLinesChange() Check `instructions.lines.canAddCartLine` or `instructions.lines.canRemoveCartLine` or `instructions.lines.canUpdateCartLine` before calling `applyCartLinesChange()`. Changes to applyMetafieldChange() Check `instructions.metafields.canSetCartMetafields` or `instructions.metafields.canDeleteCartMetafields` before calling `applyMetafieldChange()` if you are working with cart metafields. Changes to applyNoteChange() Check `instructions.notes.canUpdateNote` before calling `applyNoteChange()`. ## Migrating applyAttributeChange() ##### React ```jsx import { Banner, Button, useApplyAttributeChange, useInstructions, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const applyAttributeChange = useApplyAttributeChange(); const instructions = useInstructions(); if ( instructions.attributes.canUpdateAttributes ) { return ( ); } else { return ( Loyalty points are unavailable ); } } ``` ##### JavaScript ```js import { extension, Banner, Button, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, api) => { if ( api.instructions.current.attributes .canUpdateAttributes ) { root.appendChild( root.createComponent( Button, { onPress: () => api.applyAttributeChange({ type: 'updateAttribute', key: 'loyaltyPoints', value: '100', }), }, 'Apply 100 loyalty points', ), ); } else { root.appendChild( root.createComponent( Banner, {}, 'Loyalty points are unavailable', ), ); } }, ); ``` ## Migrating applyShippingAddressChange() ##### React ```jsx import { Banner, Button, useApplyShippingAddressChange, useInstructions, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const applyShippingAddressChange = useApplyShippingAddressChange(); const instructions = useInstructions(); if ( instructions.delivery.canSelectCustomAddress ) { return ( ); } else { return ( Shipping address cannot be modified ); } } ``` ##### JavaScript ```js import { extension, Banner, Button, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, api) => { if ( api.instructions.current.delivery .canSelectCustomAddress ) { root.appendChild( root.createComponent( Button, { onPress: () => api.applyShippingAddressChange({ type: 'updateShippingAddress', address: { zip: '90201', }, }), }, 'Change your postal code', ), ); } else { root.appendChild( root.createComponent( Banner, {}, 'Shipping address cannot be modified', ), ); } }, ); ``` ## Migrating applyDiscountCodeChange() ##### React ```jsx import { Banner, Button, useApplyDiscountCodeChange, useInstructions, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const applyDiscountCodeChange = useApplyDiscountCodeChange(); const instructions = useInstructions(); if ( instructions.discounts.canUpdateDiscountCodes ) { return ( ); } else { return ( Loyalty discounts are unavailable ); } } ``` ##### JavaScript ```js import { extension, Banner, Button, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, api) => { if ( api.instructions.current.discounts .canUpdateDiscountCodes ) { root.appendChild( root.createComponent( Button, { onPress: () => api.applyDiscountCodeChange({ type: 'addDiscountCode', code: 'FREE_SHIPPING', }), }, 'Apply your loyalty discount', ), ); } else { root.appendChild( root.createComponent( Banner, {}, 'Loyalty discounts are unavailable', ), ); } }, ); ``` ## Migrating applyCartLinesChange() ##### React ```jsx import { Banner, Button, useApplyCartLinesChange, useInstructions, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const applyCartLinesChange = useApplyCartLinesChange(); const instructions = useInstructions(); if (instructions.lines.canAddCartLine) { return ( ); } else { return ( The products in your cart cannot be modified ); } } ``` ##### JavaScript ```js import { extension, Banner, Button, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, api) => { if ( api.instructions.current.lines .canAddCartLine ) { root.appendChild( root.createComponent( Button, { onPress: () => api.applyCartLinesChange({ type: 'addCartLine', merchandiseId: 'gid://shopify/product/1234', quantity: 1, }), }, 'Add a free gift to your order', ), ); } else { root.appendChild( root.createComponent( Banner, {}, 'The products in your cart cannot be modified', ), ); } }, ); ``` ## Migrating applyMetafieldChange() ##### React ```jsx import { Banner, Button, useApplyMetafieldChange, useInstructions, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const applyMetafieldChange = useApplyMetafieldChange(); const instructions = useInstructions(); if ( instructions.metafields.canSetCartMetafields ) { return ( ); } else { return ( Loyalty points are unavailable ); } } ``` ##### JavaScript ```js import { extension, Banner, Button, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, api) => { if ( api.instructions.current.metafields .canSetCartMetafields ) { root.appendChild( root.createComponent( Button, { onPress: () => api.applyMetafieldChange({ type: 'updateCartMetafield', metafield: { namespace: 'loyalty', key: 'loyaltyPoints', value: '100', type: 'string', }, }), }, 'Apply 100 loyalty points', ), ); } else { root.appendChild( root.createComponent( Banner, {}, 'Loyalty points are unavailable', ), ); } }, ); ``` ## Migrating applyNoteChange() ##### React ```jsx import { Banner, Button, useApplyNoteChange, useInstructions, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const applyNoteChange = useApplyNoteChange(); const instructions = useInstructions(); if (instructions.notes.canUpdateNote) { return ( ); } else { return ( Free gifts cannot be added to this order ); } } ``` ##### JavaScript ```js import { extension, Banner, Button, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, api) => { if ( api.instructions.current.notes.canUpdateNote ) { root.appendChild( root.createComponent( Button, { onPress: () => api.applyNoteChange({ type: 'updateNote', note: 'Please include a free gift.', }), }, 'Include a free gift with your order', ), ); } else { root.appendChild( root.createComponent( Banner, {}, 'Free gifts cannot be added to this order', ), ); } }, ); ``` ***