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.
Resource Picker API
The Resource Picker API lets merchants search for and select products, collections, or product variants. Use this API when your extension needs merchants to choose Shopify resources to work with. The resource picker returns detailed resource information including IDs, titles, images, and metadata.
If you need to pick app-specific resources like product reviews, email templates, or subscription options, use the Picker API instead.
If you need to pick app-specific resources like product reviews, email templates, or subscription options, use the Picker API instead.
Anchor to Use casesUse cases
- Resource selection: Display resource picker interfaces for selecting Shopify resources.
- Product selection: Enable product selection in bundle or collection configuration workflows.
- Customer selection: Select customers for targeting or segmentation purposes.
- Bulk selection: Support bulk resource selection for batch operations.
Anchor to PropertiesProperties
The object defines how the resource picker behaves, including which resource type to display, selection limits, filters, and preselected items. Access the following properties on the object to configure the resource picker's appearance and functionality.
- Anchor to typetypetype'product' | 'variant' | 'collection''product' | 'variant' | 'collection'requiredrequired
The type of Shopify resource to select:
'product'for products,'variant'for specific product variants, or'collection'for collections. This determines what appears in the picker and what data structure is returned.- Anchor to actionactionaction'add' | 'select''add' | 'select'Default: 'add'Default: 'add'
The action verb that appears in the picker's title and primary button. Use
'add'for actions that add new items (for example, "Add products") or'select'for choosing existing items (for example, "Select products"). This helps merchants understand the picker's purpose.- Anchor to filterfilterfilterFiltersFilters
Filtering options that control which resources appear in the picker. Use filters to restrict resources by publication status, include or exclude variants, or apply custom search criteria. This helps merchants find relevant items faster.
- Anchor to multiplemultiplemultipleboolean | numberboolean | numberDefault: falseDefault: false
The selection mode for the picker. Pass
trueto allow unlimited selections,falsefor single-item selection only, or a number to set a maximum selection limit (for example,5allows up to five items). Whentypeis'product', merchants can still select multiple variants from a single product even ifmultipleisfalse.- Anchor to queryqueryquerystringstringDefault: ''Default: ''
An initial search query that appears in the picker's search bar when it opens. Merchants can see and edit this query. See search syntax for the query format. For most use cases, use
filter.queryinstead, which filters results without exposing the query to merchants.- Anchor to selectionIdsselection
Idsselection Ids BaseResource[]BaseResource[]Default: []Default: [] Resources that should be preselected when the picker opens. Pass an array of resource objects with IDs (and optional variant IDs) to show which items are already selected. Merchants can deselect these preselected items. Use this to show current selections or default choices.
Filters
Filter options that control which resources appear in the resource picker. Use filters to restrict the available resources based on publication status, resource type, or custom search criteria.
- archived
Whether to include archived products in the picker. When `false`, archived products are hidden. When `undefined`, archived products appear with an archived badge. Only applies when `type` is `'product'`. Use this to prevent selecting discontinued products.
boolean | undefined - draft
Whether to include draft products in the picker. When `false`, draft products are hidden. When `undefined`, draft products appear with a draft badge. Only applies when `type` is `'product'`. Use this to prevent selecting products that aren't ready for use.
boolean | undefined - hidden
Whether to include products that aren't published on any sales channels. When `false`, only products published to at least one sales channel appear in the picker. Use this to ensure merchants only select products that customers can purchase.
boolean - query
A GraphQL search query that filters the available resources without showing the query in the picker's search bar. Merchants won't see or edit this filter. See [search syntax](/docs/api/usage/search-syntax) for the query format. Use this to programmatically restrict resources based on attributes like tags, vendor, or product type (for example, `"tag:featured"` or `"vendor:Acme"`).
string - variants
Whether to show product variants in the picker. When `false`, merchants can only select products, not individual variants. Only applies when `type` is `'product'`. Use this to simplify selection when you only need product-level data.
boolean
BaseResource
A resource that can have associated variants. Products and collections extend this interface.
- id
The resource's unique global identifier (GID) in GraphQL format (for example, `'gid://shopify/Product/1'`). Use this to reference the resource in GraphQL queries.
string - variants
An array of variant resources associated with this resource. Use this for products that have multiple variants with different options.
Resource[]
Resource
A base resource with a unique identifier. All Shopify resources extend from this interface.
- id
The resource's unique global identifier (GID) in GraphQL format (for example, `'gid://shopify/Product/1'`). Use this to reference the resource in GraphQL queries.
string
Anchor to ResourcePicker return payloadResource Picker return payload
The resource picker returns an array of selected resources when the merchant confirms their selection, or undefined if they cancel. The resource structure in the array varies based on the type option: products include variants and images, collections include rule sets, and variants include pricing and inventory data.
SelectPayload<Type>SelectPayload<Type>SelectPayload
Preview

