Why maps in an app break at scale
The mapping module almost never fails all at once — it degrades gradually, and the first symptom usually comes from support: "the customer's address is wrong." The cause is outdated tiles: the map pulls cached fragments, while the base layer on the server has already been updated, and the new address physically lies in a different square.
The user sees a point at a place that no longer exists and loses trust in the app faster than in any other part of it.
The second class of failures is a desync of addresses between the directory and the map.
An organization has moved, a building has been given a new block, a street has been renamed — if search and the geocoder pull from different sources, the app confidently leads the courier to the old entrance.
In dense urban development, this is compounded by growing response time: the more objects in the frame, the longer the results take to build, and navigation starts to "stick" exactly where precision is needed.
A separate story is offline mode. It is either not built into the architecture at all, or implemented in such a way that the app crashes at the very first loss of connection: the base layer is requested, there is no response, there is no handling.
In the field, in a basement, in roaming, this looks like a completely non-working app, even though a single module is to blame.
2GIS SDK removes these classes of failures at the integration level: up-to-date map tiles come from a maintained source, the directory and the geocoder are synchronized, offline mode is built into the storage scheme, and response time stays predictable even in dense urban development. Let's break down how this is handled in a project.
What a correct maps integration delivers
A correct maps integration is not "we put a map on the screen" but predictable behavior of routes and addresses under real operating conditions.
When a route is built in fractions of a second and is not recalculated on every map pan, and geocoding finds an address even with incomplete input, users leave for other apps less often and contact support less often.
We build this in at the architecture level: we calculate routes with a local cache and limits on the number of concurrent requests in mind, and we design address search so that suggestions appear as the user types, not after a button press.
A separate topic is a weak network. In the subway, on a highway, in the basement of a shopping mall, the map must not turn into a white screen.
We cache tiles and the most recently built routes, handle timeouts carefully, and show the user a clear state instead of an endless loading indicator.
This directly affects the share of successful geocodings: if a request fails, the app does not lose the entered address but retries with the saved context.
From a support standpoint, the effect is measurable.
Most map-related inquiries are "it doesn't build a route," "it doesn't find the address," "it shows the wrong point." When these scenarios are covered at the logic level, the flow of such inquiries drops severalfold, and the load on the first line decreases.
We record metrics before and after: route build time, share of successful geocodings, number of failures on a weak network — and we hand them to you as part of the report, not as a promise.
We work on the current SDK branch and maintain compatibility with current versions of mobile platforms so that an app update does not break the map.
If you want to understand what exactly is currently slowing down your routes and losing addresses — describe the task, and we will come back with an estimate and a plan.
Map integration methods: comparing approaches
The choice of integration method determines not only the appearance of the map, but also how the application will survive a weak network, tariff changes, and updates on the data provider's side.
Below are three working options that are realistically chosen between at the start of a project, with their strengths and weaknesses.
| Option | When it fits | Limitations |
|---|---|---|
| Built-in module | The map is a secondary feature: an object's address, a point on the map in an order card | Hard-coded display logic, a limited set of layers, difficult to embed your own interface elements on top of the map |
| Separate layer on top of the map | You need your own markers, clusters, heat zones, non-standard tooltips and gestures | Requires synchronizing the state of the layer and the map during zoom and pan, higher entry threshold for the team |
| Hybrid with its own tile cache | The application works on trips, in warehouses, in regions with unstable coverage | Requires a cache invalidation policy and control over its size, otherwise storage on the device grows uncontrollably |
The built-in module wins on launch speed: integration boils down to initialization and passing coordinates, while the provider handles all rendering.
The price for this is predictability: you get exactly the set of capabilities that the module provides, and any non-standard scenarios have to be worked around.
A layer on top of the map gives full control over the visual part, but requires careful work with coordinate systems and recalculating positions on every scale change.
The hybrid adds a tile cache to this: the map opens instantly even without a network, but a new task appears — managing the cache lifecycle: what to store, when to reset, and how not to hit the device's limits.
In practice, the choice is not binary: teams often start with the built-in module, and as interface requirements grow, they move to a layer on top of the map, leaving the cache as a separate stage. Let's break down how this is handled in each of the cases.
Stages of integrating 2GIS SDK into an application
We start with an audit of the current module: we look at how maps, routes, and geocoding are already structured in the application, which screens depend on them, and where the integration boundaries will run.
At this step, we pin down what we migrate to 2GIS SDK and what stays on the previous layer — otherwise, the setup turns into rewriting half of the application.
- Module audit and defining boundaries. We break down the existing map and map point code, compile a list of dependencies and scenarios affected by the integration. The output is a change map: which screens we modify and which we leave untouched.
- Layer scheme. We design the separation: a data layer for points and routes, a map layer, and an interface layer. This scheme allows changing the map provider later without rewriting the application logic.
- SDK setup. We connect the library, configure access keys, map styles, camera behavior, and marker display rules for the product's needs.
- Integration with business logic. We connect the map with the application data: addresses, filters, favorites, route building. We verify that map events correctly reach the other screens.
- Scenario testing. We run through real user paths — address search, point selection, route, returning to the map after minimizing. We separately examine behavior under weak network conditions and when geolocation access is denied.
- Handover and documentation. We deliver the configured module, the layer scheme, and instructions for updating keys and styles so the team can maintain the integration without us.
Each stage ends with a verifiable result, not a work report: after the audit, the boundaries of changes are clear; after setup, a working map on a test bench; after testing, a closed list of scenarios.
This way, the integration doesn't turn into a long process with an unclear ending, and the handover follows a ready-made scheme.
What the client receives
We hand over not "access to maps," but a working subsystem with transparent logic. Below is what physically ends up with your team after delivery.
- Map layer configurations. A set of profiles for each scenario: which layer is enabled by default, the stacking order, behavior under weak signal and with offline cache. The profiles are moved into a config rather than hardcoded — marketing or product can change the map's appearance without rebuilding the app.
- Routing schemas. The logic of building routes: start and finish points, intermediate stops, travel modes, handling addresses without precise coordinates. The schema describes how the app guides the user and what it shows when rerouting.
- Key access policies. The key is not stored in plaintext in the app. It describes where it is stored, how it is restricted by platform and domain, how it is rotated upon compromise, and who has access to the control panel.
- Backend integration schema. How the app requests data, what is cached on the device, what is pulled from the server, how it behaves when the network is unavailable.
- Documentation. A map of the subsystem: entry points, dependencies, configs, failure scenarios. An engineer who was not involved in development can figure it out from it without calling the author.
- Update procedures. The procedure for updating the subsystem version and related dependencies: what we check before rollout, how we roll back, which metrics we watch after release.
- Acceptance checklist. A list of checks by scenario — from building a route to behavior when the network is lost, with the expected result for each item.
We separately formalize knowledge transfer: a code walkthrough with your team and answers to questions on each artifact. After a month of support, you are left with no "black box" — you have a subsystem that can be developed on your own or with us.
Case study: how route building time was reduced
The client — a delivery service covering 40+ cities — came with a typical pain point: the map in the app opened, but routes were built slowly, and some addresses could not be found at all. The user entered an address, waited for a response, gave up, and left to place an order by phone.
We identified the bottleneck: geocoding was done via a synchronous request to an external service without a cache, and the offline scenario was not provided for at all — when the network was lost, the map screen remained empty.
2GIS was chosen because of the density of its address database for the region and the availability of offline packages that can be shipped together with the app.
From there, the work was driven by metrics rather than guesswork: we recorded baseline values, collected telemetry for every step of route building, and only after that changed the logic.
What was changed
- Geocoding was moved to an asynchronous scheme with a local cache of frequent addresses: re-entering the same address no longer goes to the network.
- Offline packages were connected for the cities of operation — the map and search work without a connection, and data is loaded once it appears.
- Route building was split into stages with timeouts and a fallback: if the external response is delayed, we show an approximate line and refine it later.
- Metrics were added for each stage — map response time, share of successful geocodings, number of failures in offline mode.
Results in numbers
The map response time to a user action was reduced by almost threefold. The share of successful geocodings grew from 82% to 97% — mainly due to the cache and offline packages.
Failures when working without a network are gone: previously they accounted for about 9% of sessions, now we record only a few per day. Placing an order in the app no longer depends on the quality of the connection at the moment the address is entered.
Monitoring was set up separately: if the share of successful geocodings drops or response time grows, the team sees it before users complain.
The metrics were brought into a shared dashboard together with the order funnel — now changes in the map are visible in business indicators, not just in logs.
How does a built-in module differ from a layer on top of the map?
A built-in module is when the map logic and its related data are compiled into the application and run within its process. A layer on top of the map is when the map and part of the data are pulled from an external service, and the application accesses them as needed.
The difference shows up in three places: who manages the map's lifecycle, how quickly the data is available, and how this affects the application size and startup time.
The map's lifecycle in a built-in module is subordinate to the application: initialization, pausing, releasing resources when minimized and exited — all of this is managed by the same mechanisms as the other screens.
A layer on top of the map lives by its own rules: the connection to the external service must be established, the response must be awaited, and it must be properly closed when leaving the screen.
If this is not taken into account, the user sees an empty rectangle where the map should be, or a freeze when returning to the application.
Data access also differs. A built-in module keeps the required set of objects locally, so the map and its related elements appear immediately, without waiting for the network.
A layer on top of the map accesses the service every time it opens: on a weak connection this is a noticeable delay, but the data is always fresh and does not take up space on the device.
Application size and startup speed are the flip side. A built-in module increases the installation package and adds work at startup, because part of the data and logic is already inside.
A layer on top of the map keeps the application compact and starts faster, but shifts the weight to the moment the map is opened.
The choice is not binary: part of the data can be kept locally, and the rest can be pulled over the network.
We look at the usage scenario — how often the map is opened, whether offline operation is needed, how critical startup time is — and on this basis we decide what to compile inside and what to leave as an external layer.
Common technical concerns
Engineering concerns around maps and directories usually boil down to four topics: offline behavior, data freshness, regional coverage, and compatibility with an already-built application. Below are short answers for each, without marketing fluff.
How does the app behave without a network?
Maps and the directory are cached on the device: pre-selected areas and recently viewed objects remain available offline, and search and route building within the cached zone work.
Outside of it, the interface doesn't break — we show a clear "data unavailable" state instead of a blank screen. We limit the cache by size and clear it according to policy so the app doesn't grow on disk.
How fresh is the data in the directory?
Data on organizations, addresses, and opening hours is updated on the provider's side, and the app pulls the current version at launch and on a schedule. We don't keep a copy of the directory ourselves — otherwise it becomes outdated the moment it's deployed.
If you need your own objects (points of sale, delivery zones), they're overlaid as a separate layer and updated independently of the maps.
Are there regional restrictions?
Coverage and detail depend on the country and city: in some places detailed building plans and pedestrian routes are available, in others — only basic layers.
At the start, we verify the list of regions where the business actually operates and check each one: this is cheaper than dealing with blank maps after release. For uncovered zones, we design the behavior in advance — a hint or a redirect to an external source.
Is it compatible with our current stack?
Integration doesn't require rewriting the application: maps are embedded as a separate screen or component, and navigation and search are connected through a public interface. It works on current branches of mobile platforms, including cross-platform builds.
If part of the logic is already written in native code, we connect through a wrapper — without duplicating screens or breaking the existing architecture.
Describe your platform and map usage scenarios — we'll come back with an estimate and an integration plan.
Let's discuss your maps challenge
To come back with an estimate and a work plan rather than generalities, we need to understand your challenge in detail.
Tell us what you already have: a native-platform app or a cross-platform framework, which map scenarios are critical — address search, route building, displaying points of sale, input suggestions. This determines how to integrate 2GIS SDK and what data will need to be prepared.
We will also separately discuss what to clarify regarding integration: whether offline mode is needed, how we behave when the network is lost, whether there are requirements for displaying your own objects on top of the map, and whether analytics on routes and points are planned.
If maps are already connected through another service, we will discuss migration and how to preserve current scenarios without downtime for users.
What to prepare for the start:
- access to the repository and the app's build environment;
- keys and accounts for the mapping service, if they are already set up;
- a description of scenarios: where exactly the user interacts with the map;
- mockups or links to screens where the map should appear;
- a list of your own data — addresses, coordinates, service areas;
- requirements for platforms and minimum supported system versions;
- a contact person on the product side for quick clarifications.
With this set, we estimate the scope of work by stages: connecting and configuring maps, integrating scenarios, working with data, testing on real devices, releasing to app stores. You get a clear plan with a sequence of steps and areas of responsibility, not an abstract range.
Describe your challenge — we will come back with an estimate and a work plan.







