Shopify Local Pick-up
Learn how to configure Local Pickup in your Merchants Shopify store, and customise pickup options.
Headless Stores
Prerequisites
While there are no FE prerequisites for the checkout, to be able to query stock levels on the FE, you need the following:
Shopify Storefront API version 2023-04 or above
Stores set up in Shopify that allow in-store pickup
The Hook
To handle this, we’re best to create a useFindInStore
hook — this would power a few parts:
Fetching user location
Fetching the product variant data
Handling errors
The GraphQL Query
The storeAvailability
connection is available on the variant, so before you can run the query, the user should have already selected a variant (see 2 in need to knows).
We can then present the user with the option to search for store stock. An example would be:
query FindInsStoreVariantsAndLocations($handle: String!, $latitude: Float!, $longitude: Float!) {
product(handle: $handle) {
variantBySelectedOptions(selectedOptions: $selectedOptions) {
storeAvailability(first:250, near: { latitude: $latitude, longitude: $longitude }) {
edges {
node {
available
pickUpTime
location {
name
id
address {
formatted
latitude
longitude
}
}
}
}
}
}
}
}
With the following variables:
variables: {
handle: product?.handle,
selectedOptions: product?.activeVariant?.selectedOptions,
latitude: coords.lat,
longitude: coords.lng,
}
This will return this response:
{
"data": {
"product": {
"variantBySelectedOptions": {
"storeAvailability": {
"edges": [
{
"node": {
"available": true,
"pickUpTime": "Usually ready in 24 hours",
"location": {
"name": "Doncaster Store",
"id": "gid://shopify/Location/60903817288",
"address": {
"formatted": [
"619 Doncaster Road",
"Shop 1013",
"Doncaster VIC 3108",
"Australia"
],
"latitude": -37.7851115,
"longitude": 145.1262028
}
}
}
},
{
"node": {
"available": true,
"pickUpTime": "Usually ready in 24 hours",
"location": {
"name": "Armadale Store",
"id": "gid://shopify/Location/60898607176",
"address": {
"formatted": [
"1080 High Street",
"Armadale VIC 3143",
"Australia"
],
"latitude": -37.855974,
"longitude": 145.023201
}
}
}
}
]
}
}
}
}
}
From this response, you could flatten the array then sort by the distance:
const getDistance = useCallback((pos1: any, pos2: any) => {
if (!pos1 || !pos2) {
return 0
}
const R = 6371 // Radius of the earth in km
const dLat = deg2rad(pos2.lat - pos1.lat) // deg2rad below
const dLon = deg2rad(pos2.lng - pos1.lng)
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(pos1.lat)) * Math.cos(deg2rad(pos2.lat)) * Math.sin(dLon / 2) * Math.sin(dLon / 2)
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
return R * c
}, [])
const availability = edgeNormaliser(data?.product?.variantBySelectedOptions?.storeAvailability)
const sortedAvailability = availability?.map(location => ({...location, distance: getDistance(userCoords, {lat:location?.location?.latitude, lng:location?.location?.longitude})}))?.sort((a: any, b: any) => parseInt(a?.distance) - parseInt(b?.distance))
return storeAvailability
Example Implementation
Whilst it is outdated, Tony Bianco is a good reference for how to implement native Shopify Pickup.
On the PDP, the drawer uses Google Maps API to search for the user's location with autocomplete, or the Find My Location uses navigator.geolocation to get the user's current position.
Links
useFindStore Hook: https://gitlab.com/dotdevv/clients/tonybianco/tony-bianco-website/-/blob/main/app/src/hooks/useFindStore.tsx (not the best reference because it’s outdated, but an okay-ish reference for how it all pieces together)
Last updated
Was this helpful?