Tutorials and hands-on lessons for learning

Sheet Mapper

Create a live-updating map that displays the locations of all your POIs or events, powered by a spreadsheet.

View fullscreen demo

Many organizations use spreadsheets to collaborate and collect data, so we are often asked how to create a map from data in this format.

This blueprint is appropriate for any organization trying to map a set of locations from a CSV or Google Sheet — to display offices, emergency shelters, distributed events, and more.

This solution also can be used with more advanced functionality, including data joins to other tilesets, routing between locations, and more.

Getting started

There are a few resources you'll need to get started:


Tools we'll use:

  • Google Sheets to create and store your event data.
  • Text Editor (Atom, VSCode, JSFiddle) to write and edit your code.‍
  • Mapbox account to access: ‍‍‍

    Mapbox Studio to create your map style.

    Mapbox GL JS to add interactivity to your map and publish it on the web‍‍.

  • csv2geojson to convert CSV and TSV files to GeoJSON data suitable for maps‍
  • GitHub account to publish your Mapbox GL JS map

Note: This tutorial demonstrates how to access data from a Google Sheet using csv2geojson, but this solution is also appropriate for users storing data as a CSV or TSV. For more information read the csv2geojson README.

Create data in Google sheet

Set up a Google Spreadsheet with the data for your map. You can duplicate your sheet from this template or start your own. You need longitude and latitude for each point to place your map marker. Name, Address, and additional fields will be displayed in the popups.

Need help with generating lat/long points? You can use Nominatim, an open-source OpenStreetMap tool, for forward and reverse geocoding.

  1. Go to https://nominatim.openstreetmap.org/
  2. Search an address in the search bar
  3. Click the Details button, copy the coordinates listed in the Centre Point row, and paste into your spreadsheet.

Once your table is complete, set sharing settings to 'Anyone with the link can view' so the data is visible without granting access to change it. To create an export link, copy the following link to a notepad or some other document to be used later:


Replace {key} with your Google Sheet ID and {sheet_name} with the name of your sheet.

Google Sheet link:


Google Sheet ID: 1MiqwGe_7m6B0xFQfaS3GGRO8CmGm5xlXPICDPEeGHyo

Sheet name: Sheet1

Updated link:


Start your map code

Open a text editor and create a file called index.html. Set up the document downloading the demo code.

Add your Mapbox access token

Without an access token, the rest of the code will not work.‍

Login or create a free Mapbox account. Find your access token on your Access tokens page or the main page you sign into your Mapbox account.

Note: We recommend using the URL restriction feature on the token to avoid token misuse and want to emphasize that only public tokens should be posted to public repositories. Find out more information about how to securely manage your access tokens.

//YOUR TURN: add your Mapbox token
mapboxgl.accessToken =

Add a basemap style

There are several Mapbox-designed map styles that you can choose "out of the box" or you can design your own using the Mapbox Studio style editor. Let’s use Mapbox Streets:

Add Streets Style to your map by replacing 'Replace with Mapbox style URL' with mapbox://styles/mapbox/streets-v11.

//YOUR TURN: add your Mapbox token
mapboxgl.accessToken =
  'pk.eyJ1IjoibWFwYm94LWNvbW11bml0eSIsImEiOiJja2tkN21jcjAwMG51MnBxdHAxemdueGpzIn0.e0IzLkytGq4pcGGieP8KNA'; //Mapbox token
var map = new mapboxgl.Map({
  container: 'map', // container id
  style: 'mapbox://styles/mapbox/streets-v11', // YOUR TURN: choose a style: https://docs.mapbox.com/api/maps/#styles
  center: [-122.411, 37.785], // starting position [lng, lat]
  zoom: 10, // starting zoom
  transformRequest: transformRequest

Connect your spreadsheet

The code uses csv2geojson to retrieve data from the Google Sheet CSV export that you saved in Step 1 and convert into a GeoJSON.

To connect your Google Sheet, replace the ‘url’ value with your Google Sheet export link.

   $(document).ready(function () {
        type: "GET",
        //YOUR TURN: Replace with csv export link
        url: 'https://docs.google.com/spreadsheets/d/1dLkr70tfAL_-U6ipad9xLF39lHmU8k-xd08uKHkLD5M/gviz/tq?tqx=out:csv&sheet=Sheet1',
        dataType: "text",
        success: function (csvData) { makeGeoJSON(csvData); }

Add layer to the map

The next part of the code adds the layer to the map and specifies how it will be styled. In this example, the layer is added as a circle with a 5 px radius and the color is set to purple. You can read more about layer types and available paint and layout properties in the Mapbox Style Specification.

//Add the the layer to the map
  id: 'csvData',
  type: 'circle',
  source: {
    type: 'geojson',
    data: data
  paint: {
    'circle-radius': 5,
    'circle-color': 'purple'

Note: You can add an icon to symbolize your locations by changing the type to 'symbol' and updating the paint properties. For more information check out the following example.

Add popups

When a user clicks a symbol we want to show a Popup containing more information about the locations stored in our spreadsheet. The text for each popup is assigned to the fields ‘Name’, ‘Address’, and ‘Phone’.

// When a click event occurs on a feature in the csvData layer, open a popup at the
// location of the feature, with description HTML from its properties.
map.on('click', 'csvData', function(e) {
  var coordinates = e.features[0].geometry.coordinates.slice();

  //set popup text
  //You can adjust the values of the popup to match the headers of your CSV.
  // For example: e.features[0].properties.Name is retrieving information from the field Name in the original CSV.
  var description =
    `<h3>` +
    e.features[0].properties.Name +
    `</h3>` +
    `<h4>` +
    `<b>` +
    `Address: ` +
    `</b>` +
    e.features[0].properties.Address +
    `</h4>` +
    `<h4>` +
    `<b>` +
    `Phone: ` +
    `</b>` +
    e.features[0].properties.Phone +

  // Ensure that if the map is zoomed out such that multiple
  // copies of the feature are visible, the popup appears
  // over the copy being pointed to.
  while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
    coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;

  //add Popup to map

  new mapboxgl.Popup()

// Change the cursor to a pointer when the mouse is over the places layer.
map.on('mouseenter', 'csvData', function() {
  map.getCanvas().style.cursor = 'pointer';

// Change it back to a pointer when it leaves.
map.on('mouseleave', 'places', function() {
  map.getCanvas().style.cursor = '';

var bbox = turf.bbox(data);
map.fitBounds(bbox, { padding: 50 });

If you want to add different fields, change the display text (e.g. ‘Address:’) and the e.features[0].properties.columnName (e.features[0].properties.Address) to match the corresponding column label in your CSV.

Publish your map

You’ve made a web map! But it isn’t a webpage yet… to do that we need some way to host a webpage. There are many different ways to host a webpage. Read this guide to learn how to publish your finished map on GitHub, Netlify, or Glitch.

Finished project

View our finished example map at https://labs.mapbox.com/impact-tools/spreadsheet-to-map/.

Need more help? Ask questions on Stack Overflow or contact Mapbox Support. If you are working on a social good project, contact the Mapbox Community Team.

Want to share what you’ve built? Tweet it with #builtwithmapbox

Was this page helpful?