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.
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. |
Check `instructions.attributes.canUpdateAttributes` before calling `applyAttributeChange()`.
import {
Banner,
Button,
useApplyAttributeChange,
useInstructions,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);
function Extension() {
const applyAttributeChange =
useApplyAttributeChange();
const instructions = useInstructions();
if (
instructions.attributes.canUpdateAttributes
) {
return (
<Button
onPress={() =>
applyAttributeChange({
type: 'updateAttribute',
key: 'loyaltyPoints',
value: '100',
})
}
>
Apply 100 loyalty points
</Button>
);
} else {
return (
<Banner status="warning">
Loyalty points are unavailable
</Banner>
);
}
}
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',
),
);
}
},
);
Check `instructions.delivery.canSelectCustomAddress` before calling `applyShippingAddressChange()`. When `true`, this instruction implies that extensions can change the shipping address.
import {
Banner,
Button,
useApplyShippingAddressChange,
useInstructions,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);
function Extension() {
const applyShippingAddressChange =
useApplyShippingAddressChange();
const instructions = useInstructions();
if (
instructions.delivery.canSelectCustomAddress
) {
return (
<Button
onPress={() =>
applyShippingAddressChange({
type: 'updateShippingAddress',
address: {
zip: '90201',
},
})
}
>
Change your postal code
</Button>
);
} else {
return (
<Banner status="warning">
Shipping address cannot be modified
</Banner>
);
}
}
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',
),
);
}
},
);
Check `instructions.discounts.canUpdateDiscountCodes` before calling `applyDiscountCodeChange()`.
import {
Banner,
Button,
useApplyDiscountCodeChange,
useInstructions,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);
function Extension() {
const applyDiscountCodeChange =
useApplyDiscountCodeChange();
const instructions = useInstructions();
if (
instructions.discounts.canUpdateDiscountCodes
) {
return (
<Button
onPress={() =>
applyDiscountCodeChange({
type: 'addDiscountCode',
code: 'FREE_SHIPPING',
})
}
>
Apply your loyalty discount
</Button>
);
} else {
return (
<Banner status="warning">
Loyalty discounts are unavailable
</Banner>
);
}
}
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',
),
);
}
},
);
Check `instructions.lines.canAddCartLine` or `instructions.lines.canRemoveCartLine` or `instructions.lines.canUpdateCartLine` before calling `applyCartLinesChange()`.
import {
Banner,
Button,
useApplyCartLinesChange,
useInstructions,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);
function Extension() {
const applyCartLinesChange =
useApplyCartLinesChange();
const instructions = useInstructions();
if (instructions.lines.canAddCartLine) {
return (
<Button
onPress={() =>
applyCartLinesChange({
type: 'addCartLine',
merchandiseId:
'gid://shopify/product/1234',
quantity: 1,
})
}
>
Add a free gift to your order
</Button>
);
} else {
return (
<Banner status="warning">
The products in your cart cannot be
modified
</Banner>
);
}
}
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',
),
);
}
},
);
Check `instructions.metafields.canSetCartMetafields` or `instructions.metafields.canDeleteCartMetafields` before calling `applyMetafieldChange()` if you are working with cart metafields.
import {
Banner,
Button,
useApplyMetafieldChange,
useInstructions,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);
function Extension() {
const applyMetafieldChange =
useApplyMetafieldChange();
const instructions = useInstructions();
if (
instructions.metafields.canSetCartMetafields
) {
return (
<Button
onPress={() =>
applyMetafieldChange({
type: 'updateCartMetafield',
metafield: {
namespace: 'loyalty',
key: 'loyaltyPoints',
value: '100',
type: 'string',
},
})
}
>
Apply 100 loyalty points
</Button>
);
} else {
return (
<Banner status="warning">
Loyalty points are unavailable
</Banner>
);
}
}
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',
),
);
}
},
);
Check `instructions.notes.canUpdateNote` before calling `applyNoteChange()`.
import {
Banner,
Button,
useApplyNoteChange,
useInstructions,
reactExtension,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);
function Extension() {
const applyNoteChange = useApplyNoteChange();
const instructions = useInstructions();
if (instructions.notes.canUpdateNote) {
return (
<Button
onPress={() =>
applyNoteChange({
type: 'updateNote',
note: 'Please include a free gift.',
})
}
>
Include a free gift with your order
</Button>
);
} else {
return (
<Banner status="warning">
Free gifts cannot be added to this order
</Banner>
);
}
}
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',
),
);
}
},
);
Use the cart instructions API to determine if the affected APIs are available in checkout.