Troubleshooting

Tilesets API recipe reference

Public beta

The Tilesets API features and workflows discussed in this guide are in public beta. All features and workflows are subject to potential future changes.

Current version: 1

Tileset recipes are tile transformation documents that tell the Tilesets API how to turn tileset source data into vector tiles. Recipes must be constructed according to the rules in this recipe reference.

Recipe top-level fields

A recipe is a JSON object that must contain the following top-level fields:

Required fieldsDescriptionData type
versionThe version of the Tilesets API recipe reference that the recipe uses. The current version number is 1. Any version value other than the current version or a previous version will result in an error.Integer
layersThe LayerObject is an object in which the keys are the names of the layer and their values are objects that represent the configuration and options for the layer.Object
{
  "version": 1,
  "layers": { ... }
}

LayerObject

A layer object is the primary way of describing how a vector tile layer should be created. It specifies where to retrieve source data, the precision of the data through zoom levels, and how to transform features and render them into tiles. The following fields are the top-level options for a single layer:

Required fieldsDescriptionData type
sourceThe source data to use for this layer. Tileset sources are created with the Create a tileset source endpoint of the Tilesets API.String
minzoomDescribes the lowest zoom level for the tileset.Integer
maxzoomDescribes the highest zoom level for the tileset. More info.Integer

You can further refine the resulting tileset with the following optional fields:

Optional fieldsDescriptionData type
featuresSpecifies the output on a per feature basis. More info.Object
tilesSpecifies the output on a per tile basis. More info.Object

The following describes every available field for a LayerObject and the JSON type that field must be.

{
  "minzoom": Integer,
  "maxzoom": Integer,
  "features": {
    "id": {
      "attribute_id": String,
      "add_to_attributes": String,
      "output_id": Boolean
    },
    "attributes": {
      "zoom_element": Array,
      "set": Object,
      "allowed_output": Array
    },
    "filter": Object,
    "simplification": Number or Array
  },
  "tiles": {
    "extent": Integer,
    "buffer_size": Integer,
    "limit": Array,
    "union": [
      {
        "group_by": Array,
        "aggregate": Array,
        "maintain_direction": Boolean,
        "where": Array
      }
    ]
  }
}

Basic example

The simplest example tileset recipe includes a layer name, a tileset source ID, a minimum zoom value, and a maximum zoom.

{
  "version": 1,
  "layers": {
    "trees": {
      "source": "mapbox://tileset-source/{username}/trees-data",
      "minzoom": 4,
      "maxzoom": 8
    }
  }
}

Multi-layer recipes

Recipes can also be arrays of recipe objects. This format can be used to create multi-layer tilesets. Recipes can have a maximum of 20 layers defined.

{
  "version": 1,
  "layers": {
    "trees": { ... },
    "parks": { ... },
    "paths": { ... }
  }
}

Layer name configuration

The layer name key is required for each LayerObject (e.g. "trees", "parks", and "paths" in the above example). This is the unique identifier for the layer of data in your final tileset. For any map each layer name must be unique. The layer name must be a string with only underscores (_) and alphanumeric characters.

Source configuration

A source refers to a tileset source, which is a collection of geographic data stored as line-delimited GeoJSON on Mapbox.com. Tileset sources can be created via the Create a tileset source endpoint of the Tilesets API.

Zoom level configuration

The minzoom and maxzoom configurations control the zoom levels at which your data will be tiled. They are required for a recipe. These values must be integers. The minzoom must be less than or equal to maxzoom, and both must be between the values of 0 and 16.

Zoom levels play a large role in your output tileset. The higher the zoom level, the higher fidelity your data is as users zoom in. This also comes at a cost. Increasing zoom level fidelity creates exponentially more tiles!

It’s important to consider the cases your map is trying to solve when choosing zoom levels. If your users are going to be viewing the map at a global extent it’s not necessary to choose a high zoom. If your users are going to be viewing the map at a city or street level, high zooms will be helpful for the most accurate data.

If you know the precision to which you want your data to be represented, this table shows the approximate precision corresponding to various minzoom and maxzoom choices:

