A first-class mobile companion for self-hosted Uptime Kuma. Free, open source, native-feeling.
Uptime Pocket is the iOS and Android app for Uptime Kuma β a beautiful, self-hosted monitoring tool. It brings your monitors, incidents, and notifications to your pocket with native Liquid Glass UI on iOS 26+ and Material 3 Expressive on Android.
Latest release: v0.5.0. See CHANGELOG.md for what landed in each version, including the unreleased work on
main.
- π± Native UI β iOS 26 Liquid Glass, Material 3 Expressive on Android, buttery 120fps animations
- π Multi-server β connect to all your Kuma instances from one app
- π Secure auth β bearer tokens (Kuma 2.0+) or username/password, stored in iOS Keychain / Android Keystore
- π Smart notifications β choose between direct socket connection or self-hosted push relay
- π Home screen widgets β glanceable monitoring on iOS and Android, including Lock Screen
- π Rich detail view β 24h/7d/30d response time charts, uptime bars, incident history
- β‘ Live updates β real-time status changes via socket.io
- π Light / Dark β system, manual, or auto
- π Biometric lock β Face ID, Touch ID, fingerprint
- π Open source β MIT licensed, no telemetry, no ads, no analytics
# Install dependencies
npm install
# Run on iOS (macOS only)
npm run ios
# Run on Android
npm run android
# Run on web (limited - widgets don't work in browser)
npm run webThe first time you launch the app, you'll see the Add a server empty state in the Monitors tab. Tap the + in the Servers tab, paste your Kuma URL + API token, and you're connected. The dev sample seed has been removed; Uptime Pocket now boots into a clean state.
- Monitors tab β list of all monitors with status pills, uptime, response time. Tap to see detail with response time chart, uptime bar, and recent incidents.
- Incidents tab β placeholder for v1.0; will show history of monitor down/recovery events.
- Servers tab β manage Kuma server connections. Tap the + to add a new server.
- Settings tab β theme switcher, app info, and a link to the Design System screen (showcase of every component in light + dark).
- Add Server β form with bearer token (recommended) or username/password auth.
- Server switcher β accessible from the Monitors tab header.
- Node.js 20+
- For iOS development: macOS with Xcode 17+
- For Android development: Android Studio with API 26+ SDK
- Expo Go app on your phone (for development)
- Expo SDK 56 (Universal App, New Architecture)
- Expo Router 56 (file-based routing)
- NativeWind 4.2 + Tailwind CSS 3.4 (styling for React Native)
- Reanimated 4 (UI-thread animations)
- expo-glass-effect (iOS 26 Liquid Glass)
- expo-notifications (push + local)
- expo-sqlite (server metadata persistence)
- expo-secure-store (iOS Keychain / Android Keystore credential vault)
- socket.io-client (live updates)
- Zustand (state)
- Zod (validation)
- Jest + jest-expo (unit tests)
uptime-pocket/
βββ app/ # Expo Router screens
β βββ (tabs)/ # Tab bar (Monitors, Incidents, Servers, Settings)
β βββ servers/ # Add server / server detail
β βββ welcome.tsx # First-launch onboarding
βββ src/
β βββ components/ # Reusable UI
β β βββ ui/ # Primitives (Button, Chip, Tag, EmptyState, β¦)
β β βββ monitor/ # MonitorCard, MonitorRow
β β βββ server/ # ServerCard, ServerSwitcher
β β βββ chart/ # ResponseTimeChart, UptimeBar
β βββ theme/ # Design tokens (colors, spacing, type)
β βββ domain/ # Pure business logic + models
β βββ data/ # I/O layer
β β βββ api/ # REST client + Kuma auth
β β βββ socket/ # socket.io client
β β βββ db/ # SQLite schema, migrations, repository
β β βββ secure/ # Credential vault (SecureStore wrapper)
β β βββ connection/ # KumaConnectionManager
β β βββ store/ # Zustand stores (servers, monitors, settings)
β βββ features/ # Feature hooks (e.g. useServersHydrated)
β βββ platform/ # Native bridges (widgets)
β βββ lib/ # Utilities
β βββ i18n/ # Translations
βββ tests/ # Jest unit tests (a few also live beside their source)
βββ plugins/ # Expo config plugins (android-widget, ios-widget)
βββ UptimePocketWidget/ # iOS WidgetKit extension (Swift)
βββ relay/ # Optional self-hosted push relay (Go)
βββ .maestro/ # Maestro end-to-end flows
βββ .github/workflows/ # CI: ci.yml (app) + relay.yml (Go relay)
βββ scripts/ # Dev/E2E helper scripts
βββ docs/ # Documentation
βββ assets/ # Images, fonts
βββ jest.config.js # Jest configuration (jest-expo preset)
βββ jest.setup.ts # Global mocks (expo-secure-store, expo-sqlite)
Phase 2 introduces a clear split between server metadata (SQLite) and credentials (SecureStore), and a single source of truth for Kuma connections.
| Data | Lives in | Why |
|---|---|---|
| Server metadata (id, name, url, auth kind, version, connection state) | SQLite (servers table) |
Needs to be queryable, orderable, joinable. |
| Auth secrets (bearer tokens, passwords) | expo-secure-store (iOS Keychain / Android Keystore) | Encrypted at rest by the OS. The Server type has no field for a secret β secrets only exist transiently in KumaConnectionManager. |
The in-memory servers Zustand store mirrors the SQLite rows (via useServersHydrated()). To actually connect to a Kuma instance, the connection manager calls loadCredentials(serverId) and the secret never enters React state.
KumaConnectionManager owns the socket + REST lifecycle for the active server:
connect(serverId)β loads creds from SecureStore β opens socket β sets monitors store status toconnecting.- On socket
connectevent β status becomesconnected, version is recorded,serversRepo.setConnected(true)persists to SQLite. - On socket
disconnect/ error β status reflects the failure;recheck()re-attempts;pause()/resume()control backoff. disconnect(serverId)tears down the socket, clears the connection state in both stores and SQLite.
useKumaConnection() hook keeps the manager in sync with activeServerId β it auto-connects to the new active server and disconnects from the old one on switch. It also cleans up on unmount.
Server.auth(full strategy) was removed in v0.3.0. Server records carry onlyauthKind: 'bearer' | 'password'.- The credential load path is zod-validated. Empty / malformed values return
null, and the manager surfaces a "No credentials stored" error. - Credentials are namespaced by server id (
uptime-pocket.cred.<serverId>) and never written to logs or state.
- Architecture
- Authentication β bearer token vs username/password
- Notifications β None / Direct / Relay modes
- Push relay β optional self-hosted push server
- Design system
# Unit tests (Jest + jest-expo)
npm test
# TypeScript
npm run typecheck
# Lint
npm run lint
# React Doctor β broader code health scan
npm run lint:doctorJest is configured via jest.config.js (jest-expo preset) and jest.setup.ts (global mocks for expo-secure-store and expo-sqlite). Most unit tests live under tests/, mirroring the src/ structure; a few sit next to their source (src/platform/widget/__tests__/, src/data/relay/client.test.ts). Jest's testMatch picks up both.
Two things to know about npm run lint, because both have already produced misleading results:
- It is
expo lint, which caches results in.expo/cache/eslint/. The cache key is file content + config, notnode_modules, so animport/no-unresolvedrecorded while a dependency was missing keeps reappearing after you install it. Ifnpm run lintreports an error thatnpx eslint <that file>does not, runnpm run lint -- --no-cacheor delete.expo/cache/eslint. - It only walks
src,appandcomponents. To lintplugins/,scripts/,tests/and the root config files too, runnpx eslint ..
We also have Maestro flows under .maestro/ for end-to-end smoke tests.
.github/workflows/ci.yml runs npm run typecheck, npm run lint and npm test on every push and pull request. It uses only the first-party actions/checkout and actions/setup-node actions, and does not build, sign, publish or upload anything β this project deliberately does not use EAS or any third-party build service.
- Web bundling is blocked by an
expo-sqlitewasm bundler issue. iOS and Android builds are unaffected. We don't ship web in this release. npm auditreports 33 advisories (17 moderate, 16 high) as of 2026-09-01. Six are direct dependencies βdrizzle-orm(high),@expo/config-plugins,expo,expo-router,expo-splash-screenandxcode(all moderate) β and the rest are transitive. They have not been individually triaged for reachability from app code; treat the count as a to-do, not as a cleared risk.
We welcome PRs! See CONTRIBUTING.md for guidelines.
Before opening a PR:
- Run
npm run lintandnpm run typecheck - Run
npm test(we use Jest + Maestro for E2E) - Add tests for new functionality
- Update docs if you change user-facing behavior
Found a security issue? Please see SECURITY.md β don't open a public issue.
MIT Β© 2026 Quavon-dev
This project is not affiliated with the official Uptime Kuma project, but shares its spirit of self-hosted, privacy-respecting software.
- Uptime Kuma by @louislam β the amazing monitoring tool this app is built for
- Expo β for the SDK that makes this app possible
- All our contributors β thank you!