Examples
Select products
Description
Open the product resource picker to select items from the store catalog. This example invokes `shopify.resourcePicker` with `type: "product"`, handles the async selection, and displays the count of selected products. When merchants confirm their selection, the resource picker returns an array of product objects with GIDs, titles, and handles for use in your extension.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ProductPicker = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Products" onPress={handlePick} /> {selected && <Text>{selected.length} products selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ProductPicker />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Products', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} products selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Filter to published products
Description
Filter the picker to show only published products using the `filter` option with `published_status: "published"`. This example shows restricting the picker to live, customer-visible products. Use this for promotional campaigns, product recommendations, or any feature that should only work with active inventory, preventing accidental selection of draft or archived products.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const FiltersPicker = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({ type: 'product', filter: { published_status: 'published', }, }); setSelected(result); }; return ( <> <Button title="Select Published Products" onPress={handlePick} /> {selected && <Text>{selected.length} products selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <FiltersPicker />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Published Products', onPress: async () => { const result = await resourcePicker({ type: 'product', filter: { published_status: 'published', }, }); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} products selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Limit selection count
Description
Limit selection to a maximum of five products by setting `multiple: 5`. This example shows restricting how many products merchants can choose. This is useful for bundle builders with item limits, featured product sections with fixed display slots, or promotional campaigns with maximum product counts. The resource picker automatically prevents selection beyond the limit.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ResourcePickerExample = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Resources" onPress={handlePick} /> {selected && <Text>{selected.length} selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ResourcePickerExample />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Resources', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Preselect products
Description
Open the resource picker with products already selected by passing GIDs to the `selectionIds` option. This example shows pre-populating the resource picker with current selections for edit workflows. Use this for showing what products are already in a bundle, collection, or promotional set. Merchants can see current selections and modify them by adding or removing products before confirming.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ResourcePickerExample = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Resources" onPress={handlePick} /> {selected && <Text>{selected.length} selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ResourcePickerExample />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Resources', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Select collections
Description
Select collections instead of individual products by setting `type: "collection"`. This example shows switching the resource picker to collection mode for choosing product groupings. This is useful for homepage featured collection carousels, navigation menu builders, bulk collection operations, or promotional campaigns targeting entire product categories rather than individual items.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const CollectionPicker = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'collection'}); setSelected(result); }; return ( <> <Button title="Select Collections" onPress={handlePick} /> {selected && <Text>{selected.length} collections selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <CollectionPicker />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Collections', onPress: async () => { const result = await resourcePicker({type: 'collection'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} collections selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Select unlimited products
Description
Allow unlimited product selection by setting `multiple: true` without a numeric limit. This example shows enabling multi-selection where merchants control the quantity. Use this for mass product taggers, bulk inventory tools, category managers, or export utilities where selection count depends on merchant needs without artificial constraints.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ResourcePickerExample = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Resources" onPress={handlePick} /> {selected && <Text>{selected.length} selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ResourcePickerExample />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Resources', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Select product variants
Description
Select specific product variants instead of entire products by setting `type: "variant"`. This example shows switching to variant-level selection for choosing individual SKUs. Use this for inventory transfer tools, variant-specific promotions, wholesale pricing sheets, or shipment builders where you need granular control over size, color, and individual SKU tracking.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ResourcePickerExample = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Resources" onPress={handlePick} /> {selected && <Text>{selected.length} selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ResourcePickerExample />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Resources', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Set action verb
Description
Customize the resource picker button text by setting the `action` option to "add" or "select". This example shows changing the action verb to provide workflow context. "Add" suggests appending to an existing list, while "select" implies choosing for a specific purpose or replacing selections. This subtle language difference improves clarity for different workflow contexts.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ResourcePickerExample = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Resources" onPress={handlePick} /> {selected && <Text>{selected.length} selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ResourcePickerExample />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Resources', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );Start with search query
Description
Start the resource picker with a pre-filled search query by passing the `query` option. This example shows initializing the picker with a search term already entered. This is helpful when you know what merchants are likely looking for, such as products from a specific vendor, tag, or product type. Merchants can modify the query, but starting with relevant results saves time in large catalogs.
React
import React, {useState} from 'react'; import {reactExtension, useApi, Button, Text} from '@shopify/ui-extensions-react/admin'; const ResourcePickerExample = () => { const {resourcePicker} = useApi<'admin.product-details.block.render'>(); const [selected, setSelected] = useState<any[] | null>(null); const handlePick = async () => { const result = await resourcePicker({type: 'product'}); setSelected(result); }; return ( <> <Button title="Select Resources" onPress={handlePick} /> {selected && <Text>{selected.length} selected</Text>} </> ); }; export default reactExtension('admin.product-details.block.render', () => <ResourcePickerExample />);TS
import {extension, Button, Text} from '@shopify/ui-extensions/admin'; export default extension( 'admin.product-details.block.render', (root, api) => { const {resourcePicker} = api; let selectedText; const pickButton = root.createComponent(Button, { title: 'Select Resources', onPress: async () => { const result = await resourcePicker({type: 'product'}); if (selectedText) root.removeChild(selectedText); if (result) { selectedText = root.createComponent(Text, {}, `${result.length} selected`); root.appendChild(selectedText); } }, }); root.appendChild(pickButton); }, );
Anchor to Best practicesBest practices
- Filter query runs server-side: The
queryproperty in filters isn't visible to merchants and runs as a GraphQL search query. Use it to programmatically restrict results (for example,vendor:Acme) without exposing the filter logic. - Handle undefined return on cancellation: When merchants close the picker without selecting, it returns
undefinedrather than an empty array. Check forundefinedexplicitly.
Anchor to LimitationsLimitations
- Only products, variants, and collections are supported. Other resource types like customers, orders, or locations can't be selected. Use the Picker API for custom resources.
- Product selection with
multiple: falsedoesn't prevent multi-variant selection from the same product. Merchants can select multiple variants from a single product even whenmultiple: false. - Filter options are limited to predefined fields (
hidden,variants,draft,archived,query). Custom filter criteria beyond these aren't supported. - Returned data structure varies by resource type. Products include a
variantsarray, variants includepriceandinventoryQuantity, and collections includeruleSet.