Zoom levelPrecision in feetPrecision in meters
032000 ft10000 m
116000 ft5000 m
28000 ft2500 m
34000 ft1250 m
42000 ft600 m
51000 ft300 m
6500 ft150 m
7250 ft80 m
8125 ft40 m
964 ft20 m
1032 ft10 m
1116 ft5 m
128 ft2 m
134 ft1 m
142 ft0.5 m
151 ft0.25 m
160.5 ft0.125 m

Feature configuration

The features configuration object is used to describe how features are individually processed into vector tiles. This field contains the following elements, which are evaluated in the order of the list provided below:

Optional fieldsDescriptionData type
idA JSON object that describes both how to identify a feature in a recipe and how that feature will be identified in the resulting tile. See the feature IDs section for more details.Object
attributesA JSON object that controls how attributes are modified and which attributes are allowed in the resulting tileset.Object
filterA filter expression determining which features should be retained. If no filter is defined, the default filter is true and all features will be retained.Array
simplificationAn integer expression or value that is greater than zero that controls the level of simplification that occurs for features. This integer value is relative to the extent provided for the tiles, with a larger value resulting in more simplification.Integer or Array

Feature IDs

The id configuration gives you control over what field is used as the feature ID during tiling. It also allows you to specify where to put this ID in the resulting tileset as an attribute.

The following fields are allowed in the id object:

Optional fieldDescriptionData type
attribute_idBy default, the standard ID field in the tileset source GeoJSON will be used as IDs. But it is possible to use a specific attribute key for an ID instead. If this configuration option is provided, the attribute with a key that matches the string provided here will be used as the ID.String

In this example, the recipe indicates that the iso_2 property in each feature should be the feature ID in the resulting tileset:

{
  "features": {
    "id": {
      "attribute_id": "iso_2"
    }
  }
}
Optional fieldDescriptionData type
add_to_attributesAdds your original ID field to the attributes of features using the key name provided. This is helpful in retrieving original string IDs that have been converted to integers in the vector tile feature.String

In this example, the recipe saves the top-level ID field in the attribute road_id of the final vector tile. This is particularly helpful for saving top-level string IDs that will otherwise be converted to integers in the final vector tile.

{
  "features": {
    "id": {
      "add_to_attributes": "road_id"
    }
  }
}
Optional fieldDescriptionData type
output_idBy default this value is true. Places the ID into the ID field of the vector tile. If you do not want numeric IDs in this field, change to false.Boolean

If output_id is true, the ID is saved to the id field within a feature of a vector tile. The current Mapbox Vector Tile Specification does not allow for string-based IDs in features, so if this value is true any string IDs will be converted to an integer using a hash.

In this example, the recipe adds feature IDs to feature attributes using the attribute my_id, but does not place the ID in the final vector tile ID field.

{
  "features": {
    "id": {
      "add_to_attributes": "my_id",
      "output_id": false
    }
  }
}

Feature filters

The filter configuration is a single filter expression that results in a true or false evaluation for each feature as configured by the minzoom and maxzoom. This is the primary way to control which features are allowed into the final tileset on a per-feature basis. If no filter is provided, by default this results in a value of true for all features.

Filter expressions

In various configurations throughout the recipe, you have the ability to select relevant features by their attributes. This is possible with filter expressions, which use the Mapbox GL JS expression syntax defined in the Mapbox GL JS Style Spec.

Each filter is a JSON array that is evaluated for a boolean or value result using the following operations:

  • Type assertion:

    • array, boolean, number, object, string, typeof
  • Type conversion:

    • to-boolean, to-number, to-string
  • Quoting:

    • literal
  • Feature characteristics:

    • geometry-type, id, zoom
  • Data retrieval:

    • properties, at, get, has, length
  • Comparison:

    • ==, !=, <, >, <=, >=, step
  • Boolean operations

    • !, all, any
  • Conditionals:

    • case, coalesce, match
  • Local variables

    • let, var
  • String manipulation

    • concat, downcase, upcase
  • Arithmetic

    • -, +, /, *, ^, %, abs, ceil, floor, e, ln, ln2, log10, log2, max, min, round, sqrt
  • Trigonometry

    • acos, asin, atan, cos, sin, tan, pi

Feature attributes

The attributes configuration allows for manipulation of attribute data, generation of new attributes, and removal of attributes. The available options are described below, and implemented in the order they are listed:

