Self-hosted service
tess1o/geopulse avatar
tess1o/geopulse

GeoPulse: a self-hosted Google Timeline alternative built on Quarkus and PostGIS

A self-hosted, privacy-first location timeline platform: an open-source alternative to Google Timeline with automatic trip detection, Immich integration, and rich analytics.

1,420 stars62 forksJavaNOASSERTION

At a glance

What is it?
GeoPulse turns raw GPS points from OwnTracks, Overland, GPSLogger and similar apps into a searchable timeline of stays and trips on your own hardware. It is a good fit for homelab users who already run Immich and want their location history to stay local.
Who is it for?
Adopt GeoPulse if you already run a homelab or NAS with Docker, you have a GPS app such as OwnTracks or Overland feeding it, and you want location history on your own disk next to an Immich library. Skip it if you need a hosted service with zero maintenance, or if you cannot live with the Business Source License 1.1 that the repository badge shows.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What GeoPulse replaces, and for whom

Google Timeline answers a simple question: where was I on a given day. GeoPulse answers the same question without sending your coordinates to a third party. The README describes it as "The open-source, privacy-first Google Timeline alternative", and the repository topics confirm the shape of the project: self-hosted, privacy, timeline, PostGIS, Quarkus.

The target user is someone who already collects their own location data. The README lists OwnTracks (HTTP and MQTT), Overland, GPSLogger, Home Assistant, Traccar, Dawarich and Colota as supported sources. If you are not already running one of those apps on your phone, GeoPulse has nothing to ingest, and the timeline stays empty. That is the first gate.

The second gate is infrastructure. GeoPulse is a multi-container deployment: the compose file starts a key generation job, a PostgreSQL database with PostGIS, a backend and a frontend. It is not a single binary you drop on a laptop and forget. The README claims a lightweight runtime, typically under 100MB RAM and under 1% CPU in regular usage, and the compose file caps the backend container at 512m with a 128m reservation. Those are the project's own numbers, not measurements taken here.

From GPS pings to stays and trips: the processing pipeline

The core mechanism the README describes is detection. Raw GPS points arrive from a tracking app, and GeoPulse converts them into three kinds of entity: stays, trips and data gaps. A stay is a period where you did not move meaningfully; a trip is movement between two stays; a gap is a stretch where no points arrived, which the system records rather than silently interpolating.

Detection sensitivity and travel mode classification are configurable, per the README's feature list. That matters because the thresholds that work for a car commute will produce nonsense for cycling or rail travel. The project exposes the knobs rather than hiding a single heuristic.

Map matching is the most interesting design decision. The README states it is "Valhalla-backed route refinement" that "makes noisy trip paths follow roads and paths while raw GPS remains authoritative". In other words, the snapped geometry is a display layer, and the original points are still the record of truth. That is the right call for a system of record, but it also means you are running or reaching a Valhalla instance in addition to the core stack. The README does not spell out the resource cost of that on the same page.

Storage is PostgreSQL with PostGIS, which is what makes spatial queries over a multi-year history practical. The compose file wires the backend to the database through GEOPULSE_POSTGRES_URL, built from GEOPULSE_POSTGRES_HOST, GEOPULSE_POSTGRES_PORT and GEOPULSE_POSTGRES_DB.

Installing GeoPulse with Docker Compose

The README gives a four-command quick start. It fetches the example environment file and the compose file from the main branch, then starts the stack.

bash
mkdir geopulse && cd geopulse
curl -L -o .env https://raw.githubusercontent.com/tess1o/GeoPulse/main/.env.example
curl -L -o docker-compose.yml https://raw.githubusercontent.com/tess1o/GeoPulse/main/docker-compose.yml
docker compose up -d

The README says the UI is then reachable at http://localhost:5555, and adds a warning that production deployments should review the .env for security-related settings first. Take that warning literally: the compose file generates JWT signing keys and an AI encryption key into a local ./keys directory on first run, and those files are mounted into the backend container.

The .env.example pins GEOPULSE_VERSION, which selects the image tag. The compose file references tess1o/geopulse-backend:${GEOPULSE_VERSION}-native, with commented alternatives for ghcr.io and for a -native-compat build aimed at old CPUs (x86-64-v2) and Raspberry Pi 3/4. Pick the compatible image if your hardware predates the native build's baseline; the compose file does not auto-detect this for you.

Two settings in .env.example deserve attention before you expose anything. GEOPULSE_PUBLIC_BASE_URL is described as optional but recommended for OIDC callback and link generation. GEOPULSE_CORS_ENABLED defaults to false because the standard deployment puts nginx in front and serves everything same-origin. The file explicitly says the cookie domain should be left empty for "99% of deployments" and only set when you run without the nginx proxy on separate subdomains.

If you want MQTT for OwnTracks, Kubernetes, Unraid, Proxmox LXC or bare metal, the README points to separate deployment guides rather than the quick start. The repository confirms those paths exist: charts/, helm/, docker-compose.unraid.yml and docker-compose-complete.yml are all present at the top level.

Where GeoPulse is the wrong tool

The licence is the first hard constraint. The README badge reads BSL 1.1, and the repository's licence field is NOASSERTION, which means automated tooling could not classify it. Business Source License 1.1 is source-available, not OSI open source, and it typically carries terms that restrict production or commercial use until a change date. The README does not restate those terms. Anyone evaluating GeoPulse for a company, a client project or a paid service needs to read the LICENSE file directly rather than trusting the badge. Nothing here is legal advice.

The second constraint is operational. This is a Postgres-backed multi-container stack with a reverse proxy and, optionally, a Valhalla service for map matching. There is no managed hosting mentioned in the README. If you do not want to run a database, handle backups and watch disk growth, GeoPulse is the wrong choice regardless of how good the timeline looks.

