DEV Community

Cover image for How I Built an Offline-First Qibla Compass for a PWA Without an Internet Connection
Yunus Khan
Yunus Khan

Posted on

How I Built an Offline-First Qibla Compass for a PWA Without an Internet Connection

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);
Enter fullscreen mode Exit fullscreen mode

},
(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     │
          └───────┬───────┘
                  │
    ┌─────────────┴─────────────┐
    ↓                           ↓
Enter fullscreen mode Exit fullscreen mode

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:

  1. With Wi-Fi enabled
  2. With mobile data disabled
  3. In airplane mode
  4. Indoors
  5. Outdoors
  6. After rotating the device
  7. 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)