Skip to content

notifly

notifly

Every ping, checked.
A personal finance tracker that turns your bank and e-wallet notifications into a ledger, and never counts a cent until you confirm it.

CI Latest release License: AGPL-3.0 Android 8.0+ Kotlin Compose Multiplatform On-device parsing Last commit

Features · How it works · Privacy · Installation · Building · Contributing

Warning

notifly is pre-release software under active development. Cloud sync is not configured yet, and the app has not been published to the Play Store. Keep your own records while you try it out.


Why notifly?

You already get a notification for every GCash send, Maya top-up and bank transfer. notifly reads those pings on your phone and turns each one into a draft transaction. You glance, confirm, and your balance is up to date. You don't have to type anything.

  • No typing. The ledger builds itself from notifications you already get.
  • You confirm everything. Parsed transactions start as Needs review. They never change your headline balance until you confirm them.
  • Private by design. Notification text is parsed on-device and never leaves the phone.
  • Works offline. No account, no sign-up, no server needed.

Transaction search, light theme   Transaction search, dark theme

Features

Automatic capture Reads notifications only from apps you allow-list. Built-in support for GCash, Maya and BPI, plus a bundled on-device classifier for other apps.
Review queue Drafts wait in Needs review, shown as a separate pending line that never mixes with the confirmed balance.
Full ledger Add, edit, search and filter transactions. Bulk actions with long-press selection and swipe actions.
Accounts & transfers Per-account balances, transfer detection that excludes transfers from spending, and transfer fees.
Budgets & bills Inline budgets per category and bill reminders parsed from notifications.
Insights Spending breakdowns and trends over time.
Notification log See every captured notification, how it was parsed and why it was ignored. Clear it whenever you want.
CSV import / export Move your ledger in and out as plain CSV. Imported rows also go to review first. See docs/TRANSACTION_CSV.md.
App lock Protect the app with a PIN or biometrics.
Theming Four palettes in light and dark, plus Material You themed launcher icons.
Adaptive layouts Phone and tablet layouts.
Accessible State is never shown by colour alone, swipe actions have accessibility alternatives, and the app follows system font scale and reduced motion settings.

How it works

flowchart LR
    A[Bank / e-wallet<br>notification] --> B{Allow-listed<br>app?}
    B -- no --> X[Ignored<br>package + reason only]
    B -- yes --> C[On-device parser<br>+ classifier]
    C -- no amount --> U[Unrecognized<br>no transaction]
    C -- amount found --> D[Draft<br>NEEDS_REVIEW]
    D -- you confirm --> E[Confirmed<br>moves balance]
  1. Grant notification access. Android treats this as special access, so you turn it on in system settings instead of answering a permission dialog. notifly takes you there and shows whether the listener is actually connected.
  2. Pick your apps. notifly only reads notification text from apps you allow-list.
  3. Review and confirm. Each captured payment shows up as a draft. Confirm it, edit it, or delete it.

Apps often update one notification in place, so capture dedupes on notification key and content hash. If notifly can't find an amount, it doesn't create a transaction. It never guesses one.

Privacy

Privacy is part of the architecture. You can't switch it off in settings.

  • Notification text is parsed on-device and is never sent over the network.
  • Notification content is never written to logs.
  • Text from apps that aren't allow-listed is never read.
  • Keeping raw notification text is off by default. If you turn it on, the text stays on the device for troubleshooting only.
  • Crash reporting (Sentry) is opt-in, off by default, and strips exception messages, screenshots and transaction data.
  • Android backup and device transfer exclude the ledger and notification data.

The full draft policy is in docs/PRIVACY.md.

Installation

notifly is not on the Play Store yet.

  • Releases: signed builds are attached to GitHub Releases.
  • Nightly / PR builds: every pull request uploads a debug APK as a CI artifact.

Requirements: Android 8.0 (API 26) or newer.

Note

iOS isn't supported, and that won't change with more work: iOS has no API for reading other apps' notifications. The iOS targets exist only to keep the shared code platform-neutral.

Building from source

