Building a Shoppable Videos mini
What will you learn?
In this guide, you'll learn how to do the following:
- Accept data from an entry point.
- Render a list of videos.
- Show products connected to each video.
Prerequisites
This guide assumes that you have your test store set up and are able to create entry points but mock data will be provided if you are just getting started. You could alternatively fetch this data from your own API if you wish.
Step 1: Set up your entry point
The first thing to do is to create an entry point with a list of videos and associated products. For this example I will be using the data that comes from the STORE_PAGE
VIDEO_COLLECTION_V2 entry point.
For development purpose, we have included mocked data which populates the mini with a few videos and associated products. We advise you to use this mock data to get started and then switch to using the real entry points data once you have set up your entry point(s).
You can create an entry point for this guide like so:
mutation SetEntryPoint {
entryPointSetByOwner(
shopDomain: "shop-minis-test-store.myshopify.com",
location: PRODUCT_PAGE,
ownerId: "gid://shopify/Product/7541934391551",
input: {
videoCollectionV2:{
items:[
{
video: {
embedUrl: "https://stream.mux.com/tQe00IYarTC202VrQIpjngZzhuE8goZ14D.m3u8"
},
fallbackImage: {
url: "https://cdn.shopify.com/s/files/1/0621/0463/3599/products/mediamodifier-kJXGTOY1wLQ-unsplash.jpg?v=1651847844"
},
contentCreator:{
avatar:{
url: "https://cdn.shopify.com/s/files/1/0621/0463/3599/products/vin-stratton-V1dX9O1B4pM-unsplash_1946x.jpg?v=1651847754",
},
name: "Yu Tuba"
},
relatedProducts: [
{productId: "gid://shopify/Product/7922587762943"},
{productId: "gid://shopify/Product/7541927510271"},
{productId: "gid://shopify/Product/7541934391551"},
],
externalId: "1"
},
# ... more items
]
}
}
) {
entryPoint {
id
ownerId
visibilityRule
}
}
}
Step 2: Reading entry point data
In your mini you can now use the useMinisParams()
hook to get hold of entryPoint.collectionItems
. When a mini is launched from a VIDEO_COLLECTION_V2 or IMAGE_COLLECTION_V2 entry point this object will contain all of the entry point items. We can use that for our first page of data instead of fetching it from an API which will help our mini first load to feel fast and responsive. Subsequent pages of data will need to be fetched from elsewhere and it's result should return in the fetchMore
property.
- ShoppableVideosScreen.tsx
import {
ShoppableVideos,
VideoCollectionV2EntryPointItem,
useMinisParams,
} from '@shopify/shop-minis-platform-sdk'
export const ShoppableVideosScreen = () => {
const {entryPoint, entryPointParams} = useMinisParams()
const [listVideos, setListVideos] = useState<
VideoCollectionV2EntryPointItem[]
>([])
useEffect(() => {
// This is where you would get videos from the entry point for the first load
setListVideos(entryPoint.collectionItems)
}, [entryPoint?.collectionItems])
const shoppableVideos = useMemo(
// This is a helper function that maps the entry point items to the ShoppableVideosItem type
() => mapEntryPointCollectionItemsToShoppableVideos(listVideos),
[listVideos]
)
const fetchMore = async () => {
const moreVideos = (await Promise.resolve(
// Fetch more videos from your API
)) as VideoCollectionV2EntryPointItem[]
setListVideos(list => list.concat(moreVideos))
}
return (
<ShoppableVideos
items={shoppableVideos}
shopId={entryPointParams.shopGID}
fetchMore={fetchMore}
/>
)
}
function mapEntryPointCollectionItemsToShoppableVideos(
collectionItems: VideoCollectionV2EntryPointItem[]
) {
return collectionItems.map(item => ({
externalId: item.externalId!,
videoUrl: item.video.embeddedUrl!,
fallbackImageUrl: item.fallbackImage.url,
relatedProductsIds: item.relatedProducts.map(
relatedProduct => relatedProduct.productId
),
}))
}
As mentioned above mock data is provided if you cannot use entry point data yet. Just import entryPoint
and entryPointParams
from mockData.ts
instead of using useMinisParams()
. This mock data assumes you are using enableApiSandbox
so toggle that back on if you previously disabled it.
Step 3: Rendering a list of videos
The result you'll get with this data is a list of videos that look like this:
Step 4: Customizing your Shopable Videos mini
You can customize the look and feel of your Shoppable Videos mini by using the ShoppableVideos
component's props.
You can find the full list of props here: ShoppableVideosProps.
Example
// ...
<ShoppableVideos
items={shoppableVideos}
shopId={entryPointParams.shopGID}
fetchMore={fetchMore}
renderItem={({item}) => (
<View>
<CustomVideoHeader />
<Video
source={{uri: item.videoUrl}}
style={{height, width: 'auto'}}
poster={item.fallbackImageUrl}
posterResizeMode="cover"
repeat
resizeMode="cover"
paused={false}
progressUpdateInterval={10}
muted
ignoreSilentSwitch="ignore"
testID="video"
/>
<CustomVideoFooter />
</View>
)}
/>
// ...
// ...
<ShoppableVideos
items={shoppableVideos}
shopId={entryPointParams.shopGID}
fetchMore={fetchMore}
renderMedia={({item}) => <CustomCarouselPost images={imageStack(item)} />}
/>
// ...
// ...
<ShoppableVideos
items={shoppableVideos}
shopId={entryPointParams.shopGID}
fetchMore={fetchMore}
renderMediaHeader={() => null}
/>
// ...
// ...
<ShoppableVideos
items={shoppableVideos}
shopId={entryPointParams.shopGID}
fetchMore={fetchMore}
renderMediaFooter={({item}) => (
<View>
<Pressable
onPress={() => setShowGift(!showGift)}
style={{
justifyContent: 'flex-end',
marginBottom: 20,
}}
>
<IconButton
name="gift"
onPress={() => setShowGift(!showGift)}
accessibilityLabel="products"
/>
</Pressable>
<RelatedProductsList
products={item.relatedProducts}
style={RELATED_PRODUCTS_LIST_STYLE}
shopId={entryPointParams.shopGID}
/>
{showGift ? (
<GiftBottomSheet
text='Use PROMO2023 to get 10% off your purchase'
/>
) : null}
</View>
)}
/>
// ...
We look forward to seeing what you build!