Android app for plausible.io statistics
Find a file
Ole-Morten Duesund ebe1d18123 feat: add open-in-browser button to dashboard
Opens {baseUrl}/{siteId} in the default browser so users can quickly
access the full Plausible web interface for their site.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 17:53:53 +01:00
app feat: add open-in-browser button to dashboard 2026-03-18 17:53:53 +01:00
gradle feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
.gitignore feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
build.gradle.kts feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
CLAUDE.md feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
gradle.properties feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
gradlew feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
gradlew.bat feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
LICENSE feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
plan.md feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00
README.md docs: add README with features, architecture, and build instructions 2026-03-18 17:48:51 +01:00
settings.gradle.kts feat: implement Phase 1 MVP of Implausibly 2026-03-18 16:46:08 +01:00

Implausibly

An open-source Android dashboard app for self-hosted Plausible Analytics CE.

The existing third-party apps are all closed-source. If you're running self-hosted Plausible specifically because you care about control and transparency, a closed-source dashboard app is an odd fit.

Implausibly is:

  • Fully open source (GPL-3.0) — audit it, fork it, contribute
  • Self-hosted first — configurable base URL, no Plausible.io assumptions
  • No account or subscription — just your Plausible API key
  • Zero telemetry — no analytics in the analytics app
  • No Google Play Services — pure AndroidX, F-Droid compatible

Screenshots

Coming soon — the app is functional but screenshots haven't been captured yet.

Features

  • Multi-instance support — connect to multiple Plausible servers
  • Full dashboard — visitors, pageviews, bounce rate, visit duration
  • Visitor chart — custom Canvas line chart with area fill
  • Dimension breakdowns — top sources, pages, countries, devices, browsers, OS
  • Date range selector — today, 7d, 30d, 6mo, 12mo
  • Pull-to-refresh — swipe down to reload
  • Caching — SQLDelight cache with TTL per date range; shows cached data instantly on launch
  • Encrypted API keys — stored via EncryptedSharedPreferences (AES-256-GCM)
  • Clone instances — duplicate an instance config to track a different site with the same credentials
  • Smart navigation — remembers your last-viewed dashboard and opens directly to it
  • Material 3 — light and dark theme

Requirements

  • Android 8.0+ (API 26)
  • A self-hosted Plausible CE instance with API v2 enabled
  • An API key (or a public shared link)

Building

# Clone
git clone ssh://git@kode.naiv.no:2222/olemd/implausible.git
cd implausible

# Build debug APK
./gradlew assembleDebug

# Run unit tests
./gradlew test

# Install on connected device
./gradlew installDebug

# Lint
./gradlew lint

Requires JDK 17. The Gradle wrapper is included — no separate Gradle installation needed.

Architecture

Four-layer unidirectional data flow:

UI (Jetpack Compose + Material 3)
  | observes StateFlow
ViewModel (per screen, sealed UiState)
  | calls
Repository (cache-first, coordinates API + DB)
  | delegates to
Remote (Ktor) + Local Cache (SQLDelight)

Everything goes through one API endpoint: POST /api/v2/query. The dashboard fires 8 concurrent queries per load.

Tech stack

Component Library
UI Jetpack Compose + Material 3
HTTP Ktor (OkHttp engine)
Serialization kotlinx.serialization
Local DB SQLDelight
DI Hilt
Preferences DataStore
Secrets EncryptedSharedPreferences
Charts Custom Canvas (no library)

Package structure

no.naiv.implausibly/
  data/
    remote/         Ktor API client, DTOs
    local/          SQLDelight generated code
    repository/     StatsRepository, InstanceRepository, SiteRepository, CacheManager
    ApiKeyStore     Encrypted key storage
    AppPreferences  DataStore preferences
  domain/model/     Domain models (decoupled from API/DB)
  di/               Hilt modules
  ui/
    setup/          Instance onboarding
    sites/          Site list / management
    dashboard/      Stats dashboard, components, sections
    navigation/     NavHost, routes
    theme/          Material 3 theme
    common/         Shared UI (UiState, LoadingIndicator, ErrorState)

API

The app uses the Plausible Stats API v2. Rate limit is 600 requests/hour — with 8 queries per dashboard load, that's ~75 refreshes/hour.

Caching

Cache key = SHA-256 hash of (instanceId, siteId, dateRange). TTL varies:

Date range Cache TTL
Realtime Never cached
Today 5 min
7d, 30d 30 min
6mo, 12mo 2 hours

On app open: show cached data immediately, refresh in background.

Roadmap

Phase 2 (planned)

  • Filter system (bottom sheet, combinable filters)
  • Material You dynamic color
  • Landscape layout
  • Realtime polling
  • Sites API auto-discovery
  • Custom date ranges
  • F-Droid submission

Phase 3 (future)

  • Comparison mode (this period vs previous)
  • Goal conversions
  • Segments support
  • Home screen widgets (Glance)

License

GPL-3.0-only

This means any distributed fork must also be open source under the same license. All dependencies are GPL-compatible (Apache 2.0, MIT).

Contributing

Contributions welcome. The project is hosted on Forgejo at kode.naiv.no.

All source files must include the SPDX header: // SPDX-License-Identifier: GPL-3.0-only