When you're travelling, one of the simplest problems can become surprisingly difficult: finding the Qibla direction without an internet connection.
I wanted to solve this problem while building SabrTime, an Islamic PWA focused on making everyday worship tools available with minimal dependencies, no mandatory login, and an offline-first experience.
The result was an offline-capable Qibla compass that can calculate the direction toward the Kaaba using the device's location and orientation sensors.
Why Offline Qibla Matters
Most web applications assume that the user has an active internet connection.
That isn't always true.
A person may be:
- Travelling by airplane
- In an area with poor network coverage
- Abroad without mobile data
- Inside a building with unreliable connectivity
- Using airplane mode
A Qibla tool shouldn't necessarily stop being useful just because the network disappears.
This led me to an important design principle:
«Calculate what can be calculated locally, and use the network only when it is actually necessary.»
The Basic Architecture
The Qibla calculation itself doesn't require a server.
The basic flow is:
Device Location
↓
Latitude + Longitude
↓
Calculate Bearing to Kaaba
↓
Device Orientation Sensor
↓
Calculate Relative Direction
↓
Display Qibla Compass
The Kaaba's geographic coordinates are fixed, so the application can calculate the bearing locally once it knows the user's latitude and longitude.
Calculating the Bearing to the Kaaba
The first step is determining the initial bearing between the user's location and the Kaaba.
For two points on Earth, we can use the following formula:
const lat1 = userLatitude * Math.PI / 180;
const lat2 = kaabaLatitude * Math.PI / 180;
const deltaLon =
(kaabaLongitude - userLongitude) * Math.PI / 180;
const y = Math.sin(deltaLon) * Math.cos(lat2);
const x =
Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(deltaLon);
let bearing = Math.atan2(y, x);
bearing = bearing * 180 / Math.PI;
bearing = (bearing + 360) % 360;
The resulting value represents the initial compass bearing toward the Kaaba.
This is useful because the calculation happens entirely on the device.
There is no need to send the user's coordinates to a remote API simply to calculate a direction.
Getting the User's Location
The browser's Geolocation API can provide the user's current coordinates.
A simplified implementation looks like this:
navigator.geolocation.getCurrentPosition(
(position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
calculateQibla(latitude, longitude);
},
(error) => {
console.error("Unable to get location:", error);
}
);
Of course, a production application needs to handle permission denial, unavailable location data, low accuracy, and other edge cases.
Using Device Orientation
Knowing the Qibla bearing isn't enough for a compass interface.
We also need to know which direction the device is facing.
Modern browsers can expose device orientation information through sensor APIs, although implementation details and permission requirements can vary between browsers and operating systems.
The basic concept is:
Qibla Bearing
-
Device Heading
=
Relative Qibla Direction
For example, if the Qibla bearing is 280° and the device is currently facing 250°:
280° - 250° = 30°
The UI can then tell the user that the Qibla is approximately 30° to the right.
The Difficult Part: Sensors Are Messy
This sounds straightforward until you actually test it on physical devices.
A compass isn't perfectly stable.
The readings can be affected by:
- Magnetic interference
- Metal objects
- Device hardware
- Sensor noise
- Indoor environments
- Browser differences
- Device calibration
- Rapid device movement
So a good compass interface shouldn't simply trust one sensor reading.
Instead, the application needs to smooth readings and provide clear visual feedback.
Handling Sensor Noise
One simple approach is to maintain a rolling set of readings and smooth the result.
For example:
const readings = [];
function smoothHeading(newHeading) {
readings.push(newHeading);
if (readings.length > 10) {
readings.shift();
}
return readings.reduce((sum, value) => sum + value, 0)
/ readings.length;
}
This is only a basic example. Circular values such as 359° and 1° require special handling because a normal arithmetic average can produce incorrect results.
That's an important lesson when working with compass data:
Angles aren't ordinary numbers.
Building It as a PWA
The next challenge was making the experience work even when connectivity disappears.
A Progressive Web App can cache the application's static resources so that previously loaded functionality remains available offline.
The architecture becomes:
┌───────────────┐
│ PWA UI │
└───────┬───────┘
│
┌─────────────┴─────────────┐
↓ ↓
Local calculations Cached resources
↓ ↓
Qibla bearing Offline interface
↓
Device sensors
↓
Qibla direction
The key idea is that the compass calculation doesn't need a continuous internet connection.
Privacy Was Another Design Goal
Location data is sensitive.
For an Islamic utility like a Qibla compass, I wanted the architecture to minimize unnecessary data transmission.
If the calculation can happen locally, there is little reason to send the user's exact coordinates to a remote server merely to determine a bearing.
This is one reason I prefer a privacy-first, client-side approach wherever practical.
What About Airplane Mode?
This is where the offline-first approach becomes particularly useful.
With network connectivity disabled, a PWA can still provide functionality that doesn't depend on an external server.
The important distinction is:
Offline does not mean “everything works without hardware or permissions.”
The application may still require:
- Previously cached application resources
- Location permission
- Device location capability
- Orientation sensors
- Browser support
The goal is to remove the unnecessary dependency on the internet, not to magically bypass device requirements.
Testing on Real Devices
One of the biggest lessons from this project was that browser-based sensor applications should be tested on actual phones.
A feature can appear perfect in desktop development tools but behave differently on a physical device.
I recommend testing:
- With Wi-Fi enabled
- With mobile data disabled
- In airplane mode
- Indoors
- Outdoors
- After rotating the device
- On multiple browsers where possible
This catches problems that aren't obvious during normal development.
What I Learned
Building this feature taught me that an offline-first web application isn't simply about adding a service worker.
It requires thinking about the entire dependency chain.
For every feature, ask:
«Does this actually need the internet?»
If the answer is no, move the computation to the client whenever practical.
For a Qibla compass, this means location + mathematical calculation + device sensors can do most of the work locally.
The SabrTime Implementation
I built this approach into SabrTime, an Islamic PWA that includes prayer tools, Qibla, Islamic resources, and other everyday worship utilities.
You can explore the project here:
SabrTime: https://sabrtime.in/
I also documented the Qibla approach in more detail in this article:
Airplane Mode Qibla Compass: https://sabrtime.in/blog/airplane-mode-qibla-compass.html
If you're interested in the broader problem of maintaining useful Islamic tools while travelling, I also wrote about "missed prayers and Qaza" (https://sabrtime.in/blog/missed-prayers-qaza-guide.html) and practical guidance around making up missed Salah.
Final Thoughts
The web doesn't always need to depend on the cloud.
For many utility applications, calculations can happen directly on the user's device. This can improve:
- Offline reliability
- Privacy
- Performance
- Resilience
- User experience
The Qibla compass was a good example of this principle.
Instead of asking a server:
«“Where is the Qibla from this location?”»
the phone can calculate the answer itself.
That small architectural decision makes the feature much more useful when the user is travelling — precisely when a Qibla compass may be needed most.
I'm continuing to experiment with offline-first and privacy-focused web development while building SabrTime, and I'll be sharing more of the technical lessons from the project.
Top comments (0)