Mugo Web main content.

Making your custom embedded Google Maps more efficient with marker clusters

By: Maxim Strukov | March 15, 2023 | Front-end development

Google Maps is an almost ubiquitous tool and can be incredibly useful to integrate into your site. There’s a lot of versatility in its uses, but depending on how much you’re asking it to do, the results might not be optimal. When you have a huge dataset to display on Google Maps, the performance tends to slow down. When that data is spread across a large geographic area, the issue can be compounded. As you zoom out and more markers try to load, your map can slow to a crawl. What was a useful tool now becomes a point of frustration for visitors to your site. Let’s take a look at the technique that can be used to improve the performance of maps with large datasets.

Using marker clusters

Since this issue becomes more prevalent at different levels of zoom, the answer is also found in how to manage the data at these levels. Using marker clusters is the most obvious thing to do for optimization. As you zoom out, the map will consolidate the markers into these clusters that will display a number indicating how many markers it contains. Zooming in decreases the number of clusters formed, and individual markers are displayed again. By clustering the markers, you are limiting the number of objects that have to be rendered while still showing the data in a visually significant way.

Let’s assume we have the instance of the map - mapPins variable, and the array of markers - mapMarkers variable. So we pass them to the MarkerClusterer instantiation while using our own cluster renderer to specify the parameters like label, icon, title etc.

let markerClusters;

const renderer = {
    render: function ({ count, position }) {
        return new google.maps.Marker({
            label: {text: count.toString(), color: 'white', fontSize: '12px'},
            icon: 'cluster-icon.svg',
            title: 'Zoom in to view resources in this area',
            // adjust zIndex to be above other markers
            zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,

markerClusters = new markerClusterer.MarkerClusterer({
    map: mapPins,
    markers: mapMarkers,
    renderer: renderer

As a result, we’ll see not only the map pins but also some clusters on our map:

a map of the San Francisco Bay Area with clustered markers.

Rendering the markers only within the current bounds

Our map object has a getBounds method on the current instance which allows us to determine the visible bounds of the map based on its position and zoom level. Let’s use it and limit the rendering of the markers when we drag the map or zoom in/out. The tilesloaded and dragend events will help us to achieve that. Those events’ handlers will clear the existing markers for the clusters and add only those which are within updated map bounds.

// Add event to render the pins when the visible tiles have finished loading
mapPins.addListener("tilesloaded", function () {

// Render the pins when the map position has changed
mapPins.addListener("dragend", function () {

function renderVisible() {
        landingMarkers.filter(marker =>
            marker.getVisible() && map.getBounds().contains(marker.getPosition())

In case we don’t use the clusters, the same logic can be implemented for the markers (pins) by rendering those within the map bounds. Then the renderVisible function can look like this:

function renderVisible() {
    for (let i = 0; i < markers.length; i++) {
        if (map.getBounds().contains(markers[i].getPosition())) {
            // render every pin within the bounds
        } else {
            // hide the pins outside of the bounds

With this optimization in place, we should soon see a significant improvement in Google Maps performance. Faster loading pins means your visitors get more information more quickly, which is a win for everyone.