The third is data gravity. GeoPulse is a destination, not a source. It ingests from your tracking app. If your phone stops reporting, gaps appear, and the README treats gaps as a first-class concept rather than papering over them. That is honest design, but it means the quality of your timeline is bounded by the reliability of whatever feeds it.

Finally, the AI features require you to bring your own OpenAI-compatible key. The README says so plainly. If the idea of routing location-derived queries to an external model provider conflicts with your reason for self-hosting, leave the AI chat disabled; the timeline itself does not depend on it.

GeoPulse compared with Dawarich

Dawarich appears twice in the project's own material. The README lists it as a supported data source, and it is the only direct alternative named in the repository's related searches. The two projects overlap heavily: both are self-hosted location history platforms, both ingest from OwnTracks-style trackers, and both target people leaving Google Timeline behind.

The difference in approach is visible in the stack. GeoPulse is a Java and Quarkus backend over PostgreSQL with PostGIS, shipped as native images, with a Vue 3 frontend. That is a compiled, JVM-ecosystem bet, and the Makefile builds both -jvm and -native variants across linux/amd64 and linux/arm64/v8. Dawarich is a Ruby on Rails application, which is a different operational profile: easier to read and patch for many self-hosters, heavier per-request in the common case.

The more useful distinction is integration surface. GeoPulse's README leans on Immich for photos, Memos for notes, Panoramax for street-level imagery and Weather for conditions, all layered onto the timeline. It also exposes an MCP server described as read-only and API-token-authenticated, so AI clients can query the timeline and permitted friend data. If your homelab already centres on Immich, that coupling is the reason to pick GeoPulse. If you want the smallest possible moving parts and no Java runtime anywhere, Dawarich's Rails stack will feel more familiar. The README does not publish a migration path between the two, so treat the choice as one-way in practice.

Maintenance, releases and upgrade cost

The last push to the repository was on 2026-09-10, and the most recent release listed is v1.39.0 on 2026-09-07, titled "MCP, Panoramax, Trip Split". Two releases landed in the same week: v1.38.0 on 2026-09-03 ("Map Matching, Admin Backups and more") and v1.38.1 on 2026-09-04, described as a regression fix. That cadence tells you two things. Feature work is moving, and regressions do reach tagged releases, which is why the patch release exists.

Upgrades are version-pinned. GEOPULSE_VERSION in .env.example is set to 1.39.0, and the comment above it states that the app, frontend and backend should all use the same version. Since the backend and frontend images are pulled by that single variable, bumping the version and re-running docker compose up -d is the upgrade path the compose file implies. The README does not document a rollback procedure, and it does not state whether database migrations are reversible. Back up before you bump.

Backups are a first-class feature rather than a suggestion. The README describes "Encrypted, password-protected full backups with manual restore and scheduled automatic backups", and the compose file mounts ./backups into the backend at /data/geopulse-backups. There is also an ./import-drop directory mounted at /data/geopulse-import for bulk imports. Both are host directories, so your backup story is only as good as whatever copies those paths off the machine.

On licence cost: BSL 1.1 generally permits non-production use freely and restricts production or competing use until a change date, but the specific grant is in the LICENSE file, not the README. Read it before you build anything commercial on top.

Editorial conclusion

Adopt GeoPulse if you already run a homelab or NAS with Docker, you have a GPS app such as OwnTracks or Overland feeding it, and you want location history on your own disk next to an Immich library. Skip it if you need a hosted service with zero maintenance, or if you cannot live with the Business Source License 1.1 that the repository badge shows. Before committing, read the LICENSE file itself, confirm which image tag matches your CPU (the compose file notes a -native-compat variant for x86-64-v2 and Raspberry Pi 3/4), and check the .env.example values for GEOPULSE_PUBLIC_BASE_URL and GEOPULSE_CORS_ORIGINS against your own domain.

Frequently asked questions

What is GeoPulse?

GeoPulse is a self-hosted location timeline platform that the README calls the open-source, privacy-first Google Timeline alternative. It converts raw GPS data from apps such as OwnTracks, Overland and GPSLogger into a searchable timeline of stays, trips and data gaps, and runs entirely on your own infrastructure.

What is a GeoPulse alternative for self-hosted location history?

Dawarich is the direct alternative named in the project's related searches, and GeoPulse itself lists Dawarich as a supported data source. The main difference is the stack: GeoPulse is a Java and Quarkus backend over PostgreSQL with PostGIS, while Dawarich is a Ruby on Rails application. The README does not document a migration path between them.

How do I install GeoPulse?

The README's quick start downloads .env.example and docker-compose.yml into a geopulse directory, then runs docker compose up -d. The UI is then available at http://localhost:5555. For MQTT, Kubernetes, Unraid, Proxmox or bare metal, the README points to separate deployment guides.

Does GeoPulse work with Immich?

Yes. The README lists Immich integration as a feature, and states that photos from your Immich library appear directly on your map timeline. Memos notes and weather conditions are integrated in the same way.

What licence does GeoPulse use?

The README badge shows BSL 1.1, and the repository's licence field is NOASSERTION, meaning it could not be classified automatically. The README does not restate the licence terms, so read the LICENSE file in the repository before using GeoPulse in a commercial or production setting.

Can GeoPulse import my existing Google Timeline data?

The README lists universal import support for Google Timeline alongside GPX, GeoJSON, OwnTracks exports and CSV. The compose file also mounts a host directory at /data/geopulse-import for bulk imports.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. tess1o/geopulse on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tess1o-geopulse.svg)](https://hysenlabs.com/projects/tess1o-geopulse)