Dynamic Geo-Fencing: Building Location-Aware IoT Applications with MQTT and HiveMQ
How can you connect mobile IoT devices—like smartphones, cars, or robots—with local, geo-specific information and real-time messages? The key is to build a system that understands the physical location of each device and can deliver relevant data based on where it is and what's around it.
This article explores how to leverage HiveMQ’s powerful extension system and the MQTT protocol to build a highly efficient and decoupled geo-fencing application. The architecture is straightforward: mobile IoT clients connect to a HiveMQ broker and periodically send their location information. In response, a custom extension on the broker dynamically manages the client’s topic subscriptions, ensuring it's always subscribed to relevant "geo-cells" that represent its current location.
These geo-cell topics represent specific geo-fenced areas, allowing other devices or backend services to interact with clients in that specific location. This approach creates a location-aware publish/subscribe system where subscriptions dynamically change based on geography—a far more efficient model for location-based messaging than traditional static subscriptions.
This architecture unlocks a wide range of sophisticated, geo-local use cases, such as:
Smart Factories: Autonomous service robots automatically subscribe to topics for the specific areas, zones, or buildings they are currently in. Using retained messages, they can immediately receive the latest status for the joined area. And by facilitating shared subscriptions, tasks can be distributed to all available workers within a defined zone only.
Smart Cities: Cars can dynamically subscribe to topics for specific streets or intersections to receive real-time traffic updates.
Logistics and Delivery: Delivery drivers or drones can receive real-time offers from local customers as they enter a specific service area.
Technical Implementation of Dynamic Geo-Fencing Using MQTT
While using MQTT to send and track device locations is a well-established practice, there is no official standard for how to encode and send locations or map locations to topics. Our solution introduces a clear pattern for this.
For this example, we will use the GeoJSON format to define our spatial data and map these geographic areas to MQTT topics. The core concept is to determine if a client's location (a point) is inside a predefined area (a polygon). However, this mechanism can easily be extended to other mappings, such as proximity to a specific point of interest. First, we define our geo-fenced areas in a json file that will be loaded by the extension. In GeoJSON, these areas are called Feature
objects. We add a custom mqtt_topic
property to each feature to link the geographic polygon directly to an MQTT topic.
Here is an example geojson file defining two polygonal areas, each mapped to a unique topic:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "HiveMQ Office Building",
"mqtt_topic": "geo/hivemq-office-building"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[12.153229, 48.538857],
[12.153059, 48.538798],
[12.153188, 48.538733],
[12.153615, 48.538724],
[12.153611, 48.538862],
[12.153229, 48.538857]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "HiveMQ Office Surroundings",
"mqtt_topic": "geo/hivemq-office-surroundings"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[12.156147, 48.540570],
[12.151775, 48.538891],
[12.148174, 48.535375],
[12.154694, 48.533138],
[12.158976, 48.538622],
[12.156147, 48.540570]
]
]
}
}
]
}
Architecting the Dynamic Geo Subscription Extension
Now, let's explore how to implement this logic with the Dynamic Geo Subscription Extension using the HiveMQ Extension SDK. We need to solve three main problems:
How does the client report its geolocation?
How do we map the client's location to the predefined cells?
How do we dynamically manage the client's subscriptions?
1. Reporting Client Locations
Since there's no official standard for reporting locations, we'll define a simple JSON format. A client connects to the HiveMQ broker and, at regular intervals, publishes a message with its coordinates to the dedicated location
topic. For reliability, these messages should be sent with QoS 1.
For example, a smartphone entering the HiveMQ HQ building would simply send a message {"lat": 48.538780, "lng": 12.153390 }
to the location
topic. The result is the client being subscribed to the geo/hivemq-office-surroundings
as well as the geo/hivemq-office-building
topics.
On the broker, the extension uses a PublishInboundInterceptor
to act on these incoming messages. The interceptor's logic is as follows:
It checks if the message was published to our specific
location
topic.It parses the client's geo-location from the message payload.
Crucially, it calls
output.preventPublishDelivery()
to stop the broker from sending this message to any other subscribers. The message's sole purpose is to update the client's location within our extension.Finally, it triggers the function to update the client's subscriptions based on the new location.
@Override
public void onInboundPublish(
final @NotNull PublishInboundInput input,
final @NotNull PublishInboundOutput output) {
// Only act on messages sent to the LOCATION_TOPIC
if (!input.getPublishPacket().getTopic().equals("location")) {
return;
}
// Prevent message from being delivered to any subscribers
output.preventPublishDelivery();
// Parse the incoming message
LocationUpdate locationUpdate = parseLocationFromPayload(input.getPublishPacket().getPayload());
// Update subscriptions based on new location
updateClientSubscriptions(clientId, locationUpdate);
}
2. Mapping Locations to Topics
When the extension starts, it loads the geographic data. In our example, it parses the static geojson file. For more dynamic environments, this could be extended to query data from an external API or a spatial database like PostGIS. For this prototype, we use the popular JTS (Java Topology Suite) and Jackson libraries for efficient processing and querying of the spatial data. The location to cell lookups must be very efficient and scale with the number of clients and cells to map. Libraries like JTS or PostGIS databases are optimized to support these kinds of queries.
3. Dynamically Managing Subscriptions
The updateClientSubscriptions()
function is where the core logic resides. Its job is to ensure the client is subscribed to the correct topics for its current location. This is done by querying the spatial data to find all polygons (cells) that contain the client's location, looking up the client's existing subscriptions, and then adding or removing subscriptions as needed to synchronize the client's state.
The HiveMQ Extension SDK makes this simple by providing access to the SubscriptionStore
.
import com.hivemq.extension.sdk.api.services.Services;
import com.hivemq.extension.sdk.api.services.builder.Builders;
import com.hivemq.extension.sdk.api.services.subscription.TopicSubscription;
private void updateClientSubscriptions(
final @NotNull String clientId,
final @NotNull LocationUpdate locationUpdate) {
getTopics(locationUpdate);
...
Services.subscriptionStore().getSubscriptions(clientId)
Services.subscriptionStore().addSubscriptions(clientId, ...)
Services.subscriptionStore().removeSubscriptions(clientId, ...)
}
From Possibility to Production
The Dynamic Geo Subscription Extension is a powerful demonstration of how HiveMQ's extension system can be used to build highly efficient, real-time, location-aware applications. By dynamically managing subscriptions based on real-world geography, you can unlock sophisticated use cases in smart cities, logistics, and manufacturing.
While this article uses a GeoJSON file for mapping, the architecture is designed for flexibility. Your application might need to integrate with a specialized GIS database, connect to a proprietary fleet management API, or meet other unique enterprise requirements.
This is where the power of a truly extensible platform shines. If you're inspired to build your own custom location-aware services, our team is here to help. We can work with you to design and implement bespoke HiveMQ extensions that solve your specific challenges and accelerate your time to market.
Contact us today to explore how we can help you build your next-generation IoT solution.

Dr. Matthias Grawinkel
Matthias Grawinkel is the Principal Architect for the HiveMQ Cloud team, where he leads the platform's technical design. With over 20 years of experience in software engineering, he is an expert in building and operating cloud-native systems. His background includes everything from real-time operating systems for embedded IoT nodes and high-performance distributed storage for datacenters to the cloud infrastructure for data-intensive AI applications in finance.