--- title: Attributes description: The API for interacting with cart and checkout attributes. api_version: 2025-04 api_name: checkout-ui-extensions source_url: html: 'https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/attributes' md: >- https://shopify.dev/docs/api/checkout-ui-extensions/latest/apis/attributes.md --- # Attributes The API for interacting with cart and checkout attributes. ## StandardApi The base API object provided to `purchase` extension targets. * **attributes** **StatefulRemoteSubscribable\** **required** The custom attributes left by the customer to the merchant, either in their cart or during checkout. ### Attribute * key The key for the attribute. ```ts string ``` * value The value for the attribute. ```ts string ``` ```ts export interface Attribute { /** * The key for the attribute. */ key: string; /** * The value for the attribute. */ value: string; } ``` ## CheckoutApi The API object provided to `purchase.checkout` extension targets. * **applyAttributeChange** **(change: AttributeChange) => Promise\** **required** Performs an update on an attribute attached to the cart and checkout. If successful, this mutation results in an update to the value retrieved through the [`attributes`](https://shopify.dev/docs/api/checkout-ui-extensions/apis/attributes#standardapi-propertydetail-attributes) property. **Note:** This method will return an error if the \cart instruction\ \\attributes.can\Update\Attributes\\ is false, or the buyer is using an accelerated checkout method, such as Apple Pay, Google Pay, or Meta Pay. ### AttributeChange ```ts AttributeUpdateChange | AttributeRemoveChange ``` ### AttributeUpdateChange Updates an attribute on the order. If an attribute with the provided key does not already exist, it gets created. * key Key of the attribute to add or update ```ts string ``` * type The type of the \`AttributeUpdateChange\` API. ```ts "updateAttribute" ``` * value Value for the attribute to add or update ```ts string ``` ```ts export interface AttributeUpdateChange { /** * The type of the `AttributeUpdateChange` API. */ type: 'updateAttribute'; /** * Key of the attribute to add or update */ key: string; /** * Value for the attribute to add or update */ value: string; } ``` ### AttributeRemoveChange Removes an attribute on the order if an attribute with the provided key already exists. * key Key of the attribute to remove ```ts string ``` * type The type of the \`AttributeRemoveChange\` API. ```ts "removeAttribute" ``` ```ts export interface AttributeRemoveChange { /** * The type of the `AttributeRemoveChange` API. */ type: 'removeAttribute'; /** * Key of the attribute to remove */ key: string; } ``` ### AttributeChangeResult ```ts AttributeChangeResultSuccess | AttributeChangeResultError ``` ### AttributeChangeResultSuccess The returned result of a successful update to an attribute. * type The type of the \`AttributeChangeResultSuccess\` API. ```ts "success" ``` ```ts export interface AttributeChangeResultSuccess { /** * The type of the `AttributeChangeResultSuccess` API. */ type: 'success'; } ``` ### AttributeChangeResultError The returned result of an unsuccessful update to an attribute with a message detailing the type of error that occurred. * message A message that explains the error. This message is useful for debugging. It is \*\*not\*\* localized, and therefore should not be presented directly to the buyer. ```ts string ``` * type The type of the \`AttributeChangeResultError\` API. ```ts "error" ``` ```ts export interface AttributeChangeResultError { /** * The type of the `AttributeChangeResultError` API. */ type: 'error'; /** * A message that explains the error. This message is useful for debugging. * It is **not** localized, and therefore should not be presented directly * to the buyer. */ message: string; } ``` ## use​Apply​Attribute​Change() Returns a function to mutate the `attributes` property of the checkout. ### Returns * **(change: AttributeChange) => Promise\** ### AttributeChange ```ts AttributeUpdateChange | AttributeRemoveChange ``` ### AttributeUpdateChange Updates an attribute on the order. If an attribute with the provided key does not already exist, it gets created. * key Key of the attribute to add or update ```ts string ``` * type The type of the \`AttributeUpdateChange\` API. ```ts "updateAttribute" ``` * value Value for the attribute to add or update ```ts string ``` ```ts export interface AttributeUpdateChange { /** * The type of the `AttributeUpdateChange` API. */ type: 'updateAttribute'; /** * Key of the attribute to add or update */ key: string; /** * Value for the attribute to add or update */ value: string; } ``` ### AttributeRemoveChange Removes an attribute on the order if an attribute with the provided key already exists. * key Key of the attribute to remove ```ts string ``` * type The type of the \`AttributeRemoveChange\` API. ```ts "removeAttribute" ``` ```ts export interface AttributeRemoveChange { /** * The type of the `AttributeRemoveChange` API. */ type: 'removeAttribute'; /** * Key of the attribute to remove */ key: string; } ``` ### AttributeChangeResult ```ts AttributeChangeResultSuccess | AttributeChangeResultError ``` ### AttributeChangeResultSuccess The returned result of a successful update to an attribute. * type The type of the \`AttributeChangeResultSuccess\` API. ```ts "success" ``` ```ts export interface AttributeChangeResultSuccess { /** * The type of the `AttributeChangeResultSuccess` API. */ type: 'success'; } ``` ### AttributeChangeResultError The returned result of an unsuccessful update to an attribute with a message detailing the type of error that occurred. * message A message that explains the error. This message is useful for debugging. It is \*\*not\*\* localized, and therefore should not be presented directly to the buyer. ```ts string ``` * type The type of the \`AttributeChangeResultError\` API. ```ts "error" ``` ```ts export interface AttributeChangeResultError { /** * The type of the `AttributeChangeResultError` API. */ type: 'error'; /** * A message that explains the error. This message is useful for debugging. * It is **not** localized, and therefore should not be presented directly * to the buyer. */ message: string; } ``` ## use​Attributes() Returns the proposed `attributes` applied to the checkout. ### Returns * **Attribute\[] | undefined** ### Attribute * key The key for the attribute. ```ts string ``` * value The value for the attribute. ```ts string ``` ```ts export interface Attribute { /** * The key for the attribute. */ key: string; /** * The value for the attribute. */ value: string; } ``` ## use​Attribute​Values(**[keys](#useattributevalues-propertydetail-keys)**​) Returns the values for the specified `attributes` applied to the checkout. ### Parameters * **keys** **string\[]** **required** An array of attribute keys. ### Returns * **(string | undefined)\[]** Examples ### Examples * #### Attribute values ##### React ```jsx import { Text, reactExtension, useAttributeValues, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const [buyerSelectedFreeTShirt, tshirtSize] = useAttributeValues([ 'buyerSelectedFreeTShirt', 'tshirtSize', ]); if (Boolean(buyerSelectedFreeTShirt) === true) { return ( You selected a free t-shirt, size:{' '} {tshirtSize} ); } return null; } ``` ##### JavaScript ```js import { extension, Text, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', (root, {attributes}) => { attributes.subscribe(() => { renderUI(); }); function renderUI() { const buyerSelectedFreeTShirt = attributes.current?.find( (attr) => attr.key === 'buyerSelectedFreeTShirt', )?.value; const tshirtSize = attributes.current?.find( (attr) => attr.key === 'tshirtSize', )?.value; if ( Boolean(buyerSelectedFreeTShirt) === true ) { root.replaceChildren( root.createComponent( Text, undefined, `You selected a free t-shirt, size: ${tshirtSize}`, ), ); } else { root.replaceChildren(); } } renderUI(); }, ); ``` * #### Applying changes to attributes ##### Description You can add or remove cart and checkout attributes by using the \`applyAttributeChange\` API. ##### React ```jsx import { reactExtension, BlockStack, Button, Text, useAttributeValues, useApplyAttributeChange, useInstructions, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.block.render', () => , ); function Extension() { const [giftWrapValue] = useAttributeValues([ 'giftWrap', ]); const giftWrap = Boolean(giftWrapValue); const applyAttributeChange = useApplyAttributeChange(); const instructions = useInstructions(); async function toggleGiftWrap() { const result = giftWrap ? await applyAttributeChange({ type: 'removeAttribute', key: 'giftWrap', }) : await applyAttributeChange({ type: 'updateAttribute', key: 'giftWrap', value: 'true', }); if (result.type === 'error') { console.error(result.message); } } return ( Gift wrapping:{' '} {giftWrap ? 'Added' : 'Not set'} ); } ``` ##### JavaScript ```js import { extension, BlockStack, Button, Text, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.block.render', ( root, { attributes, instructions, applyAttributeChange, }, ) => { let giftWrap = false; const text = root.createComponent(Text); const button = root.createComponent(Button, { onPress: async () => { const result = giftWrap ? await applyAttributeChange({ type: 'removeAttribute', key: 'giftWrap', }) : await applyAttributeChange({ type: 'updateAttribute', key: 'giftWrap', value: 'true', }); if (result.type === 'error') { console.error(result.message); } }, }); const blockStack = root.createComponent( BlockStack, { spacing: 'tight', }, [text, button], ); attributes.subscribe(updateUI); instructions.subscribe(updateUI); function updateUI() { giftWrap = Boolean( attributes.current?.find( (attr) => attr.key === 'giftWrap', )?.value, ); text.replaceChildren( `Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`, ); button.updateProps({ disabled: !instructions.current?.attributes ?.canUpdateAttributes, }); button.replaceChildren( giftWrap ? 'Remove gift wrap' : 'Add gift wrap', ); } updateUI(); root.append(blockstack); }, ); ``` ## Related [Reference - Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) [Reference - Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) [Reference - Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) [Learn - Tutorials](https://shopify.dev/apps/checkout)