Optional fieldDescriptionData type
zoom_elementA JSON array that provides a list of attributes that are specified per zoom level in the source data.Array<String>

For each attributes with a specified zoom_element, the final output attribute at zoom level N will be the Nth element in the array in the source data. If no zoom_element is defined, no attributes are altered. If the zoom level is greater than or equal to the number of elements in the array, the last element is used.

Consider the following attributes for a single GeoJSON feature:

{
  "type": "Feature",
  "geometry": { ... },
  "properties": { "name": [ null, null, "Main", "Main St.", "Main Street" ] }
}

In this example, the zoom_element array includes name. Using the attributes from the GeoJSON above, this feature would have no name attribute at zoom levels 0 and 1, would have "Main" at zoom level 2, "Main St." at zoom level 3, and "Main Street" at zoom levels 4 and above.

{
  "features": {
    "attributes": {
      "zoom_element": [ "name" ]
    }
  }
}
Optional fieldDescriptionData type
setA JSON object mapping the names of attributes to be generated to filter expressions that return the new attribute values. Particularly helpful for generating ranking schemes to be used in styling expressions.Object

Consider the following attributes for a single GeoJSON feature:

{
  "type": "Feature",
  "geometry": { ... },
  "properties": { "place": "state", "name": "California" }
}

In this example, the set attribute defines a new attribute to be included in the final tileset, labelrank, that is derived from the existing data's place attribute. Using the "match" expression, it assigns a value to features based on the value of "place". If "place" is equal to "country", then the labelrank attribute for the resulting feature will have a value of 0, and so on. It also provides a default value of 5 for any features that have a "place" value that does not match any of the values explicitly provided.

{
  "features": {
    "attributes": {
      "set": {
        "labelrank": [
          "match", [ "get", "place" ],
          "country", 0,
          "state", 1,
          "region", 2, "province", 2,
          "district", 3, "county", 3,
          "municipality", 4, "city", 4,
          5
        ]
      }
    }
  }
}
Optional fieldDescriptionData type
allowed_outputA JSON array of attributes that controls which attributes will be carried over into the resulting tileset.Array<String>

If an allowed_output array is provided only the attributes specified in the array will be saved to the tileset. This does not prevent the attributes that are not excluded by allowed_output from being used in filter expressions and other steps throughout the publish job.

In this example, features in the resulting tileset will only have two attributes, name_en & name_es:

{
  "features": {
    "attributes": {
      "allowed_output": [ "name_en", "name_es" ]
    }
  }
}

Feature simplification

Optional fieldDescriptionData type
simplificationIndicates the desired level of simplification. Larger values result in more simplification, in which some vertices are removed. The default value is 4. The maximum value is 4096.Integer or Array

The simplification expression or value describes the maximum distance that a point can be from the straight line that connects its two neighbors and still be considered to be on the line, and can therefore be removed safely. Any point with a distance that is larger than the simplification value is considered to be away from the line, and must be preserved.

As you increase the simplification value, the number of vertices in each feature decreases. The Tilesets API recipe validator will reject any simplification value that is more than 4096. If you do not add a value for simplification, the Tilesets API will use 4, the default value.

The resulting shape depends on the original shape of your feature. For instance, if your original feature is circular and you increase simplification, the result will look more like a polygon. If your original feature is a curved line and you increase simplification, the result will look more like a straight line.

The Tilesets API uses the Ramer–Douglas–Peucker algorithm to simplify features.

The simplification may be a constant number, or it may be an expression that evaluates to a number. A typical use for an expression for the simplification would be to use a minimal simplification at the layer's maximum zoom level, so it can be overzoomed with high precision, but to use a larger simplification at lower zoom levels that will never be magnified very far.

Tile configurations

The tiles object contains the following elements, which are evaluated as each tile is being assembled from its component features:

Optional fieldDescriptionData type
buffer_sizeControls the size of the buffer that will be created in your vector tiles.Number

buffer_size represents a percentage of the size of a tile. The default buffer size is 0.5. Note that the value of this attribute cannot be larger than 100.

Buffers are particularly helpful for label point layers to avoid cutting labels of at tile boundaries.

Optional fieldDescriptionData type
layer_sizeSpecifies the size limit in kibibytes of each layer.Integer

