--- title: Storage API description: >- The Storage API lets you persist key-value data scoped to the customer across sessions. Use this API to store customer preferences, dismissed states, or other lightweight data that should survive navigation and return visits. api_version: 2025-07 api_name: customer-account-ui-extensions source_url: html: >- https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/target-apis/platform-apis/storage-api md: >- https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/target-apis/platform-apis/storage-api.md --- Migrate to Polaris Version 2025-07 is the last API version to support React-based UI components. Later versions use [web components](https://shopify.dev/docs/api/customer-account-ui-extensions/latest/polaris-web-components), native UI elements with built-in accessibility, better performance, and consistent styling with [Shopify's design system](https://shopify.dev/docs/apps/design). Check out the [migration guide](https://shopify.dev/docs/apps/build/customer-accounts/migrate-to-web-components) to upgrade your extension. # Storage API The Storage API lets you persist key-value data scoped to the customer across sessions. Use this API to store customer preferences, dismissed states, or other lightweight data that should survive navigation and return visits. ### Use cases * **Remember customer preferences**: Save choices like preferred language, display options, or notification settings so they persist across visits. * **Track dismissed content**: Store whether a customer has dismissed a promotional banner or onboarding message so it doesn't reappear. * **Cache lightweight data**: Store small pieces of data to reduce redundant API calls, such as a customer's loyalty tier or last-viewed order. ### Support Targets (25) ### Supported targets * Customer​Account::Kitchen​Sink * [customer-account.​footer.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/footer#footer-render-after-) * [customer-account.​order-index.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-index#order-index-targets) * [customer-account.​order-index.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-index#order-index-block-) * [customer-account.​order-status.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#order-status-announcement-) * [customer-account.​order-status.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#order-status-block-) * [customer-account.​order-status.​cart-line-item.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#cart-line-item-render-after-) * [customer-account.​order-status.​cart-line-list.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#cart-line-list-render-after-) * [customer-account.​order-status.​customer-information.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#customer-information-render-after-) * [customer-account.​order-status.​fulfillment-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/fulfillment-status#fulfillment-status-targets) * [customer-account.​order-status.​payment-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/payments-and-returns#payments-and-returns-targets) * [customer-account.​order-status.​return-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/payments-and-returns#return-details-render-after-) * [customer-account.​order-status.​unfulfilled-items.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/fulfillment-status#unfulfilled-items-render-after-) * [customer-account.​order.​action.​menu-item.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-actions#order-action-menu-item-) * [customer-account.​order.​action.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-actions#order-action-) * [customer-account.​order.​page.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/full-page#order-specific-full-page-) * [customer-account.​page.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/full-page#customer-account-full-page-) * [customer-account.​profile.​addresses.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#profile-page-default-targets-) * [customer-account.​profile.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#announcement-) * [customer-account.​profile.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#profile-block-) * [customer-account.​profile.​company-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#profile-page-b2b-targets-) * [customer-account.​profile.​company-location-addresses.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-addresses-render-after-) * [customer-account.​profile.​company-location-payment.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-payment-render-after-) * [customer-account.​profile.​company-location-staff.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-staff-render-after-) * customer-account.​profile.​payment.​render-after ### Properties The Storage API object provides key-value storage scoped to the customer. Access the following properties on the API object to read, write, and delete persistent data across sessions. * **storage** **Storage** **required** Key-value storage that persists across customer sessions. Data is scoped to your app and shared across all extension targets. ### Storage Key-value storage that persists across customer sessions. Data is scoped to your app and shared across all extension targets. * delete Deletes the stored data for the given key. ```ts (key: string) => Promise ``` * read Reads and returns a stored value by key. The stored data is deserialized from JSON and returned as its original type. Returns \`null\` if no data exists for the given key. ```ts (key: string) => Promise ``` * write Writes data for the given key. The data must be serializable to JSON. ```ts (key: string, data: any) => Promise ``` Examples ### Examples * #### Save and retrieve stored data ##### Description Write a value to storage and read it back when the extension loads again. This example saves a locale preference using \`shopify.storage.write()\` and reads it when the extension loads with \`shopify.storage.read()\`. ##### React ```tsx import {useEffect, useState} from 'react'; import { reactExtension, useApi, BlockStack, Text, Button, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.order-status.block.render', () => , ); function Extension() { const {storage} = useApi(); const [preference, setPreference] = useState(null); useEffect(() => { async function loadPreference() { const stored = await storage.read('locale_pref'); if (stored) { setPreference(stored); } } loadPreference(); }, [storage]); async function handleSave(value: string) { await storage.write('locale_pref', value); setPreference(value); } return ( {preference ? `Saved preference: ${preference}` : 'No preference saved'} ); } ``` ##### TS ```js import { extension, BlockStack, Text, Button, } from '@shopify/ui-extensions/customer-account'; export default extension( 'customer-account.order-status.block.render', async (root, {storage}) => { const stored = await storage.read('locale_pref'); const text = root.createComponent( Text, {}, stored ? `Saved preference: ${stored}` : 'No preference saved', ); const button = root.createComponent( Button, { onPress: async () => { await storage.write( 'locale_pref', 'en-US', ); text.replaceChildren( 'Saved preference: en-US', ); }, }, 'Set preference to en-US', ); const stack = root.createComponent( BlockStack, {}, [text, button], ); root.appendChild(stack); }, ); ``` * #### Delete stored data ##### Description Remove a stored value when the customer resets a preference or state. This example tracks whether a promotion was dismissed and uses \`shopify.storage.delete()\` to clear the value when the customer wants to see it again. ##### React ```tsx import {useEffect, useState} from 'react'; import { reactExtension, useApi, BlockStack, Banner, Button, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.order-status.block.render', () => , ); function Extension() { const {storage} = useApi(); const [dismissed, setDismissed] = useState(false); useEffect(() => { async function checkDismissed() { const value = await storage.read('promo_dismissed'); if (value === 'true') { setDismissed(true); } } checkDismissed(); }, [storage]); async function handleDismiss() { await storage.write( 'promo_dismissed', 'true', ); setDismissed(true); } async function handleReset() { await storage.delete('promo_dismissed'); setDismissed(false); } if (dismissed) { return ( ); } return ( Get 20% off your next order. ); } ``` ##### TS ```js import { extension, BlockStack, Banner, Button, } from '@shopify/ui-extensions/customer-account'; export default extension( 'customer-account.order-status.block.render', async (root, {storage}) => { const value = await storage.read('promo_dismissed'); let dismissed = value === 'true'; const resetButton = root.createComponent( Button, { onPress: async () => { await storage.delete('promo_dismissed'); dismissed = false; render(); }, }, 'Show promotion again', ); const banner = root.createComponent( Banner, {title: 'Special offer!'}, 'Get 20% off your next order.', ); const dismissButton = root.createComponent( Button, { onPress: async () => { await storage.write( 'promo_dismissed', 'true', ); dismissed = true; render(); }, }, 'Dismiss', ); const promoStack = root.createComponent( BlockStack, {}, [banner, dismissButton], ); function render() { root.replaceChildren( dismissed ? resetButton : promoStack, ); } render(); }, ); ``` * #### Track a dismissed banner ##### Description Check storage on load to decide whether to show a promotional banner. When the customer dismisses it, write to storage so it stays hidden on future visits. ##### React ```tsx import {useEffect, useState} from 'react'; import { reactExtension, useApi, Banner, Text, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.order-status.block.render', () => , ); function Extension() { const {storage} = useApi(); const [dismissed, setDismissed] = useState(true); useEffect(() => { async function checkDismissed() { const value = await storage.read('promo_dismissed'); setDismissed(value === 'true'); } checkDismissed(); }, [storage]); async function handleDismiss() { await storage.write( 'promo_dismissed', 'true', ); setDismissed(true); } if (dismissed) { return null; } return ( Use code FREESHIP at checkout. ); } ``` ##### TS ```js import { extension, Banner, Text, } from '@shopify/ui-extensions/customer-account'; export default extension( 'customer-account.order-status.block.render', async (root, {storage}) => { const value = await storage.read('promo_dismissed'); if (value === 'true') { return; } const text = root.createComponent( Text, {}, 'Use code FREESHIP at checkout.', ); const banner = root.createComponent( Banner, { title: 'Free shipping on your next order', onDismiss: async () => { await storage.write( 'promo_dismissed', 'true', ); banner.remove(); }, }, [text], ); root.appendChild(banner); }, ); ``` *** ## Best practices * **Store only small values**: Keep stored data lightweight. Storage is intended for simple key-value pairs like preferences and flags, not large datasets. * **Use descriptive keys**: Name your storage keys clearly (for example, `promo_dismissed` or `locale_pref`) so their purpose is obvious and conflicts with other extensions are unlikely. * **Handle missing values gracefully**: Always check for `null` or `undefined` when reading from storage, since the value may not exist on the customer's first visit. * **Don't store sensitive data**: Storage isn't encrypted. Don't store personal information, tokens, or anything that could compromise customer privacy. *** ## Limitations * Storage is scoped per customer and per extension. You can't share data between different extensions or access another customer's stored values. * On the pre-authenticated Order status page, storage is scoped to the customer associated with the order, not the browsing session. * All values are stored as strings. You must serialize and deserialize complex types (like JSON objects). ***