Creating your own vector tiles

OS Open Zoomstack and the OS Vector Tile API already offer some amazing mapping which can be used as the basis for overlaying other information

7 minute read
There are various ways to add data overlays to your base map including data received from Web Feature Services (WFS) such as the OS Features API or simply GeoJSON files which are stored on your web server.

As part of our developer series, we recently discussed the benefits of vector tiles in one of our previous blog posts.

Although both these options are perfect for smaller volumes of data (in terms of number of features and/or geometric complexity), sometimes it makes more sense to take advantage tiled vector data which can enable data of any size to be quickly rendered in your browser.

The OS Vector Tile API already offers a selection of data overlays but, with the right tooling and a bit of data processing, it is relatively straight-forward to generate your own.

In this blog, we are going to look at the steps involved in creating your own vector tile overlay using the parliamentary constituency polygons from the Boundary-Line dataset. Although we are using the parliamentary constituencies in this example, it is possible to swap in any of the administrative and electoral boundaries (or alternatively the entire dataset as demonstrated here).

There are various applications/libraries which can generate vector tilesets. In this post, we will be concentrating on an open source tool called Tippecanoe.

Tippecanoe creates vector tilesets from [large] GeoJSON feature collections. The output is an MBTiles file that can be uploaded to Mapbox or a directory of files that can be self-hosted.

Downloading the data

The first step is to download the Boundary-Line data in GeoPackage format from the OS OpenData downloads area of the Data Hub:

Conversion to GeoJSON

Once the Boundary-Line GeoPackage has been downloaded and extracted from the zip archive, we need to extract the parliamentary constituencies as a GeoJSON feature collection (which is the format Tippecanoe requires as its input).

This can be achieved using GDAL (Geospatial Data Abstraction Library), which is one of the fantastic format conversion tools we previously highlighted in the useful tools for web mapping blog post. GDAL provides a variety of raster and vector programmes.

ogr2ogr is one of the vector programmes which can be used for converting simple features data between file formats. It can also perform various operations during the process, such as spatial or attribute selection, reducing the set of attributes, setting the output coordinate system or even reprojecting the features during translation.

We are going to use the following command:

ogr2ogr -f GeoJSON westminster_const.geojson bdline_gb.gpkg -sql “SELECT * FROM westminster_const” -s_srs “+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.999601 +x_0=400000 +y_0=-100000 +ellps=airy +units=m +no_defs +nadgrids=./OSTN15_NTv2_OSGBtoETRS.gsb” -t_srs EPSG:4326 -lco RFC7946=YES

Let’s break this down:

-f GeoJSON – denotes the output file format name.
westminster_const.geojson – the destination data source name.
bdline_gb.gpkg – the source data source name.
-sql “SELECT * FROM westminster_const” – the SQL statement to execute (in this case selecting all the features from the “westminster_const” layer).
-s_srs “+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.999601 +x_0=400000 +y_0=-100000 +ellps=airy +units=m +no_defs +nadgrids=./OSTN15_NTv2_OSGBtoETRS.gsb” – override the source spatial reference system to ensure the OSTN15/OSGM15 transformation is utilised*.
-t_srs EPSG:4326 – reproject/transform to the WGS84 spatial reference system (which is the default for both GeoJSON and Tippecanoe) on output.
-lco RFC7946=YES – layer creation option to use RFC 7946 standard.

* For further information (including the download link for theNTv2 format files), take a look at this page on the OS website.

Generating the vector tileset

The Tippecanoe homepage has a lot of information around the various options and tooling for configuring the vector tileset output. You can take some time to look at this in more detail, but for our purposes we can keep things relatively simple.

The command we are going to use is as follows:

tippecanoe -ab -z12 -Z5 -e boundaries -l westminster-constituencies westminster_const.geojson

Again, breaking this down:

-ab – improve shared polygon boundaries by detecting borders that are shared between multiple polygons and simplify them identically in each polygon.
-z12 – the highest zoom level (maxzoom) for which tiles are generated.
-Z5 – the lowest zoom level (minzoom) for which tiles are generated.
-e boundaries – write tiles to the specified directory (named “boundaries”) instead of to an MBTiles file.
-l westminster-constituencies – use the specified layer name instead of deriving a name from the input filename.

You will notice that we are only generating the tiles to a maximum zoom level of 12. This is because all boundaries in the Boundary-Line dataset are captured and maintained to a generalised scale of 1:10 000. We could generate the tiles to higher zoom levels, but we wouldn’t be gaining any greater levels of detail and would only be outputting a more verbose tileset than is actually required.

