Skip to content
An easy-to-use template to tag, store, and search your content using location context
JavaScript Shell Perl HTML CSS
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Content Tagging

This Solution Architecture provides an easy-to-use template to tag your content with location context, store it, and then retrieve it based on end-user searches. This solution is comprised of two applications, a Node.js API server that handles content ingestion and search, and a UI frontend to upload and visually display content that has been indexed.

Content Tagging



To begin development you will need the following:


You will need to have Node v8.10+ installed to run this solution.


For development purposes only you will need to have Docker installed. This is used to run the default Elasticsearch instance that will power indexing and search.


For production use, or if you do not wish to use Docker, you must install Elasticsearch v7+. For instructions on installing Elasticsearch in your environment, consult the Elasticsearch documentation.

For development, this dashboard will run a Dockerized version of Elasticsearch Basic edition. This is free-to-use and features are documented on the Elastic website. Mapbox will not provide Elasticsearch support.


You will need a Mapbox public token with access to the Mapbox Permanent Geocoding API. If you do not have a Mapbox account sign up here. If you don’t have access to the mapbox.places-permanent endpoint for permanent geocoding, contact Mapbox sales to request access.


Once you have secured access to the Permanent Geocoding API, add your Mapbox access token to the environment. You can do this in two ways: either export the access token as an environment variable or create a .env file with all your configuration variables. For an example of how to structure your .env file, see sample.dotenv in the repository.

The configuration variables available:

  • ELASTIC_URL: Optional, defaults to localhost:9200. If you have your own Elasticsearch cluster set the url here



Clone the repository and install dependencies for the server and UI starting in the repository root:

% npm ci
% cd ui && npm ci

Starting Elasticsearch with Docker

Before starting up the server you’ll need to start a docker container with Elasticsearch. You can do this with a default Elasticsearch configuration in a fresh container with this command, run from the project root:

% npm run-script docker

To start start from a fresh index, restart the docker container and all data will be cleared (uploaded images will remain in /public). In a production environment, use snapshots to prevent data loss in the event of a stopped Elasticsearch process.

Starting the Application

In a new terminal window, start both the user interface and server from the project root by running:

% npm start

You will see the react application and development server start with live-reload enabled

> @ start /content-tagging
> cd ui && npm start
> pics@0.1.0 start /content-tagging/ui
> SKIP_PREFLIGHT_CHECK=true concurrently "react-scripts start" "cd .. && nodemon server/app.js "
\[1\] [nodemon] 1.19.4
\[1\] [nodemon] to restart at any time, enter rs
\[1\] [nodemon] watching dir(s): .
\[1\] [nodemon] watching extensions: js,mjs,json
\[1\] [nodemon] starting node server/app.js
[1] This is Listening on 3001
[0] Starting the development server...

This will also a browser window with the UI loaded at http://localhost:3000 . You should see an Image Search form, and a File Upload control as seen below.

Uploading Images

Start with uploading an image. From the browser click Choose Files, and select a sample image encoded with EXIF GPS information from the sample-images folder.

In this example, we are using chenonceau.jpg , which was taken in France. The client application POSTs the image to the /upload endpoint (see server/upload.js) which does several things:

  1. Uploads the image to the /public folder. To modify where images are stored see upload.js:7
  2. Extracts geographic coordinates from the image's EXIF tags.
  3. Calls the ingest function, defined in server/ingest.js.
  4. The ingest function calls the Mapbox Geocoding and Raster Tiles APIs to add location and elevation metadata
  5. Inserts a reference to the image along with all metadata into Elasticsearch for indexing. Since this is our first piece of content, Elasticsearch automatically creates a new index with default mappings. Read more about how to customize Elasticsearch mappings here.

Upon completion, a status box will appear indicating that the image was successfully uploaded.

In the terminal, you will see the results of the ingest function requesting geographic and elevation data from Mapbox.


Once you have the image uploaded, from the Image Search form, type in “France” or “Chenonceau”. To view all uploaded images search for “*”. The interface passes the search query to the /search endpoint (see server/search.js for more) which performs a basic full-text search of our Elasticsearch index.

Press return and the image you uploaded appears.

Deployment & Customization

Ingesting Other Types of Content

The /upload api uploads and ingests images by extracting EXIF information and passig it to the ingest functions. However the application can also be used to tag and index other types of content by using the /ingest api directly.

Any piece of content with a latitude and longitude can be tagged and indexed in this way provided it has latitude, longitude, and a url (referenced here as imgUrl). For example, to ingest an image stored elsewhere:

curl --request POST \
  --url http://localhost:3001/ingest \
  --header 'content-type: application/json' \
  --data '[{"imgUrl": "","coordinates": ["116.27963213522958", "39.857073723727865"],"createdAt": "tuesday","message": "this is taken outside the forbidden palace"}]'

Enhanced Tagging

There are several ways to augment and extend this solution for production including enhanced tagging:

  • Tag content using custom geometry like regions or service areas using the Mapbox TileQuery API.
  • Put text documents on the map — tag location extracted from text documents like news articles or ancestral records using forward geocoding.

This logic would be added to the processItem function found in server/ingest.js

Tuning Elasticsearch

There are many ways to further tune Elasticsearch to return more relevant search results. First, consider mappings, which define how a piece of content and the fields it contains, are stored and indexed. Read more about how to customize Elasticsearch mappings in the Elasticsearch docs.

A second is to customize the query structure, found in server/search.js to do things like only searching certain fields such as Address or Country. Read more about how to construct Elasticsearch queries in the Elasticsearch docs.

Lastly, running Elasticsearch in the cloud makes it easy to deploy, operate, and scale. There are also several options including and AWS


Mapbox Solutions Architecture


This project is licensed under the BSD-3-Clause License - see the file for details

You can’t perform that action at this time.