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 or Array,
    "buffer_size": Integer or Array,
    "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.

Note

maxzoom does not determine which zoom level your maps zoom to. Your map will still zoom past the max zoom in your recipe because of overzooming.

The min and max zoom levels you choose directly impact the time it takes the Tilesets API to finish processing your data. Each additional zoom level increases the amount of data in the resulting tileset exponentially.

So, it’s important to first consider the use cases your map is trying to solve for when choosing your min and max zoom levels so that you don't incur any performance costs unnecessarily. The following table will help you decide the appropriate minzoom and maxzoom based on your data precision:

Zoom levelPrecision in feetPrecision in metersUse Case
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 mlow-resolution administrative boundaries (e.g. countries and state boundaries)
1116 ft5 m
128 ft2 m
134 ft1 m
142 ft0.5 mhigh-resolution administrative boundaries (e.g. neighborhoods, census tracts, towns), national park polygon data, national land use & land cover polygon data
151 ft0.25 m
160.5 ft0.125 mbuilding/parcel polygon data, road polygon or line data, points of interest (e.g. hotels, restaurants, venues

Zoom levels greater than 16, which are applicable for use-cases like lane-level navigation maps or high-definition indoor maps, are not possible by default. If you have a use case that requires a zoom level greater than 16, please reach out to us and let us know.

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<Expression>

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 or Array<Expression>

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. An expression can also be used in buffer_size, but must still return a number between 0 and 100.

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

Optional fieldDescriptionData type
extentControls the size of the extent of a Vector Tile.Number or Array<Expression>

extent is a precision control for Vector Tiles and by default is 4096. It is not recommended in most situations you change this value. If you set this value it must be a power of 2 between 256 and 8192. You may also set this number via an expression.

Optional fieldDescriptionData type
layer_sizeSpecifies the size limit in kilobytes 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. There are two ways in which data is limited via the limit field, where and where_in_distance.

The where style limits the total number of features in the tile and its buffer. Only the first number of features that match a filter-expression are kept and the rest are dropped from the tile. The sorting of these is based on attribute which is the key to a feature's attribute and either sorted lowest to highest or highest to lowest.

The format for a where style limit are the following syntaxes:

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

The where_in_distance is the second style of limit and subdivides a tile into number of regions. Within each region only one feature is kept from the features selected by the filter-expression for the limit. The number of regions contained within a single tile is controlled by region_count. This should always be a value equal to 4 to a power in size (e.g. 1, 4, 16, 64, 256..), if the region_count is not equal to one of these numbers it will be rounded to the nearest value of one of these numbers in processing. The feature that is selected in a region is based on either the highest or lowest value based on the attribute field.

The format for a where_in_distance style limit are the following syntaxes:

  • [ "lowest_where_in_distance", filter-expression , region_count , attribute ]
  • [ "highest_where_in_distance", filter-expression , region_count , attribute ]
Optional fieldDescriptionData type
orderSpecify the order of a sequence of features in the final output tile. The features with the lowest values are placed in the tile first.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" }

Renderers, including Mapbox GL, draw or place features in the order they appear in the tile. LineString and Polygon features that are drawn early in the sequence may be covered by overlapping features that are drawn later in the sequence. Conversely, labels that are placed early in the sequence will prevent labels of features later in the sequence from being placed nearby.

You can follow these general guidelines:

  • The most important LineStrings and Polygons should have the highest values for their order attribute, so they are not covered by overlapping features.
  • The most important labels should have the lowest values for their order attribute, so they are placed first.

Read more about how label visibility is affected by the order of features in the Optimize map label placement guide.

If no order attribute is specified, the features will appear in an unpredictable order.

Feature union

Optional fieldDescriptionData type
unionJoin features based on whether or not a defined specified 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?