Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the upgrade guide to upgrade your extension.
Storage API
The Storage API provides persistent local storage for POS UI extensions, allowing you to store, retrieve, and manage extension data that persists across user sessions, device restarts, and extension target state changes. Data is stored locally on the POS device in an isolated namespace specific to your extension.
The API supports key-value storage with automatic JSON serialization, type safety through TypeScript interfaces, and built-in error handling for storage constraint violations.
Anchor to Use casesUse cases
- Data caching: Cache product information and pricing data to reduce API calls.
- User preferences: Store user preferences like theme settings or workflow customizations.
- Cross-target data: Pass contextual data between tile and action targets during multi-step workflows.
- Session data: Maintain temporary session data that needs to survive navigation and cart changes.
Supported targets
- pos.
cart. line-item-details. action. menu-item. render - pos.
cart. line-item-details. action. render - pos.
customer-details. action. menu-item. render - pos.
customer-details. action. render - pos.
customer-details. block. render - pos.
draft-order-details. action. menu-item. render - pos.
draft-order-details. action. render - pos.
draft-order-details. block. render - pos.
home. modal. render - pos.
home. tile. render - pos.
order-details. action. menu-item. render - pos.
order-details. action. render - pos.
order-details. block. render - pos.
product-details. action. menu-item. render - pos.
product-details. action. render - pos.
product-details. block. render - pos.
purchase. post. action. menu-item. render - pos.
purchase. post. action. render - pos.
purchase. post. block. render
Supported targets
- pos.
cart. line-item-details. action. menu-item. render - pos.
cart. line-item-details. action. render - pos.
customer-details. action. menu-item. render - pos.
customer-details. action. render - pos.
customer-details. block. render - pos.
draft-order-details. action. menu-item. render - pos.
draft-order-details. action. render - pos.
draft-order-details. block. render - pos.
home. modal. render - pos.
home. tile. render - pos.
order-details. action. menu-item. render - pos.
order-details. action. render - pos.
order-details. block. render - pos.
product-details. action. menu-item. render - pos.
product-details. action. render - pos.
product-details. block. render - pos.
purchase. post. action. menu-item. render - pos.
purchase. post. action. render - pos.
purchase. post. block. render
Anchor to PropertiesProperties
The Storage API object provides persistent local storage for POS UI extensions. Access the following properties on the API object to store, retrieve, and manage extension data that persists across user sessions.
- Anchor to clearclearclear() => Promise<void>() => Promise<void>requiredrequired
Clears all data from storage, removing all key-value pairs.
- Anchor to deletedeletedelete<StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>(key: Keys) => Promise<boolean><StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>(key: Keys) => Promise<boolean>requiredrequired
Deletes a specific key from storage and returns
trueif the key existed,falseif it didn't exist. Returnsfalsefor non-existent keys rather than throwing an error. Commonly used for cleaning up temporary workflow data, removing expired cache entries, or handling user preference changes.- Anchor to entriesentriesentries<StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>() => Promise<[Keys, StorageTypes[Keys]][]><StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>() => Promise<[Keys, StorageTypes[Keys]][]>requiredrequired
Retrieves all stored key-value pairs as an array of tuples, preserving original data types. Returns all data at once which may impact memory usage with large datasets. Commonly used for debugging storage contents, implementing data export features, or performing bulk operations across stored data.
- Anchor to getgetget<StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>(key: Keys) => Promise<StorageTypes[Keys]><StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>(key: Keys) => Promise<StorageTypes[Keys]>requiredrequired
Retrieves the value associated with a key, returning
undefinedif the key doesn't exist. Always handle theundefinedcase by providing fallback values or conditional logic. Commonly used for loading user preferences, retrieving cached data, or accessing contextual information passed between extension targets.- Anchor to setsetset<StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>(key: Keys, value: StorageTypes[Keys]) => Promise<void><StorageTypes extends BaseStorageTypes = BaseStorageTypes, Keys extends keyof StorageTypes = keyof StorageTypes>(key: Keys, value: StorageTypes[Keys]) => Promise<void>requiredrequired
Stores a value under the specified key, overwriting any existing value. Values must be JSON-serializable and return
when storage limits are exceeded. Commonly used for storing user preferences, caching API responses, or passing contextual data from tiles to modals.
Examples
Clear all stored data
Description
Remove all stored key-value pairs for your extension in a single operation. This example demonstrates using `storage.clear()` to reset all extension data, useful for clearing user preferences, resetting state, or implementing logout functionality.
React
import React, {useState, useEffect} from 'react'; import { Tile, reactExtension, useApi, } from '@shopify/ui-extensions-react/point-of-sale'; const TileComponent = () => { const api = useApi<'pos.home.tile.render'>(); const [itemCount, setItemCount] = useState(0); useEffect(() => { const initializeData = async () => { const count = 10; for (let i = 0; i < count; i++) { await api.storage.set(`key-${i}`, `value-${i}`); } setItemCount(count); }; initializeData(); }, [api.storage]); return ( <Tile title="Storage app" subtitle="Clear example" badgeValue={itemCount} onPress={async () => { await api.storage.clear(); api.toast.show('All data cleared'); setItemCount(0); }} enabled /> ); }; export default reactExtension('pos.home.tile.render', () => <TileComponent />);TS
import {Tile, extension} from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.tile.render', (root, api) => { let itemCount = 0; const tile = root.createComponent(Tile, { title: 'Storage app', subtitle: 'Clear example', badgeValue: itemCount, enabled: true, onPress: async () => { await api.storage.clear(); api.toast.show('All data cleared'); itemCount = 0; tile.updateProps({badgeValue: itemCount}); }, }); const initializeData = async () => { const count = 10; for (let i = 0; i < count; i++) { await api.storage.set(`key-${i}`, `value-${i}`); } itemCount = count; tile.updateProps({badgeValue: itemCount}); }; initializeData(); root.append(tile); });Delete a specific value
Description
Remove a single stored value by its key. This example shows how to use `storage.delete()` to remove specific data entries while preserving other stored values, ideal for selective data cleanup or removing outdated information.
React
import React from 'react'; import { Tile, reactExtension, useApi, } from '@shopify/ui-extensions-react/point-of-sale'; const TileComponent = () => { const api = useApi<'pos.home.tile.render'>(); return ( <Tile title="Storage app" subtitle="Delete example" onPress={async () => { await api.storage.set('key', 'A temporary value'); const storedData = await api.storage.get('key'); api.toast.show(`Current value: ${String(storedData)}`); setTimeout(async () => { api.storage.delete('key'); const storedData = (await api.storage.get('key')) ?? ''; api.toast.show(`Current value after deletion: ${String(storedData)}`); }, 2000); }} enabled /> ); }; export default reactExtension('pos.home.tile.render', () => <TileComponent />);TS
import {Tile, extension} from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.tile.render', (root, api) => { const tile = root.createComponent(Tile, { title: 'Storage app', subtitle: 'Delete example', enabled: true, onPress: async () => { await api.storage.set('key', 'A temporary value'); const storedData = await api.storage.get('key'); api.toast.show(`Current value: ${String(storedData)}`); setTimeout(async () => { api.storage.delete('key'); const storedData = (await api.storage.get('key')) ?? ''; api.toast.show(`Current value after deletion: ${String(storedData)}`); }, 2000); }, }); root.append(tile); });Get all stored entries
Description
Retrieve all key-value pairs stored by your extension. This example demonstrates using `storage.entries()` to access all stored data at once, useful for data migration, debugging, or displaying all saved preferences.
React
import React from 'react'; import type {Storage} from '@shopify/ui-extensions/point-of-sale'; import { Tile, reactExtension, useApi, } from '@shopify/ui-extensions-react/point-of-sale'; interface ExampleStorage { attempts: number; darkMode: boolean; trackingId: string; } const TileComponent = () => { const api = useApi<'pos.home.tile.render'>(); const storage: Storage<ExampleStorage> = api.storage; return ( <Tile title="Storage app" subtitle="Entries example" onPress={async () => { await storage.set('attempts', 2); await storage.set('darkMode', true); await storage.set('trackingId', 'd6ead53c-b5f5-0b16-dabb-17081ff238c3'); const allEntries = await storage.entries(); const message = allEntries.length ? allEntries.map(([key, value]) => `${key}: ${value}`).join(', ') : 'Nothing stored'; api.toast.show(message); }} enabled /> ); }; export default reactExtension('pos.home.tile.render', () => <TileComponent />);TS
import {Tile, extension} from '@shopify/ui-extensions/point-of-sale'; import type {Storage} from '@shopify/ui-extensions/point-of-sale'; interface ExampleStorage { attempts: number; darkMode: boolean; trackingId: string; } export default extension('pos.home.tile.render', (root, api) => { const storage: Storage<ExampleStorage> = api.storage; const tile = root.createComponent(Tile, { title: 'Storage app', subtitle: 'Entries example', enabled: true, onPress: async () => { await storage.set('attempts', 2); await storage.set('darkMode', true); await storage.set('trackingId', 'd6ead53c-b5f5-0b16-dabb-17081ff238c3'); const allEntries = await storage.entries(); const message = allEntries.length ? allEntries.map(([key, value]) => `${key}: ${value}`).join(', ') : 'Nothing stored'; api.toast.show(message); }, }); root.append(tile); });Retrieve a stored value
Description
Get a specific value from storage using its key. This example shows how to use `storage.get()` to retrieve previously saved data with automatic JSON deserialization and type safety, ideal for loading user preferences or cached information.
React
import React from 'react'; import { Tile, reactExtension, useApi, } from '@shopify/ui-extensions-react/point-of-sale'; const TileComponent = () => { const api = useApi<'pos.home.tile.render'>(); return ( <Tile title="Storage app" subtitle="Get example" onPress={async () => { const storedData = await api.storage.get('key'); api.toast.show(String(storedData ?? '')); }} enabled /> ); }; export default reactExtension('pos.home.tile.render', () => <TileComponent />);TS
import {Tile, extension} from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.tile.render', (root, api) => { const tile = root.createComponent(Tile, { title: 'Storage app', subtitle: 'Get example', enabled: true, onPress: async () => { const storedData = await api.storage.get('key'); api.toast.show(String(storedData ?? '')); }, }); root.append(tile); });Save a value to storage
Description
Store a value persistently using a key. This example demonstrates using `storage.set()` to save data with automatic JSON serialization, enabling you to persist user preferences, cache data, or maintain state across sessions.
React
import React from 'react'; import type {Storage} from '@shopify/ui-extensions/point-of-sale'; import { Tile, reactExtension, useApi, } from '@shopify/ui-extensions-react/point-of-sale'; interface ExampleStorage { trackingId: string; someObject: Record<string, unknown>; attempts: number; } const TileComponent = () => { const api = useApi<'pos.home.tile.render'>(); const storage: Storage<ExampleStorage> = api.storage; return ( <Tile title="Storage app" subtitle="Set example" onPress={async () => { await Promise.all([ storage.set('trackingId', 'd6ead53c-b5f5-0b16-dabb-17081ff238c3'), storage.set('someObject', { boolean: true, numeric: 2, string: 'Hello world!', }), storage.set('attempts', 2), ]); }} enabled /> ); }; export default reactExtension('pos.home.tile.render', () => <TileComponent />);TS
import {Tile, extension} from '@shopify/ui-extensions/point-of-sale'; import type {Storage} from '@shopify/ui-extensions/point-of-sale'; interface ExampleStorage { trackingId: string; someObject: Record<string, unknown>; attempts: number; } export default extension('pos.home.tile.render', (root, api) => { const storage: Storage<ExampleStorage> = api.storage; const tile = root.createComponent(Tile, { title: 'Storage app', subtitle: 'Set example', enabled: true, onPress: async () => { await Promise.all([ storage.set('trackingId', 'd6ead53c-b5f5-0b16-dabb-17081ff238c3'), storage.set('someObject', { boolean: true, numeric: 2, string: 'Hello world!', }), storage.set('attempts', 2), ]); }, }); root.append(tile); });
Anchor to Best practicesBest practices
- Validate retrieved data: Check data structure and types after calling
get()since stored data may be outdated or corrupted. Provide sensible defaults and handle missing properties. - Plan for data evolution: Design your stored data structures to handle future changes. Include version fields in complex objects and implement migration logic to handle schema updates between extension versions.
- Keep sensitive data out of local storage: Never store passwords, API keys, or other sensitive information. Use the Session API for secure backend communication and limit stored data to user preferences and non-sensitive workflow state.
Anchor to LimitationsLimitations
- POS UI extensions can store up to a maximum of 100 entries.
- The maximum key size is ~1 KB and the maximum value size is ~1 MB.
- Data persists even when extension targets are disabled or removed.
- Stored extension data is automatically cleared after 30 days of inactivity. The inactivity timer is reset only by write operations (
set); read operations (get) do not affect the timer.