Web application


When using the vector tiles in a web application (where we could have additional zoom levels representing more detailed mapping), we can take advantage of a feature known as over-zooming.

This is another one of the nice features of vector tiles. It means you don’t necessarily need to generate tiles for every zoom layer the browser supports and, provided you specify the zoom levels your source physically contains files for, your client application will be able to display the tileset beyond its given zoom extent.

In our case, it means the parliamentary constituencies would still be visible in the map at zoom level 18 (even though we only have tiles for level 12).

Using the OS Vector Tile API – Display a basic map (EPSG:3857) Mapbox GL JS example as a starting point, below is a code sample which demonstrates how the parliamentary constituency vector tileset can be added as a new source/layer.

Please note the sections in bold – these will need to be replaced with the appropriate values.

<!DOCTYPE html>
<meta charset=”utf-8″ />
<meta name=”viewport” content=”initial-scale=1,maximum-scale=1,user-scalable=no” />
<link rel=”stylesheet” href=”” />
<link rel=”stylesheet” href=”” />
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
:focus { outline: none; }

<div id=”map”></div>

<script src=””></script>
<script src=””></script>

var apiKey = ‘INSERT_API_KEY_HERE‘;

var osVectorTileServiceUrl = ‘’,
localVectorTileServiceUrl = ‘INSERT_LOCAL_TILESET_URL_HERE‘;

// Initialize the map object.
map = new mapboxgl.Map({
container: ‘map’,
minZoom: 6,
maxZoom: 18,
maxBounds: [
[ -10.76418, 49.528423 ],
[ 1.9134116, 61.331151 ]
style: osVectorTileServiceUrl + ‘/resources/styles?key=’ + apiKey,
center: [ -1.485, 52.567 ],
zoom: 7,
transformRequest: url => {
if( url.includes(osVectorTileServiceUrl) )
return {
url: url + ‘&srs=3857’

map.dragRotate.disable(); // Disable map rotation using right click + drag.
map.touchZoomRotate.disableRotation(); // Disable map rotation using touch rotation gesture.

// Add navigation control (excluding compass button) to the map.
map.addControl(new mapboxgl.NavigationControl({
showCompass: false

map.on(‘load’, function() {
// Add a source for the boundary polygons.
map.addSource(“boundaries”, {
“type”: “vector”,
“tiles”: [ localVectorTileServiceUrl + “/{z}/{x}/{y}.pbf” ],
“maxzoom”: 12

// Add a layer showing the boundary polygons.
“id”: “boundaries-layer”,
“type”: “fill”,
“source”: “boundaries”,
“source-layer”: “westminster-constituencies”,
“layout”: {},
“paint”: {
“fill-color”: “rgba(242, 133, 34, 0.4)”,
“fill-outline-color”: “rgba(242, 133, 34, 1)”

// When a click event occurs on a feature in the boundaries layer, open a popup at the
// location of the click, with name HTML from its properties.
map.on(‘click’, ‘boundaries-layer’, function(e) {
new mapboxgl.Popup()

// Change the cursor to a pointer when the mouse is over the boundaries layer.
map.on(‘mouseenter’, ‘boundaries-layer’, function() {
map.getCanvas().style.cursor = ‘pointer’;

// Change it back to a pointer when it leaves.
map.on(‘mouseleave’, ‘boundaries-layer’, function() {
map.getCanvas().style.cursor = ”;



Get started

Launched on 1 July, the OS Data Hub is the new way to access our authoritative location data. It’s replaced the current OS ordering systems (OpenData Portal, OS Orders and API shop) with one mobile-friendly platform with a single sign on to give you a better user experience.

To follow this tutorial, download the Boundary-Line data here. Alternatively if you want to explore the OS Vector Tile API, go straight to the OS Data Hub.

OS for developers

Whether you’re new to geospatial or a GIS data expert, our data platform grants access to our data

By Press Office

Sharing the latest news about OS. We can license you to use OS maps in print, online and film format. For more information and resources for journalists, bloggers and media professionals, email or call 023 8005 5565.

Products and solutions featured in this blog

  • OS Vector Tile API

    A vector tile service providing detailed Ordnance Survey data as a customisable basemap.

  • Boundary-Line

    Ordnance Survey's Boundary-Line™ is an open dataset of every administrative boundary in Great Britain.