Product Search APIAPIs
The ProductSearch API gives extensions access to the native product search and fetching functionality of Shopify POS. The interface provides numerous functions to search for products by query, or to fetch the details of one or more products or product variants.
Anchor to productsearchapiProductSearchApi
- Anchor to fetchPaginatedProductVariantsWithProductIdfetchPaginatedProductVariantsWithProductId(productId: number, paginationParams: ) => Promise<<>>required
Fetches a page of product variants associated with a product.
- Anchor to fetchProductsWithIdsfetchProductsWithIds(productIds: number[]) => Promise<<>>required
Fetches multiple products' details.
- Anchor to fetchProductVariantsWithIdsfetchProductVariantsWithIds(productVariantIds: number[]) => Promise<<>>required
Fetches multiple product variants' details.
- Anchor to fetchProductVariantsWithProductIdfetchProductVariantsWithProductId(productId: number) => Promise<[]>required
Fetches all product variants associated with a product.
- Anchor to fetchProductVariantWithIdfetchProductVariantWithId(productVariantId: number) => Promise<>required
Fetches a single product variant's details.
- Anchor to fetchProductWithIdfetchProductWithId(productId: number) => Promise<>required
Fetches a single product's details.
- Anchor to searchProductssearchProducts(searchParams: ) => Promise<<>>required
Search for products on the POS device.
ProductSearchApiContent
- fetchPaginatedProductVariantsWithProductId
Fetches a page of product variants associated with a product.
(productId: number, paginationParams: PaginationParams) => Promise<PaginatedResult<ProductVariant>>
- fetchProductsWithIds
Fetches multiple products' details.
(productIds: number[]) => Promise<MultipleResourceResult<Product>>
- fetchProductVariantsWithIds
Fetches multiple product variants' details.
(productVariantIds: number[]) => Promise<MultipleResourceResult<ProductVariant>>
- fetchProductVariantsWithProductId
Fetches all product variants associated with a product.
(productId: number) => Promise<ProductVariant[]>
- fetchProductVariantWithId
Fetches a single product variant's details.
(productVariantId: number) => Promise<ProductVariant>
- fetchProductWithId
Fetches a single product's details.
(productId: number) => Promise<Product>
- searchProducts
Search for products on the POS device.
(searchParams: ProductSearchParams) => Promise<PaginatedResult<Product>>
export interface ProductSearchApiContent {
/** Search for products on the POS device.
* @param searchParams The parameters for the product search.
*/
searchProducts(
searchParams: ProductSearchParams,
): Promise<PaginatedResult<Product>>;
/** Fetches a single product's details.
* @param productId The ID of the product to lookup.
*/
fetchProductWithId(productId: number): Promise<Product | undefined>;
/** Fetches multiple products' details.
* @param productIds Specifies the array of product IDs to lookup. This is limited to 50 products. All excess requested IDs will be removed from the array.
*/
fetchProductsWithIds(
productIds: number[],
): Promise<MultipleResourceResult<Product>>;
/** Fetches a single product variant's details.
* @param productVariantId The ID of the product variant to lookup.
*/
fetchProductVariantWithId(
productVariantId: number,
): Promise<ProductVariant | undefined>;
/** Fetches multiple product variants' details.
* @param productVariantIds Specifies the array of product variant IDs to lookup. This is limited to 50 product variants. All excess requested IDs will be removed from the array.
*/
fetchProductVariantsWithIds(
productVariantIds: number[],
): Promise<MultipleResourceResult<ProductVariant>>;
/** Fetches all product variants associated with a product.
* @param productId The product ID. All variants' details associated with this product ID are returned.
*/
fetchProductVariantsWithProductId(
productId: number,
): Promise<ProductVariant[]>;
/** Fetches a page of product variants associated with a product.
* @param paginationParams The parameters for pagination.
*/
fetchPaginatedProductVariantsWithProductId(
productId: number,
paginationParams: PaginationParams,
): Promise<PaginatedResult<ProductVariant>>;
}
PaginationParams
Base interface for pagination.
- afterCursor
Specifies the page cursor. Items after this cursor will be returned.
string
- first
Specifies the number of results to be returned in this page. The maximum number of items that will be returned is 50.
number
export interface PaginationParams {
/**
* Specifies the number of results to be returned in this page. The maximum number of items that will be returned is 50.
*/
first?: number;
/**
* Specifies the page cursor. Items after this cursor will be returned.
*/
afterCursor?: string;
}
PaginatedResult
Contains a page of fetched results.
- hasNextPage
Whether or not there is another page of results that can be fetched.
boolean
- items
The items returned from the fetch.
T[]
- lastCursor
The cursor of the last item. This can be used to fetch more results. The format of this cursor may look different depending on if POS is fetching results from the remote API, or its local database. However, that should not affect its usage with the search functions.
string
export interface PaginatedResult<T> {
/**
* The items returned from the fetch.
*/
items: T[];
/**
* The cursor of the last item. This can be used to fetch more results.
* The format of this cursor may look different depending on if POS is fetching results from the remote API, or its local database. However, that should not affect its usage with the search functions.
*/
lastCursor?: string;
/**
* Whether or not there is another page of results that can be fetched.
*/
hasNextPage: boolean;
}
ProductVariant
- barcode
string
- compareAtPrice
string
- createdAt
string
- displayName
string
- hasInStockVariants
boolean
- id
number
- image
string
- inventoryAtAllLocations
number
- inventoryAtLocation
number
- inventoryIsTracked
boolean
- inventoryPolicy
ProductVariantInventoryPolicy
- options
ProductVariantOption[]
- position
number
- price
string
- product
Product
- productId
number
- sku
string
- taxable
boolean
- title
string
- updatedAt
string
export interface ProductVariant {
id: number;
createdAt: string;
updatedAt: string;
title: string;
price: string;
compareAtPrice?: string;
taxable: boolean;
sku?: string;
barcode?: string;
displayName: string;
image?: string;
inventoryIsTracked: boolean;
inventoryAtLocation?: number;
inventoryAtAllLocations?: number;
inventoryPolicy: ProductVariantInventoryPolicy;
hasInStockVariants?: boolean;
options?: ProductVariantOption[];
product?: Product;
productId: number;
position: number;
}
ProductVariantInventoryPolicy
'DENY' | 'CONTINUE'
ProductVariantOption
- name
string
- value
string
export interface ProductVariantOption {
name: string;
value: string;
}
Product
- createdAt
string
- description
string
- descriptionHtml
string
- featuredImage
string
- hasInStockVariants
boolean
- hasOnlyDefaultVariant
boolean
- id
number
- isGiftCard
boolean
- maxVariantPrice
string
- minVariantPrice
string
- numVariants
number
- onlineStoreUrl
string
- options
ProductOption[]
- productCategory
string
- productType
string
- tags
string[]
- title
string
- totalAvailableInventory
number
- totalInventory
number
- tracksInventory
boolean
- updatedAt
string
- variants
ProductVariant[]
- vendor
string
export interface Product {
id: number;
createdAt: string;
updatedAt: string;
title: string;
description: string;
descriptionHtml: string;
featuredImage?: string;
isGiftCard: boolean;
tracksInventory: boolean;
vendor: string;
minVariantPrice: string;
maxVariantPrice: string;
productType: string;
productCategory: string;
tags: string[];
numVariants: number;
totalAvailableInventory?: number;
totalInventory: number;
variants: ProductVariant[];
options: ProductOption[];
hasOnlyDefaultVariant: boolean;
hasInStockVariants?: boolean;
onlineStoreUrl?: string;
}
ProductOption
- id
number
- name
string
- optionValues
string[]
- productId
number
export interface ProductOption {
id: number;
name: string;
optionValues: string[];
productId: number;
}
MultipleResourceResult
The result of a fetch function where the input is multiple IDs. This object contains the resources that were found, as well as an array of IDs specifying which IDs, if any, did not correspond to a resource.
- fetchedResources
The resources that were fetched using the IDs provided.
T[]
- idsForResourcesNotFound
The IDs for which a resource was not found.
number[]
export interface MultipleResourceResult<T> {
/**
* The resources that were fetched using the IDs provided.
*/
fetchedResources: T[];
/**
* The IDs for which a resource was not found.
*/
idsForResourcesNotFound: number[];
}
ProductSearchParams
Interface for product search
- afterCursor
Specifies the page cursor. Items after this cursor will be returned.
string
- first
Specifies the number of results to be returned in this page. The maximum number of items that will be returned is 50.
number
- queryString
The search term to be used to search for POS products.
string
- sortType
Specifies the order in which products should be sorted. When a `queryString` is provided, sortType will not have any effect, as the results will be returned in order by relevance to the `queryString`.
ProductSortType
export interface ProductSearchParams extends PaginationParams {
/**
* The search term to be used to search for POS products.
*/
queryString?: string;
/**
* Specifies the order in which products should be sorted. When a `queryString` is provided, sortType will not have any effect, as the results will be returned in order by relevance to the `queryString`.
*/
sortType?: ProductSortType;
}
ProductSortType
'RECENTLY_ADDED' | 'RECENTLY_ADDED_ASCENDING' | 'ALPHABETICAL_A_TO_Z' | 'ALPHABETICAL_Z_TO_A'
Anchor to examplesExamples
Examples of using the Cart API
Anchor to example-search-for-products-with-a-search-barSearch for products with a search bar
Anchor to example-fetch-a-specific-product-with-a-product-idFetch a specific product with a product ID
Anchor to example-fetch-multiple-products-by-specifying-product-idsFetch multiple products by specifying product IDs
Anchor to example-fetch-a-specific-product-variant-with-a-variant-idFetch a specific product variant with a variant ID
Anchor to example-fetch-multiple-product-variants-by-specifying-variant-idsFetch multiple product variants by specifying variant IDs
Anchor to example-fetch-a-page-of-product-variants-with-a-specific-product-idFetch a page of product variants with a specific product ID
Search for products with a search bar
examples
Search for products with a search bar
React
import React, { useState } from 'react' import { Screen, List, Navigator, reactExtension, SearchBar, useApi, ListRow } from '@shopify/ui-extensions-react/point-of-sale'; const Modal = () => { const api = useApi<'pos.home.modal.render'>(); const [data, setData] = useState<ListRow[]>([]); const search = async (queryString?: string) => { const results = await api.productSearch.searchProducts({queryString}) const data = results.items.map((product): ListRow => { return { id: String(product.id), leftSide: { label: product.title, image: { source: product.featuredImage } } } }) setData(data) } return ( <Navigator> <Screen name="HelloWorld" title="Hello World!"> <List listHeaderComponent={<SearchBar placeholder='Search products' onTextChange={search} onSearch={search} />} imageDisplayStrategy='always' data={data} /> </Screen> </Navigator> ) } export default reactExtension('pos.home.modal.render', () => <Modal />);
TS
import { SearchBar, Screen, Navigator, extension, ListRow, List, } from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.modal.render', (root, api) => { const list = root.createComponent(List, { imageDisplayStrategy: 'always', data: [], }); const search = async (queryString?: string) => { const results = await api.productSearch.searchProducts({queryString}); const data = results.items.map((product): ListRow => { return { id: String(product.id), leftSide: { label: product.title, image: { source: product.featuredImage, }, }, }; }); list.updateProps({data}); }; const searchBar = root.createFragment(); searchBar.append( root.createComponent(SearchBar, { placeholder: 'Search products', onTextChange: search, onSearch: search, }), ); list.updateProps({listHeaderComponent: searchBar}); const screen = root.createComponent(Screen, { title: 'Home', name: 'Home', }); screen.append(list); const navigator = root.createComponent(Navigator); navigator.append(screen); root.append(navigator); });
Fetch a specific product with a product ID
React
import React, { useEffect, useState } from 'react' import { Screen, List, Navigator, reactExtension, SearchBar, useApi, ListRow } from '@shopify/ui-extensions-react/point-of-sale'; const Modal = () => { const api = useApi<'pos.home.modal.render'>(); const [data, setData] = useState<ListRow[]>([]); useEffect(() => { const fetchProduct = async () => { const resultProduct = await api.productSearch.fetchProductWithId(1) if (resultProduct) { const listItem = { id: String(resultProduct.id), leftSide: { label: resultProduct.title, image: { source: resultProduct.featuredImage } } } setData([listItem]) } } fetchProduct(); }, []); return ( <Navigator> <Screen name="HelloWorld" title="Hello World!"> <List imageDisplayStrategy='always' data={data} /> </Screen> </Navigator> ) } export default reactExtension('pos.home.modal.render', () => <Modal />);
TS
import { SearchBar, Screen, Navigator, extension, ListRow, List, } from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.modal.render', (root, api) => { const list = root.createComponent(List, { imageDisplayStrategy: 'always', data: [], }); const fetchProduct = async () => { const resultProduct = await api.productSearch.fetchProductWithId(1); if (resultProduct) { const listItem = { id: String(resultProduct.id), leftSide: { label: resultProduct.title, image: { source: resultProduct.featuredImage, }, }, }; list.updateProps({data: [listItem]}); } }; const screen = root.createComponent(Screen, { title: 'Home', name: 'Home', }); screen.append(list); const navigator = root.createComponent(Navigator); navigator.append(screen); root.append(navigator); fetchProduct(); });
Fetch multiple products by specifying product IDs
React
import React, { useEffect, useState } from 'react' import { Screen, List, Navigator, reactExtension, SearchBar, useApi, ListRow } from '@shopify/ui-extensions-react/point-of-sale'; const Modal = () => { const api = useApi<'pos.home.modal.render'>(); const [data, setData] = useState<ListRow[]>([]); useEffect(() => { const fetchProducts = async () => { const results = await api.productSearch.fetchProductsWithIds([1, 2, 3]); const data = results.fetchedResources.map((product): ListRow => { return { id: String(product.id), leftSide: { label: product.title, image: { source: product.featuredImage } } } }) console.log('IDs not found: ', results.idsForResourcesNotFound); setData(data) } fetchProducts(); }, []); return ( <Navigator> <Screen name="HelloWorld" title="Hello World!"> <List imageDisplayStrategy='always' data={data} /> </Screen> </Navigator> ) } export default reactExtension('pos.home.modal.render', () => <Modal />);
TS
import { SearchBar, Screen, Navigator, extension, ListRow, List, } from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.modal.render', (root, api) => { const list = root.createComponent(List, { imageDisplayStrategy: 'always', data: [], }); const fetchProducts = async () => { const results = await api.productSearch.fetchProductsWithIds([1, 2, 3, 4]); const data = results.fetchedResources.map((product): ListRow => { return { id: String(product.id), leftSide: { label: product.title, image: { source: product.featuredImage, }, }, }; }); console.log('IDs not found: ', results.idsForResourcesNotFound); list.updateProps({data}); }; const screen = root.createComponent(Screen, { title: 'Home', name: 'Home', }); screen.append(list); const navigator = root.createComponent(Navigator); navigator.append(screen); root.append(navigator); fetchProducts(); });
Fetch a specific product variant with a variant ID
React
import React, { useEffect, useState } from 'react' import { Screen, List, Navigator, reactExtension, SearchBar, useApi, ListRow } from '@shopify/ui-extensions-react/point-of-sale'; const Modal = () => { const api = useApi<'pos.home.modal.render'>(); const [data, setData] = useState<ListRow[]>([]); useEffect(() => { const fetchProductVariant = async () => { const resultProductVariant = await api.productSearch.fetchProductVariantWithId(1); if (resultProductVariant) { const listItem = { id: String(resultProductVariant.id), leftSide: { label: resultProductVariant.title, image: { source: resultProductVariant.image } } } setData([listItem]) } } fetchProductVariant(); }, []); return ( <Navigator> <Screen name="HelloWorld" title="Hello World!"> <List imageDisplayStrategy='always' data={data} /> </Screen> </Navigator> ) } export default reactExtension('pos.home.modal.render', () => <Modal />);
TS
import { SearchBar, Screen, Navigator, extension, ListRow, List, } from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.modal.render', (root, api) => { const list = root.createComponent(List, { imageDisplayStrategy: 'always', data: [], }); const fetchProductVariant = async () => { const resultProductVariant = await api.productSearch.fetchProductVariantWithId(1); if (resultProductVariant) { const listItem = { id: String(resultProductVariant.id), leftSide: { label: resultProductVariant.title, image: { source: resultProductVariant.image, }, }, }; list.updateProps({data: [listItem]}); } }; const screen = root.createComponent(Screen, { title: 'Home', name: 'Home', }); screen.append(list); const navigator = root.createComponent(Navigator); navigator.append(screen); root.append(navigator); fetchProductVariant(); });
Fetch multiple product variants by specifying variant IDs
React
import React, { useEffect, useState } from 'react' import { Screen, List, Navigator, reactExtension, SearchBar, useApi, ListRow } from '@shopify/ui-extensions-react/point-of-sale'; const Modal = () => { const api = useApi<'pos.home.modal.render'>(); const [data, setData] = useState<ListRow[]>([]); useEffect(() => { const fetchProductVariants = async () => { const results = await api.productSearch.fetchProductVariantsWithIds([1, 2, 3]); const data = results.fetchedResources.map((variant): ListRow => { return { id: String(variant.id), leftSide: { label: variant.title, image: { source: variant.image } } } }) console.log('IDs not found: ', results.idsForResourcesNotFound); setData(data) } fetchProductVariants(); }, []); return ( <Navigator> <Screen name="HelloWorld" title="Hello World!"> <List imageDisplayStrategy='always' data={data} /> </Screen> </Navigator> ) } export default reactExtension('pos.home.modal.render', () => <Modal />);
TS
import { SearchBar, Screen, Navigator, extension, ListRow, List, } from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.modal.render', (root, api) => { const list = root.createComponent(List, { imageDisplayStrategy: 'always', data: [], }); const fetchProductVariants = async () => { const results = await api.productSearch.fetchProductVariantsWithIds([ 1, 2, 3, 4, ]); const data = results.fetchedResources.map((variant): ListRow => { return { id: String(variant.id), leftSide: { label: variant.title, image: { source: variant.image, }, }, }; }); console.log('IDs not found: ', results.idsForResourcesNotFound); list.updateProps({data}); }; const screen = root.createComponent(Screen, { title: 'Home', name: 'Home', }); screen.append(list); const navigator = root.createComponent(Navigator); navigator.append(screen); root.append(navigator); fetchProductVariants(); });
Fetch a page of product variants with a specific product ID
React
import React, { useEffect, useState } from 'react' import { Screen, List, Navigator, reactExtension, SearchBar, useApi, ListRow } from '@shopify/ui-extensions-react/point-of-sale'; const Modal = () => { const api = useApi<'pos.home.modal.render'>(); const [data, setData] = useState<ListRow[]>([]); useEffect(() => { const fetchProductVariants = async () => { const results = await api.productSearch.fetchPaginatedProductVariantsWithProductId(1, {first: 10}); const data = results.items.map((variant): ListRow => { return { id: String(variant.id), leftSide: { label: variant.title, image: { source: variant.image } } } }) console.log('Cursor for next page: ', results.lastCursor); setData(data) } fetchProductVariants(); }, []); return ( <Navigator> <Screen name="HelloWorld" title="Hello World!"> <List imageDisplayStrategy='always' data={data} /> </Screen> </Navigator> ) } export default reactExtension('pos.home.modal.render', () => <Modal />);
TS
import { SearchBar, Screen, Navigator, extension, ListRow, List, } from '@shopify/ui-extensions/point-of-sale'; export default extension('pos.home.modal.render', (root, api) => { const list = root.createComponent(List, { imageDisplayStrategy: 'always', data: [], }); const fetchProductVariants = async () => { const results = await api.productSearch.fetchPaginatedProductVariantsWithProductId(1, { first: 10, }); const data = results.items.map((variant): ListRow => { return { id: String(variant.id), leftSide: { label: variant.title, image: { source: variant.image, }, }, }; }); console.log('Cursor for next page: ', results.lastCursor); list.updateProps({data}); }; const screen = root.createComponent(Screen, { title: 'Home', name: 'Home', }); screen.append(list); const navigator = root.createComponent(Navigator); navigator.append(screen); root.append(navigator); fetchProductVariants(); });