> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/help/ja/llms.txt)

# Cluster point data with Mapbox Tiling Service

The tutorial will walk you through the process of clustering point data using [Mapbox Tiling Service](https://docs.mapbox.com/mapbox-tiling-service/) (MTS) and the [Tilesets CLI](https://github.com/mapbox/tilesets-cli/) and then styling it at runtime with data-driven styling and [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/). While clustering data at runtime using a geojson source is possible, using **Mapbox Tiling Service** to cluster data is helpful if you your data is programmatically generated, is part of a data pipeline or you want to serve the data as a tileset into multiple map styles.

The data is a line-delimited GeoJSON file of 2400 cafe locations across the U.S. The goal of this tutorial is to cluster the cafe locations into groups and style them based on the number of points in each cluster.

![Finished map with clusters styled](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--cluster-point-data-mts--finished-map.b818044.480.png)

### What you'll learn

-   How to create a tileset source using the [Tilesets CLI](https://github.com/mapbox/tilesets-cli/)
-   How to create a [tileset recipe](https://docs.mapbox.com/mapbox-tiling-service/guides/tileset-recipes/) to cluster point data
-   How to create and publish a tileset using the Tilesets CLI
-   How to load a tileset into a Mapbox GL JS map
-   How to style clustered point data using [expressions](https://docs.mapbox.com/style-spec/reference/expressions/) in Mapbox GL JS

> **Related content (tutorial): [Getting Started with MTS and the Tilesets CLI](https://docs.mapbox.com/help/ja/tutorials/get-started-mts-and-tilesets-cli/)**
> 
> This tutorial follows a similar workflow to the **Getting Started with MTS and the Tilesets CLI** tutorial. If you are new to MTS, it's recommended to start there first.

## Prerequisites

There are a few resources you'll need before getting started:

-   **Create a Mapbox access token.** Create a [new access token](https://console.mapbox.com/account/access-tokens/create) with the scopes `tilesets:write`, `tilesets:read`, and `tilesets:list`. Do not share this token!
-   **Install the [Tilesets CLI](https://github.com/mapbox/tilesets-cli/?tab=readme-ov-file#installation).** The Tilesets CLI is a Python tool that provides source data preparation and validation for interacting with MTS.

> **Note (note): The Tilesets CLI & macOS**
> 
> The [Mapbox Tilesets CLI](https://github.com/mapbox/tilesets-cli/) is one of the ways you can interact with Mapbox Tiling service (the other is [MTS Endpoints](https://docs.mapbox.com/mapbox-tiling-service/guides/#how-to-use-mts)). It is a Python tool that provides source data preparation and validation for interacting with MTS and will be used to interact with MTS in this tutorial.
> 
> If you haven't installed Python on your system or other Python tools, getting the Tilesets CLI installed can seem daunting.
> 
> If you are using macOS and need to use tools like `pip` install the Tilesets CLI, you need to be operating in a virtual environment. This is a common practice for Python development, and it helps to avoid conflicts between different projects and works around the restrictions of macOS's SIP (System Integrity Protection).

## Set your access token as an environment variable

To use Mapbox Tiling Service endpoints via the Tilesets CLI, you need to have a Mapbox access token with the correct scopes: `tilesets:write`, `tilesets:read`, and `tilesets:list`. You can pass your access token to each of the commands used in this tutorial using the `--token` flag. To save time and keep your secret token secure, it's recommended to store your Mapbox access token as an *environment variable*. Set the environment variable with the `export` command in your terminal.

```bash
$ export MAPBOX_ACCESS_TOKEN=YOUR_SECRET_MAPBOX_ACCESS_TOKEN
```

Replace the placeholder `YOUR_SECRET_MAPBOX_ACCESS_TOKEN` with an access token with the correct scopes.

> **Note**
> 
> If you set your access token with the `export` command as shown above, this token will persist only as long as your terminal environment is open. If you close your terminal, you will need to run this command again to set the environment variable.
> 
> For a more permanent solution, you can add the `export` command to your shell's configuration file (e.g., `.bash_profile`, `.bashrc`, or `.zshrc`) which makes it available every time you open a new terminal window.

## Create your tileset source

Now that you have Mapbox's [Tilesets CLI](https://github.com/mapbox/tilesets-cli/) installed, your access token set in your command line environment and the sample data downloaded, the next step is to create a tileset source.

A [tileset source](https://docs.mapbox.com/help/ja/glossary/tileset-source/) is a collection of line-delimited GeoJSON files that is saved on Mapbox.com. A tileset source is referenced by an ID, like `mapbox://tileset-source/username/hello-world`. You can think of a tileset source as a place to store your raw geographic data before turning it into a vector tileset that can be served from MTS. Tileset sources can contain multiple files. You will use a tileset source to create a new tileset `layer` later on in this tutorial.

To create a tileset source, you will use the [Tilesets CLI `upload-source` command](https://github.com/mapbox/tilesets-cli/#upload-source). In this command, you will provide the following information:

-   Your Mapbox username
-   A name for the new tileset source ("cafe-locations-source" in the example command below)
-   A single line-delimited GeoJSON file of 2400 cafe locations across the U.S. [Download line-delimited GeoJSON](https://docs.mapbox.com/help/ja/help/ja/data/cafe-locations.geojson.ld)
-   The path to the source GeoJSON file.

More detail on this command and how it interacts with MTS is available in the [Tilesets CLI's documentation](https://github.com/mapbox/tilesets-cli/blob/master/README.md#upload-source).

Run the following Tilesets CLI command, replacing `YOUR_MAPBOX_USERNAME` with your Mapbox account username.

```bash
$ tilesets upload-source YOUR_MAPBOX_USERNAME cafe-locations-source /path/to/data/cafe-locations.geojson.ld
```

This command creates a connection with MTS and uploads your source to a permanent and secure location on Mapbox's servers.

You will see a message that tells you that the tileset source has been successfully created:

```json
upload progress  [------------------------------------------------------]
{
    "id": "mapbox://tileset-source/YOUR_MAPBOX_USERNAME/cafe-locations-source", 
    "files": 1, 
    "source_size": 921703, 
    "file_size": 921703
}
```

## Cluster data with a tileset Recipe

Now that you have created your tileset source, it's time to define the set of rules to tell MTS how this source's data should be transformed when you upload and publish it. These rules are referred to as [recipes](https://docs.mapbox.com/mapbox-tiling-service/guides/tileset-recipes/).

### Set the `count` feature attribute

First, add a [feature attribute](https://docs.mapbox.com/mapbox-tiling-service/recipe-specification/vector/#feature-attributes) called `count` to the [feature configuration](https://docs.mapbox.com/mapbox-tiling-service/recipe-specification/vector/#feature-configuration) of your MTS recipe. Set the value of this feature attribute to `1`. This tells MTS to give a `count` value of `1` to each feature in the source. MTS will sum each point to create the cluster point count.

Set the `source` value to your tileset source as defined from the previous step. Replace `YOUR_MAPBOX_USERNAME` in the `source` field with your Mapbox account username.

```json
{
  "version": 1,
  "layers": {
    "locations": {
      "minzoom": 0,
      "maxzoom": 12,
      "source": "mapbox://tileset-source/YOUR_MAPBOX_USERNAME/cafe-locations-source",
      "features": {
        "attributes": {
          "set": { "count": 1 }
        }
      }
    }
  }
}
```

### Union points via Clustering

Second, add a [union object](https://docs.mapbox.com/mapbox-tiling-service/recipe-specification/vector/#feature-union) to the [tile configuration](https://docs.mapbox.com/mapbox-tiling-service/recipe-specification/vector/#tile-configuration) of the MTS recipe and set cluster to `true`. Use an empty [group_by](https://docs.mapbox.com/mapbox-tiling-service/recipe-specification/vector/#union-group_by) `("group_by": [])` to union all features (e.g., points to be clustered) regardless of their attributes. Set the [region_count](https://docs.mapbox.com/mapbox-tiling-service/recipe-specification/vector/#limit) to the number of clustered points needed for each tile. The `region_count` must be a power of 4 between 1 and 16,384, so valid values are 1, 4, 16, 64, 256, 1024, 4096, or 16384.

Finally, use an `aggregate` rule to sum the count for each point to create the point count for the cluster.

```json
{
 ...   
    "tiles": {
      "union": [
        {
          "group_by": [],
          "cluster": true,
          "region_count": 64,
          "aggregate": { "count": "sum" }
        }
      ]
    }
}
```

### The final recipe

The final recipe should look like this:

```json
{
  "version": 1,
  "layers": {
    "locations": {
      "minzoom": 0,
      "maxzoom": 12,
      "source": "mapbox://tileset-source/YOUR_MAPBOX_USERNAME/cafe-locations-source",
      "features": {
        "attributes": {
          "set": { "count": 1 }
        }
      },
      "tiles": {
        "union": [
          {
            "group_by": [],
            "cluster": true,
            "region_count": 64,
            "aggregate": { "count": "sum" }
          }
        ]
      }
    }
  }
}
```

## Create your tileset

Now you will create a new tileset using your recipe and the [Tilesets CLI `create` command](https://github.com/mapbox/tilesets-cli/#create).

You will give your tileset a [tileset ID](https://docs.mapbox.com/help/ja/glossary/tileset-id/). This will be the main resource you reference when adding the tileset to your map styles in the future. When you run the command, replace `YOUR_MAPBOX_USERNAME` with your Mapbox account username.

Use the `--recipe` flag to reference the recipe file you created in the last step. This gives MTS a set of rules to follow as it generates the tileset. **Remember** your recipe also contains the reference to your source data which will be processed into vector tiles when the tileset is published.

Use the `--name` flag to create a human-readable name for your tileset.

Create the tileset by running the following command:

```bash
$ tilesets create YOUR_MAPBOX_USERNAME.cafe-locations-clustered --recipe path/to/recipe.json --name "Cafe Locations Clustered"
```

You should see a successful response message:

```json
{
  "message": "Successfully created empty tileset YOUR_MAPBOX_USERNAME.cafe-locations-clustered. Publish your tileset to begin processing your data into tiles."
}
```

If you are signed into Mapbox Studio, you will see this new tileset on your [Tilesets page](https://console.mapbox.com/studio/tilesets/). When you click on the new tileset to open the [Tileset explorer](https://docs.mapbox.com/studio-manual/reference/tilesets/#tileset-explorer), it will appear to be empty since it has not been published.

Now that you have successfully created a tileset, the next step is to process the source data into vector tiles! This happens in the publishing step.

## Publish your tileset

Use the Tilesets CLI [`publish`](https://github.com/mapbox/tilesets-cli/#publish) command to publish your tileset. Run the following command, replacing `YOUR_MAPBOX_USERNAME` with your Mapbox account username.

```bash
$ tilesets publish YOUR_MAPBOX_USERNAME.cafe-locations-clustered
```

Publishing your tileset tells MTS to take the following steps:

-   Read your tileset's recipe.
-   Retrieve the tileset source data you created.
-   Create vector tiles from the data in the tileset source by applying the transformation rules outlined in the recipe.

You'll see a success message, and acknowledgment that your job was received which means that your publish request has been queued and MTS has begun generating your tileset!

```json
{
    "message": "Processing examples.cafe-locations-clustered", 
    "jobId": "cm9lq6nc0000p08jra0bb9uzn"
}

✔ Tileset job received. Visit https://studio.mapbox.com/tilesets/YOUR_MAPBOX_USERNAME.cafe-locations-clustered 
  or run tilesets job YOUR_MAPBOX_USERNAME.cafe-locations-clustered cm9lq6nc0000p08jra0bb9uzn to view the status of your tileset.
```

Generating your tileset may take a few minutes, but you can check the status of your tileset at any time with the Tilesets CLI [`status`](https://github.com/mapbox/tilesets-cli/#status) command]:

```bash
$ tilesets status YOUR_MAPBOX_USERNAME.cafe-locations-clustered
```

To find out more information about the processing jobs, including [any processing warnings](https://docs.mapbox.com/mapbox-tiling-service/overview/warnings/), use the Tilesets CLI [`jobs`](https://github.com/mapbox/tilesets-cli#jobs) command].

Once publishing has completed successfully, you will see the new tileset in your [Tilesets page](https://console.mapbox.com/studio/tilesets/). Click on the new tileset to open the Tileset explorer.

![Screenshot showing Mapbox Studio tilesets page with the newly published tileset](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--cluster-point-data-mts--tileset-preview.649104e.480.png)

Zooming in and out in the tileset explorer will show how the clustered point data is represented at different zoom levels. You can click on a point at any zoom level to see the number of points that are clustered together.

![Screenshot showing count on a specific point in the tileset explorer](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--cluster-point-data-mts--count-data.f130a22.480.png)

## Add your tileset to a Mapbox GL JS map

Now that you have created and published your tileset, you can use that tileset as a data source in a map style and use [data-driven styling](https://docs.mapbox.com/help/ja/glossary/data-driven-styling/) to visualize the clustered point data. You can use [Mapbox Studio](https://console.mapbox.com/studio/) to style the clusters, but in this example you will add data-driven styling at runtime using [expressions](https://docs.mapbox.com/style-spec/reference/expressions/) and [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/).

### Create a new HTML file

Create a new HTML file and add the following code. This snippet will create a full screen map centered over the US with the [Mapbox Dark](https://docs.mapbox.com/api/maps/styles/#classic-mapbox-styles) classic style.

> **Note (legacy): Classic Mapbox styles are no longer maintained**
> 
> This example uses classic Mapbox styles (for example: "streets", "outdoors", "light", "dark", etc). These styles are no longer maintained and may not include the latest features or updates. Developers are encouraged to use the [Mapbox Standard](https://docs.mapbox.com/map-styles/standard/guides/) or Mapbox Standard Satellite]([https://docs.mapbox.com/map-styles/standard/guides/#mapbox-standard-satellite](https://docs.mapbox.com/map-styles/standard/guides/#mapbox-standard-satellite)) styles or to create a custom style using [Mapbox Studio](https://docs.mapbox.com/help/tutorials/create-a-custom-style/).

**Note:** make sure you've passed a public access token from [your account](https://console.mapbox.com) to the `accessToken` option in `new mapboxgl.Map()`.

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cluster data points with MTS - Tutorial</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/{{VERSION_MAPBOXGLJS}}/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/{{VERSION_MAPBOXGLJS}}/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
    <div id="map"></div>

<script>
  // Replace YOUR_MAPBOX_ACCESS_TOKEN with your 
  // access token from https://console.mapbox.com
  // Instantiates a map, sets the style to dark-v11, and sets the initial zoom and center (over the continental US)
  const map = new mapboxgl.Map({
    accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
    container: 'map',
    style: 'mapbox://styles/mapbox/dark-v11',
    zoom: 4,
    center: [-100.10899, 39.15742]
  });

</script>
</body>
</html>
```

Open this file in your browser and you should see the map loaded with the Mapbox Dark style over the continental US.

![Map with dark style and centered over the continental US](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--cluster-point-data-mts--blank-map.7c454d7.480.png)

### Load your tileset

Now that you have a map, you can load your tileset into the map. To do this, add the following code to the `<script>` tag in your HTML file. We use a [map.on('load')](https://docs.mapbox.com/mapbox-gl-js/api/map/#map.event:load) event listener to make sure that the map has finished loading before adding the tileset source. The `url` property of the [addSource](https://docs.mapbox.com/mapbox-gl-js/api/map/#map#addsource) method should be the tileset id from the previous step. Remember to change `YOUR_MAPBOX_USERNAME` to your Mapbox username.

```javascript
  // Add a new source to the map using the tileset ID
  map.on('load', () => {
    map.addSource('clustered-data', {
      type: 'vector',
      // Load the custom tileset as a vector source
      // Formatted as 'mapbox://{username}.{tileset-id}'
      url: 'mapbox://YOUR_MAPBOX_USERNAME.cafe-locations-clustered'
    });
  });
```

Now the tileset is loaded into the map. But you can't see it yet because you haven't added a layer to visualize the data. Do that next.

Inside your `map.on('load')` beneath the `addSource` add a [`map.addLayer`](https://docs.mapbox.com/mapbox-gl-js/api/map/#map#addlayer) method to add a new layer to the map. This layer will use the tileset source you added above and is adding a [circle layer](https://docs.mapbox.com/style-spec/reference/layers/#circle), creating a circle on each point to visualize the point data. The `source-layer` property should be the name of the layer in your tileset recipe. In this case, it is `locations`.

`

```javascript
  map.on('load', () => {
    map.addSource('clustered-data', {
      type: 'vector',
      // Load the custom tileset as a vector source
      // Formatted as 'mapbox://{username}.{tileset-id}'
      url: 'mapbox://YOUR_MAPBOX_USERNAME.cafe-locations-clustered'
    });
    // highlight-start
    map.addLayer({
      id: 'locations',
      type: 'circle',
      source: 'clustered-data',
      'source-layer': 'locations',
      paint: {
        'circle-color': '#51bbd6',
        'circle-radius': 3,
        'circle-opacity': 1
      }
    })
    // highlight-end
  });
```

> **Note (tip): The `source-layer` property**
> 
> The [source-layer](https://docs.mapbox.com/style-spec/reference/layers/#source-layer) property is an optional [Layer](https://docs.mapbox.com/style-spec/reference/layers/#source-layer) property which is required when using `vector` or `raster-array` sources. The tileset source is a vector source, so you need to specify the `source-layer` property. Tilesets can contain multiple layers, and each layer corresponds to a tileset source. The `source-layer` property is used to specify which layer in the tileset source you want to use.
> 
> Details
> 
> **How to find the `source-layer` name**
> 
> You can refer to the [Tileset explorer](https://console.mapbox.com/studio/tilesets/) to find the name of the source layer in your tileset.
> 
> ![Locations layer within the Tileset explorer](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--cluster-point-data-mts--locations-layer.7d1fabe.480.png)
> 
> Or reference your tileset recipe.
> 
> ```json
> {
>  "version": 1,
>  "layers": {
>    // highlight-start
>    "locations": {
>    // highlight-end
>      "minzoom": 0,
>      "maxzoom": 12,
>      "source": "mapbox://tileset-source/YOUR_MAPBOX_USERNAME/cafe-locations-source",
>      ...
>    }
>  }
> }
> ```

Refresh your browser and you should see the circle layers on each point now displayed on the map.

Your browser doesn't support HTML5 video. Open [link to the video](https://docs.mapbox.com/help/ja/help/ja/assets/medias/tutorials--cluster-point-data-mts--circle-layer-map-7aa197defb7d67bcb3fbc87a3b06eaf5.mp4).

Now it's time to style the clustered point data with expressions!

## Style clustered point data

Now that data is displaying on the map, it's time to style the point data into clusters using [expressions](https://docs.mapbox.com/style-spec/reference/expressions/).

Each point in the tileset has a `count` property that determines how many points are in that cluster. You will use this property to style the clusters based on the number of points in each cluster.

### Style the `circle-color` and `circle-radius` properties

In your `locations` layer, add a new property called [`filter`](https://docs.mapbox.com/style-spec/reference/layers/#filter) with a value of `['has', 'count']`. The `filter` property is used to filter the features in the layer based on their properties. In this case, you are filtering the features to only show those that have a `count` property.

Next change the `circle-color` property to use an expression to set the color of the circle based on the `count` property. The expression will check the value of the `count` property and set the color based on the number of points in the cluster.

```javascript
  map.on('load', () => {
    map.addSource('clustered-data', {
      type: 'vector',
      // Load the custom tileset as a vector source
      // Formatted as 'mapbox://{username}.{tileset-id}'
      url: 'mapbox://YOUR_MAPBOX_USERNAME.cafe-locations-clustered'
    });
    // highlight-start
    map.addLayer({
      id: 'locations',
      type: 'circle',
      source: 'clustered-data',
      'source-layer': 'locations',
      // highlight-start
      filter: ['has', 'count'],
        paint: {
        'circle-color': [
          'step',
          ['get', 'count'],
          '#51bbd6',
          10, // If count is 10 or less, color is #51bbd6
          '#f1f075',
          20, // If count is 20 or less, color is #f1f075
          '#f28cb1',
          75, // If count is 75 or less, color is #f28cb1, If count is greater than 75, color is #ac41bf       
          '#ac41bf'
        ],
      // highlight-end
      'circle-radius': 3,
      'circle-opacity': 1
      }
    })
  
  });
```

The expression used in the `circle-color` value above is a [data expression](https://docs.mapbox.com/style-spec/reference/expressions/#data-expressions) as it uses feature data (in this case `count`) to calculate values for the circle color. It uses a [`step`](https://docs.mapbox.com/style-spec/reference/expressions/#step) function to set the color based on the value of the `count` property. You can think of a step function as a series of "if-this-then-that" rules.

```javascript
["step",
    input: number, // retrieve count value with ['get', 'count']
    stop_output_0: OutputType, // this value is returned if input < stop_input_1
    stop_input_1: number,  // First stop #
    stop_output_1: OutputType, // if input >= stop_input_1, color is stop_output_1
    stop_input_n: number, 
    stop_output_n: OutputType, ...
]:OutputType
```

The `step` function takes a list of values and returns a value based on the input value. In this case, if the `count` is 10 or less, the color is `#51bbd6`, if the count is 20 or less, the color is `#f1f075`, if the count is 75 or less, the color is `#f28cb1`, and if the count is greater than 75, the color is `#ac41bf`.

> **Related content (guide): [Expressions](https://docs.mapbox.com/style-spec/reference/expressions/)**
> 
> `Expressions` are a powerful way to style your data based on its properties. You can use them to create complex styles based on the data in your tileset.

Now add another expression to style the `circle-radius` property based on the `count` property and set the `circle-opacity` to `0.8`. Add the following code to the `paint` property of your `locations` `addLayer()`.

```javascript
  map.on('load', () => {
    map.addSource('clustered-data', {
      type: 'vector',
      // Load the custom tileset as a vector source
      // Formatted as 'mapbox://{username}.{tileset-id}'
      url: 'mapbox://YOUR_MAPBOX_USERNAME.cafe-locations-clustered'
    });
    map.addLayer({
      id: 'locations',
      type: 'circle',
      source: 'clustered-data',
      'source-layer': 'locations',
      filter: ['has', 'count'],
      paint: {
      'circle-color': [
        'step',
        ['get', 'count'],
        '#51bbd6',
        10, // If count is 10 or less, color is #51bbd6
        '#f1f075',
        20, // If count is 20 or less, color is #f1f075
        '#f28cb1',
        75, // If count is 75 or less, color is #f28cb1, If count is greater than 75, color is #ac41bf       
        '#ac41bf'
      ],
      // highlight-start
      'circle-opacity': 0.8,
      'circle-radius': [
        'step', 
        ['get', 'count'], 
        5, 
        2, // If count is 2 or less, radius is 5
        12, 
        10, // If count is 10 or less, radius is 12
        17, 
        20, // If count is 20 or less, radius is 17
        25, 
        50, // If count is 50 or less, radius is 25
        32, 
        100, // If count is 100 or less, radius is 32 otherwise radius is 40
        40
      ]
      // highlight-end
    }
  })
});
```

Now refresh your browser and you should see the clustered point data styled with the circle color and radius.

![Map with styled clusters](https://docs.mapbox.com/help/ja/assets/ideal-img/tutorials--cluster-point-data-mts--clusters-styled.df0370c.480.png)

Next you will render the `count` value on the map using a text layer.

## Add a `count` text layer

Now that you have styled the clustered point data, add a [`symbol`](https://docs.mapbox.com/style-spec/reference/layers/#symbol) layer to show the `count` value of each point in the circle.

Inside your `map.on('load')` and beneath your `locations` `addLayer()` add a new `addLayer()` adding a `symbol` layer.

```javascript
map.on('load', () => {
    map.addSource('clustered-data', {
      type: 'vector',
      // Load the custom tileset as a vector source
      // Formatted as 'mapbox://{username}.{tileset-id}'
      url: 'mapbox://examples.cafe-locations-clustered'
    });

    map.addLayer({
      id: 'locations',
      type: 'circle',
      source: 'clustered-data',
      {...}
    });

    // highlight-start
    map.addLayer({
      id: 'cluster-count',
      type: 'symbol',
      source: 'clustered-data',
      'source-layer': 'locations',
      filter: ['>', ['get', 'count'], 1], // Only show count if greater than 1
      paint: {
        'text-color': '#ffffff', 
        'icon-color-contrast': 1
      },
      layout: {
        'text-field': ['get', 'count'],
        'text-font': ["Open Sans Regular","Arial Unicode MS Regular"],
        'text-size': 12
      }
    });
    // highlight-end
  });
```

In this new `addLayer()`the same `source` and `source-layer` properties as the `locations` layer are used to reference the tileset source and the desired layer. The `filter` property and value make sure to only show the `count` value if it is greater than 1. The `paint` property sets the color of the text to white and the `icon-color-contrast` to 1. The `layout` property sets the `text-field` to the `count` value, as well as setting the font and text size.

Refresh your browser and you should see the `count` value displayed on the map.

## Finished product

🎉 **Congratulations!** You have successfully clustered point data using Mapbox Tiling Service and styled it at runtime with using expressions and Mapbox GL JS.

The finished product and full code snippet are below.

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cluster data points with MTS - Tutorial</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/{{VERSION_MAPBOXGLJS}}/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/{{VERSION_MAPBOXGLJS}}/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
    <div id="map"></div>

<script>
  const map = new mapboxgl.Map({
    accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
    container: 'map',
    style: 'mapbox://styles/mapbox/dark-v11',
    zoom: 4,
    center: [-100.10899, 39.15742]
  });

  map.on('load', () => {
    map.addSource('clustered-data', {
      type: 'vector',
      // Load the custom tileset as a vector source
      // Formatted as 'mapbox://{username}.{tileset-id}'
      url: 'mapbox://examples.cafe-locations-clustered'
    });

    map.addLayer({
      id: 'locations',
      type: 'circle',
      source: 'clustered-data',
      'source-layer': 'locations',
      filter: ['has', 'count'],
      paint: {
      'circle-color': [
        'step',
        ['get', 'count'],
        '#51bbd6',
        10, // If count is 10 or less, color is #51bbd6
        '#f1f075',
        20, // If count is 20 or less, color is #f1f075
        '#f28cb1',
        75, // If count is 75 or less, color is #f28cb1, If count is greater than 75, color is #ac41bf       
        '#ac41bf'
      ],
      'circle-opacity': 0.8,
      'circle-radius': [
        'step', 
        ['get', 'count'], 
        5, 
        2, // If count is 2 or less, radius is 5
        12, 
        10, // If count is 10 or less, radius is 12
        17, 
        20, // If count is 20 or less, radius is 17
        25, 
        50, // If count is 50 or less, radius is 25
        32, 
        100, // If count is 100 or less, radius is 32 otherwise radius is 40
        40
      ]
    }
  });

    map.addLayer({
      id: 'cluster-count',
      type: 'symbol',
      source: 'clustered-data',
      'source-layer': 'locations',
      filter: ['>', ['get', 'count'], 1], // Only show count if greater than 1
      paint: {
        'text-color': '#ffffff',
        'icon-color-contrast': 1
      },
      layout: {
        'text-field': ['get', 'count'],
        'text-font': ["Open Sans Regular","Arial Unicode MS Regular"],
        'text-size': 12
      }
    });


    // Uncomment this block to inspect the geojson objects of each clustered point
    // map.on('click', 'locations', (e) => {
    //   const selectedFeature = map.queryRenderedFeatures(e.point, {
    //       layers: ['locations']
    //   });
    //   console.log(JSON.stringify(selectedFeature, null, 2));
    // });

  });
</script>
</body>
</html>
```

## Next steps

### What we covered

-   How to create a tileset source using the [Tilesets CLI](https://github.com/mapbox/tilesets-cli/)
-   How to create a [tileset recipe](https://docs.mapbox.com/mapbox-tiling-service/guides/tileset-recipes/) to cluster point data
-   How to create and publish a tileset using the Tilesets CLI
-   How to load a tileset into a Mapbox GL JS map
-   How to style clustered point data using [expressions](https://docs.mapbox.com/style-spec/reference/expressions/) in Mapbox GL JS

### Updating your tileset

If you want to update your tileset after it's published, you can do so by either:

**A - Updating your tileset source**: Your source data can be updated or replaced using the [Tilesets CLI `upload-source`](https://github.com/mapbox/tilesets-cli/?tab=readme-ov-file#upload-source) command with the `--replace` flag.

**B - Updating your tileset recipe**: You can update your tileset recipe, changing how the data is displayed across the tileset using the [Tilesets CLI `update-recipe`](https://github.com/mapbox/tilesets-cli/?tab=readme-ov-file#update-recipe) command

After you have updated your tileset source or recipe, you will need to republish your tileset using the [Tilesets CLI `publish`](https://github.com/mapbox/tilesets-cli/?tab=readme-ov-file#update-recipe) command.

### Learn More

-   Learn more about using expressions in the tutorial [Get started with Mapbox GL JS expressions](https://docs.mapbox.com/help/ja/tutorials/mapbox-gl-js-expressions/)
-   Spend time browsing the Expression reference in the [Mapbox Style Specification](https://docs.mapbox.com/style-spec/reference/expressions/)
-   Learn more about [Mapbox Tiling Service](https://docs.mapbox.com/mapbox-tiling-service/examples/) by browsing the [MTS examples](https://docs.mapbox.com/mapbox-tiling-service/examples/)