The default value is 500 KiB. The value cannot be larger than 500 or smaller than 1. Configuring layer_size can be helpful for improving rendering speed.

Optional fieldDescriptionData type
remove_filledControl which "filled" features are removed by specifying a filter-expression.Array<Expression>

During tile creation it is possible for polygons to completely cover a tile and the area surrounding its buffer. These are called as "filled features". If all features within a tile are filled features, it may be useful for some tilesets to not create any tiles at all and expect that clients will look to higher zoom levels. To do this, you can use the remove_filled recipe.

The syntax utilizes a filter-expression to allow control over what features exactly should be removed.

"tiles": {
  "remove_filled": expression
}

No tile will be created if:

  • All features within the tile are considered filled features
  • All features are matched by the filter-expression provided in remove_filled

The following example removes all tiles that contain only filled features:

"tiles": {
  "remove_filled": true
}

The following example removes all tiles that contain only filled features after zoom level 5:

"tiles": {
  "remove_filled": [">", [ "zoom" ], 5]
}
Optional fieldDescriptionData type
limitA limitation rule that reduces the number of features for the specified type to a specific number, choosing the lowest or highest-numbered features according to some attribute.Array<Expression>

The limit field must be an array of limitation rules, each of which is evaluated in sequence to potentially limit the total number of features to be included in the final tile.

Rules that limit the total number of features in a tile have one of following forms:

  • [ "lowest_where", filter-expression , number , attribute ]
  • [ "highest_where", filter-expression , number , attribute ]

Rules that limit the number of features within a specified distance have one of the following forms:

  • [ "lowest_where_in_distance", filter-expression , number , attribute ]
  • [ "highest_where_in_distance", filter-expression , number , attribute ]

The number is a divisor of the total tile area. So, for instance, if the number is 256, the features will be spaced such that 256 of them are spaced evenly across the tile. The features with the lowest or highest value of attribute within each cluster are prioritized.

The difference is that lowest_where and highest_where choose any number of features that match the filter-expression, even if these features are right on top of each other, while lowest_where_in_distance and highest_where_in_distance choose any number of features that match the filter-expression while still being acceptably spatially-separated.

Optional fieldDescriptionData type
orderSpecify the order of a sequence of features in the final output tile.String

You can order the sequence of features in the final output tile by a specified attribute. The attribute values must be comparable (all strings or all numbers).

This example orders the features by the sequence attribute:

"tiles": { "order": "sequence" }

Feature union

Optional fieldDescriptionData type
unionJoin features based on whether or not a defined spedified attribute matches.Object

You can union features together if a specified set of their attributes match. The simplest case unions all features that have exactly the same attributes:

"tiles": { "union": [ { } ] }

The union specification object can contain an expression to union only features that match the specified expression as well as having matching attributes:

"where": expression

Expression options:

  • group_by: [attribute, attribute, attribute] - Use group_by to union features that have specified attributes that match, instead of requiring all attributes to match.
  • aggregate: { attribute: type, attribute: type } - Use aggregate to accumulate the specified attributes from the unioned features. Attributes that are not specified in either group_by or aggregate will be removed. Acceptable types of aggregation include sum (to add numbers), product (to multiply numbers), min (to choose the lowest number), max (to choose the highest number), mean (to take the average of numbers), comma (to concatenate with a comma), or concat (to concatenate the feature data without a delimiter).
  • maintain_direction: boolean - Use maintain_direction: false to make more compact unions of LineStrings for which directionality doesn't matter. This is done by reversing some of the LineStrings if that helps to connect them.

For example, you could specify the following to union only features where highway=motorway, and retain the average of their speed_limit attributes:

"tiles": {
  "union":
  [
    {
      "where": [ "==", [ "get", "highway" ], "motorway" ],
      "maintain_direction": true,
      "aggregate": { "speed_limit": "mean" }
    }
  ]
}

This example uses maintain_direction: true (the default) because motorway roads are generally mapped as pairs of roadways whose direction indicates their one-way direction.

Using union with zoom based properties

You can use union on zoom-element properties. If you are using union with a zoom-element property, the union will occur after the feature has been assigned the value based on the zoom level.

More resources

Was this page helpful?