Prerequisites

  • JDK 17
  • Android SDK (compile SDK 37)
  • Android Studio (latest stable or newer), or just the command line
git clone https://github.com/kryoware/notifly.git
cd notifly

# Run the test suite (includes the parser regression suite)
./gradlew :shared:allTests

# Build and install a debug APK on a connected device
./gradlew :app:installDebug

Useful tasks:

Task What it does
./gradlew lint Android lint
./gradlew test All unit tests
./gradlew :app:assembleDebug Debug APK at app/build/outputs/apk/debug/
./gradlew :app:bundleRelease Release AAB (needs signing variables, see below)
Release signing

Release builds read each value from a Gradle property (for example in ~/.gradle/gradle.properties) or, failing that, an environment variable:

Gradle property Environment variable Purpose
notiflyKeystoreFile KEYSTORE_FILE Path to the keystore
notiflyKeystorePassword KEYSTORE_PASSWORD Keystore password
notiflyKeyAlias KEY_ALIAS Signing key alias
notiflyKeyPassword KEY_PASSWORD Signing key password
sentryDsn SENTRY_DSN Optional crash reporting
SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT Optional mapping upload

If the signing variables aren't set, the local release build is unsigned. Pushing a v*.*.* tag runs release.yml, which builds a signed AAB and creates a draft GitHub Release.

Tagged builds use the tag as their displayed version. Other source builds read VERSION. When you publish the draft, release-metadata.yml commits the newest published version and CHANGELOG.md to master, so pulling master also updates the version shown in Settings. Release notes opens the GitHub release for that version. With protected master, configure the RELEASE_METADATA_TOKEN Actions secret with a token that has Contents write permission and can bypass the required PR review (for example, a repository admin token when admin enforcement is disabled). Otherwise the workflow uses GITHUB_TOKEN, which requires branch rules to allow the Actions bot to push. Commits made with GITHUB_TOKEN do not trigger another CI run.

Tech stack

Layer Technology
Language Kotlin Multiplatform
UI Compose Multiplatform, Material 3 (adaptive navigation)
Storage Room, DataStore
DI Koin
Async Coroutines, kotlinx-datetime
Charts Koala Plot
Crash reporting Sentry (opt-in)
Testing kotlin.test, Robolectric

Project layout

app/      Android entry point + NotificationCaptureService
shared/   commonMain   domain, data, ui (Compose), di
          androidMain  notification source, classifier, DB builder
          iosMain      unavailable source, DB builder
          commonTest   parser regression suite
docs/     design, privacy, brand and implementation notes
tools/    palette and icon generators

The code is layered Data → Domain → Presentation. The domain layer is pure Kotlin with no platform imports, and all capture goes through the TransactionSource interface.

Documentation

Doc Contents
DESIGN.md Design system: colour, type, components
PLAN.md Phased build plan
docs/IMPLEMENTATION_STATUS.md What's done and what still needs verification
docs/CLASSIFIER_MODEL.md The bundled on-device notification classifier
docs/PRIVACY.md Privacy policy (draft)
docs/TRANSACTION_CSV.md CSV import/export format
docs/MD_ICONS.md · docs/MD3_LIST.md Icon and list UI guides

Roadmap

  • [ ] Opt-in cloud sync of confirmed transactions only
  • [ ] Play Store release
  • [ ] More bank and e-wallet parsers, tuned on real samples
  • [ ] iOS story: bank aggregator, file import, or manual only (undecided)

Contributing

Contributions are welcome, especially parser samples for banks and e-wallets that aren't supported yet.

Before you open a PR:

  1. Run ./gradlew lint test and make sure it passes.
  2. Follow the project rules in CLAUDE.md. The ones that matter most:
  3. Money is Long minor units (centavos). Never Double or Float.
  4. Never log notification content, not even at debug level.
  5. Parsed transactions always start as NEEDS_REVIEW.
  6. All colour comes from MaterialTheme. No hardcoded hex.
  7. Never paste real notification text into issues or PRs. Redact names, account numbers and reference numbers first.

License

notifly is licensed under the GNU Affero General Public License v3.0.