Marker clustering: where the map breaks and what the customer loses
A map with a dozen markers works instantly, and at this stage it seems the task is solved.
But once the database grows to hundreds and thousands of objects, the application starts to noticeably lag: rendering drops, gestures stutter, and on weak devices the map in the app freezes on every movement.
The reason is not a "weak phone," but the fact that each object is rendered as a separate element. The more points on the map, the more expensive each frame becomes.
Then a second, less obvious failure appears — loss of visibility. When markers stand close together, they overlap each other: the user sees one icon where in reality there are twenty. The object physically exists in the data, but it is not on the screen.
For the customer's scenario this is a direct loss — the client does not find the needed point and leaves, even though it was nearby.
The third failure is opposite in symptom, but hits the result just as hard — a false sense of emptiness. If, when zooming out, the map does not rebuild the data, some objects simply disappear from the output, and the user concludes that there are no offers in their area. In reality they exist, but the interface did not show them.
All three failures grow from one root: the map tries to show everything at once, instead of showing what is needed at the current scale. Marker clustering solves exactly this — it groups nearby objects into a single node and reveals them as you zoom in.
Map performance stops depending on the total number of points, and the display of objects on the map remains honest at any zoom.
Let's break down how this is handled in practice and which grouping parameters determine whether the map will be responsive.
What marker clustering delivers: the effect in numbers and modes
Marker clustering is not a "pretty map" but a way to keep map rendering speed within predictable bounds as the number of objects grows.
Without it, every point on the map is a separate interface element: with several thousand markers, scrolling and zooming start to lag behind the gesture, and on weak devices the map stutters as soon as it opens.
Grouping points on the map turns this dependency into a nearly constant one: the number of rendered objects is determined not by the amount of data but by the current zoom level.
What changes in numbers
- Frame render time. With tens of thousands of markers and no grouping, a frame takes noticeably longer to assemble; after implementation, it stays consistently within one or two frames at any zoom level.
- Time to interactive map. The screen stops waiting for all points to fully load: clusters appear first, and detail is pulled in as you zoom in.
- The cost of an idle map. While the user waits for a response, the scenario is not being completed — the order loses conversion. A responsive map brings those actions back into the funnel.
- Memory consumption. Instead of thousands of live objects on screen, there are just a few clusters, which reduces the risk of the app crashing during a long session.
Map display modes
The mode is chosen for the scenario, not "by default": in some cases density matters, in others the precision of an individual marker. Below are working alternatives that are genuinely chosen between.
| Option | When it fits | Limitations |
|---|---|---|
| Grid-based grouping | Dense homogeneous data, a simple scenario | Clusters "jump" when zoom changes |
| Hierarchical grouping | Heterogeneous objects, level-by-level detail needed | Harder to configure thresholds |
| Grouping by regions | Geography known in advance, stable zones | Works poorly on fuzzy boundaries |
| No grouping | Fewer than a hundred markers, high precision | Degrades as data grows |
Our engineers configure thresholds, overlap behavior, and the smoothness of transitions between levels — Supercluster and similar libraries provide the foundation, but the parameters for a specific dataset are selected manually.
Why it pays off
The effect is not in the grouping itself but in the fact that the map stops being the bottleneck of the scenario. The user reaches the goal without pauses, and the product withstands growth in the object base without rewriting the screen.
How we implement clustering: stages of engineering work
Implementing clustering starts not with code, but with an audit of the application map: we look at how many objects actually load onto the screen, how the data source is structured, and where responsiveness is lost during zoom and panning.
At this stage we record the current metrics — area render time, number of concurrent requests, behavior on a weak network — so that after the work there is something to compare against.
- Audit of the application map. We analyze the current implementation: how markers are formed, where the coordinates come from, whether there are duplicates and "dead" points. We determine the thresholds beyond which the map starts to lag, and the target values for the number of objects on screen.
- Designing the grouping scheme. We choose a clustering model to match the nature of the data: static points, dynamic objects, or a mixed set. We agree on behavior at different scales — where a marker remains individual and where it merges into a group.
- Configuring marker grouping. We implement grid-based partitioning with recalculation when the scale changes, configure the merge radius and display priorities. We separately work through cluster labels and the smoothness of rebuilding so that the map does not "jump" during zoom.
- Optimizing data loading. We switch loading to the viewport: the application requests only those objects that fall on the screen and caches the ones already received. This removes unnecessary load from the server side and speeds up the map's response.
- Testing the map. We run scenarios on different data volumes, a weak channel, and old devices: zoom, panning, transition from a cluster to individual points. We compare behavior against the agreed thresholds and fix discrepancies.
- Handing over documentation. We deliver to the customer the grouping settings, the data source scheme, a description of the thresholds and behavior at each scale. We record how to change parameters without developer involvement.
Each stage ends with an artifact that can be verified: an audit report, an agreed scheme, a working prototype on real data, test results.
This order eliminates the situation where clustering has been implemented but the map still lags in dense areas — discrepancies are visible at the testing stage, not after release.
How does client-side clustering differ from server-side grouping?
Client-side clustering computes groups directly on the device: the application keeps all points in memory, recalculates the grid on every pan or zoom, and draws a single marker per cell.
Server-side grouping moves this work to the backend — the application sends the visible area and zoom level, and in return receives ready-made clusters with coordinates and a count.
The difference shows up not in the picture, but in where the resource is spent and what happens when the network degrades.
The client-side approach wins on small and medium datasets: up to several thousand points, grid recalculation fits within a frame, the map stays responsive without a single request, and on a weak connection the behavior doesn't change at all — the data is already on the device.
The limit is reached on volume: tens of thousands of markers eat up memory, recalculation on every movement starts dropping the frame rate, and cold start stretches out while the entire dataset loads.
On top of that, the data sits on the client in full — this is a question not only of weight, but also of what actually goes to the device.
Server-side grouping takes the load off the application: the device stores only what has made it onto the screen, the sample size is limited to the visible area, and heavy datasets live on the backend. The price is dependence on the channel.
Every map pan turns into a request, and on a weak connection the user sees an empty map or a loading indicator instead of markers.
This is treated with caching of recent responses by tiles, batching nearby requests, and rendering the previous state until a new response arrives — but that is already a separate layer of work on top of the map architecture.
In practice, the choice is rarely binary. A hybrid is often used: the base cluster layer comes from the server, while detail within dense zones is computed on the client from the already loaded dataset.
The boundary between the approaches runs along data volume, requirements for point freshness, and how critical it is to work in the subway, on the highway, or in a basement — that is, where the connection drops.
Case study: how marker clustering sped up the map in a delivery app
In the delivery app, the map displayed all active orders and couriers at once — under heavy load in a district, thousands of markers were rendered on screen.
Measurements on real devices showed a frame render time of about 1.2 seconds when panning and up to 2.5 seconds when zooming: the interface stuttered, and some objects didn't manage to render before the next gesture.
A separate problem was lost objects: when dragging the map quickly, markers that entered the viewport at the moment of redraw simply didn't appear, and the dispatcher saw an incomplete picture of the district.
We started with profiling: we captured rendering timelines on a mid-range and a low-end device, and counted how many markers actually fall within the visible area in typical dispatcher workflows.
It turned out that only 20–40 objects physically fit on screen, while all of them were being sent to the render layer — that difference was the source of the slowdown.
What we changed
We introduced marker clustering with grid recalculation for the current scale: at far zoom, nearby points collapse into a single marker with a count, while at close zoom they expand back into individual objects.
Recalculation happens incrementally when the viewport changes, rather than on every frame, so panning no longer triggers a full rebuild of the layer.
We added a cluster expansion threshold and display priority: problem orders and active couriers stay visible longer than the rest. This eliminated the scenario where an important marker was hidden inside a group.
Metrics before and after
| Metric | Before | After |
|---|---|---|
| Frame render time when panning | ~1.2 s | 40–60 ms |
| Render time when zooming | up to 2.5 s | 60–90 ms |
| Share of lost objects during fast panning | up to 15% | less than 1% |
| Number of objects in the render layer | all active | 20–40 visible |
Smoothness returned on devices where the map had previously been unusable for work. Dispatchers no longer had to wait for a response when dragging, and an incomplete picture of the district no longer led to erroneous assignments.
We built the clustering and grid recalculation logic on the capabilities of the MapLibre mapping layer — it provides a controllable data source and doesn't add extra weight to the app bundle.
Doubts before implementation: compatibility, migration, rollback, access
Marker clustering rarely breaks the application itself — it conflicts with an already working map: third-party layers, custom pins, filter logic, and key permissions.
That is why before starting we pin down the integration points: which map is currently used, how tiles are served, and who owns the access key.
What if the map is already integrated and cannot be changed? Clustering is placed on top of the current layer — existing markers, popups, and handlers stay in place; only the rendering method changes when points are densely clustered.
No map migration is required: the connection is made to the same map that is already in the application.
What if you need to revert to the previous behavior? Rolling back changes is done with a toggle in the configuration: clustering is enabled and disabled without rebuilding the release, and the previous marker display logic is preserved as a fallback mode.
How are access to the map and keys handled?
Keys and tokens remain in your mapping provider account — we do not transfer them to our side.
Access is granted for the duration of the work and revoked after handover, and the key configuration is described in the map documentation: where it is stored, how it is rotated, and what domain and application restrictions are set.
Upon handover, the client receives:
- clustering configuration: merge thresholds, behavior at different zoom levels, cluster styles;
- map compatibility scheme — which layers and handlers are affected, which remain untouched;
- map migration regulations and the procedure for switching between display modes;
- rollback procedure with step-by-step verification after reverting;
- map access matrix: who owns the keys, who is granted access, how it is revoked;
- map documentation describing the configuration, limitations, and extension points.
Describe your task — we will come back with an estimate and a work plan for your application.







