If you're running a Shopify store with multiple physical locations, you've probably noticed that Shopify doesn't include a built-in store locator feature. This is very sad! Most merchants turn to paid apps from the Shopify App Store, but those come with monthly fees and often limited customization options. They never feel quite right.
In this tutorial, I'll show you how to build a completely free store locator page using Shopify's native features and Mapbox. We'll create a custom page template called pages.stores.liquid, which you can then assign to any page in your Shopify admin. This approach gives you full control over the design and functionality without relying on third-party apps.
The store locator we'll build will display your store locations in a clean format with an interactive map. Each location will be clickable and have the location name and address. This solution is perfect for businesses with brick-and-mortar locations who want a simple, maintainable way to help customers find their nearest store.
Prerequisites
Before we start, you'll need:
- Access to your Shopify theme code (you can edit this in the admin under Online Store > Themes > Edit Code)
- Basic familiarity with Liquid template syntax, or ability to go in and copy/paste these code snippets
- A Shopify plan that supports custom templates (most plans do, except the Starter plan)
- A free Mapbox account (we'll use Mapbox GL JS for the interactive map), more on this below
Creating the Custom Page Template
First, we need to create a new page template in your Shopify theme. Navigate to your theme's code editor (Online Store > Themes > Actions > Edit Code) and create a new template file called pages.stores.liquid in the Templates folder.
Setting Up Mapbox
For this store locator, we'll use Mapbox GL JS to display an interactive map. Mapbox offers a generous free tier that includes 50,000 free map loads per month, which should be more than enough for most small to medium-sized businesses.
- Sign up for a free account at Mapbox
- Navigate to your account dashboard and copy your default public access token
- You'll need this token in the code below
Adding the Required Styles
Before we create the page template, we need to add the Mapbox styles to your theme. Open your theme.liquid file and add the following inside the <head> element:
<style>
#map {
height: 600px;
width: 100%;
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
}
@media (min-width: 768px) {
#map {
width: 50%;
margin: 0 auto;
}
}
.marker {
background-image: url('YOUR-MARKER-ICON-URL');
background-size: cover;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
.mapboxgl-popup {
max-width: 200px;
}
.mapboxgl-popup-content {
text-align: center;
font-family: 'Open Sans', sans-serif;
padding: 15px;
background: #fdfbf0;
}
.mapboxgl-popup-content h3 {
font-size: 16px;
}
.mapboxgl-popup-content p {
font-size: 12px;
margin: 0;
}
</style>
<script src='https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css' rel='stylesheet' />
Replace YOUR-MARKER-ICON-URL with the URL to your custom marker icon (upload an image to your Shopify Files section to get the URL).
Building the Store Locator Template
Now let's create the actual store locator page. In your pages.stores.liquid file, add the following code:
<article id="{{page.handle}}" class="page entry">
<header>
<div class="title-bar custom-font"
style="padding-top: 30px;padding-bottom: 10px;text-align: center;">
<h1 class="main-heading">{{ page.title }}</h1>
</div>
</header>
<section>
<div id='map'></div>
<script>
var geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-74.0060, 40.7128]
},
"properties": {
"title": "Downtown Manhattan Store",
"description1": "123 Broadway",
"description2": "New York, NY 10006"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-73.9442, 40.6782]
},
"properties": {
"title": "Brooklyn Heights Location",
"description1": "456 Atlantic Ave",
"description2": "Brooklyn, NY 11201"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-73.9626, 40.7589]
},
"properties": {
"title": "Midtown Store",
"description1": "789 5th Avenue",
"description2": "New York, NY 10022"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-73.9903, 40.7308]
},
"properties": {
"title": "East Village Shop",
"description1": "321 Avenue A",
"description2": "New York, NY 10009"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-73.9712, 40.7831]
},
"properties": {
"title": "Upper West Side Location",
"description1": "654 Amsterdam Ave",
"description2": "New York, NY 10025"
}
}
]
};
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN_HERE';
var map = new mapboxgl.Map({
container: 'map',
center: [-74.0060, 40.7128],
style: 'mapbox://styles/mapbox/streets-v11',
zoom: 11
});
// add markers to map
geojson.features.forEach(function(marker) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
// make a marker for each feature and add to the map
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 })
.setHTML('<h3>' + marker.properties.title + '</h3><p>' + marker.properties.description1 + '</p><p>' + marker.properties.description2 + '</p>'))
.addTo(map);
});
</script>
</section>
<section class="entry-content" style="padding-bottom: 30px; max-width: 800px; margin: 0 auto;">
<h2 style="text-align: center; padding: 60px 0 30px 0;">Our Locations</h2>
<ul class="one-column-list" style="text-align: left;">
<li>Downtown Manhattan Store, 123 Broadway, New York</li>
<li>Brooklyn Heights Location, 456 Atlantic Ave, Brooklyn</li>
<li>Midtown Store, 789 5th Avenue, New York</li>
<li>East Village Shop, 321 Avenue A, New York</li>
<li>Upper West Side Location, 654 Amsterdam Ave, New York</li>
</ul>
</section>
<section class="entry-content" style="padding-top: 30px">
{{ page.content }}
</section>
</article>
Understanding the Code
The template above has three main sections:
- Header: Displays the page title
- Map Section: Contains the interactive Mapbox map with your store locations marked with custom pins
- Location List: A simple text list of all locations for accessibility and SEO
The geojson object is where you define your store locations. Each feature in the array represents one store location with:
coordinates: The longitude and latitude (in that order - it's[lng, lat], not[lat, lng])title: The store namedescription1: Street addressdescription2: City and state
To find the coordinates for your stores, you can use Google Maps - right-click on a location and select the coordinates to copy them.
Creating the Page in Shopify
Once you've saved your pages.stores.liquid template:
- Go to Online Store > Pages in your Shopify admin
- Click "Add page"
- Give it a title like "Store Locator" or "Find a Store"
- In the right sidebar under "Theme template", select "stores" from the dropdown
- Publish the page
That's it! Your custom store locator page is now live.
Customizing Your Map Style
The code above uses Mapbox's default streets style (mapbox://styles/mapbox/streets-v11), but you can create your own custom map style to match your brand. To do this:
- Log into your Mapbox account and navigate to the Styles section
- Click "New style" and choose a template to start from (streets, light, dark, etc.)
- Use the Mapbox Studio editor to customize colors, fonts, and map features
- Once you're happy with your style, click "Share" and copy the style URL
Then, update the style property in your store locator code to use your custom style URL:
var map = new mapboxgl.Map({
container: 'map',
center: [-74.0060, 40.7128],
style: 'mapbox://styles/YOUR-USERNAME/YOUR-STYLE-ID', // Replace with your custom style URL
zoom: 11
});
Your custom style URL will look something like mapbox://styles/username/ckabcd1234567890. This allows you to have complete control over your map's appearance without touching any CSS.
Adding More Locations
To add more store locations, simply add new feature objects to the geojson.features array and update the location list below the map. Make sure to keep the format consistent.
Hope this helps!