OTP Helper, an Android app that copies codes out of notifications
open-source application that can copy OTP and codes from notifications automatically for you
At a glance
- What is it?
- OTP Helper reads incoming notifications and SMS on Android, extracts one-time codes with a detection regex, and copies them for you. It works offline with no internet permission, and it does so by asking for broad access to everything on your lock screen.
- Who is it for?
- OTP Helper suits Android users who receive one-time codes as notifications rather than as plain SMS and who want them copied without opening the sending app, and it does not suit anyone unwilling to grant a notification listener access to every message that reaches their screen.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 55 days ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A notification listener that sees every message on the screen
OTP Helper is an open source Android application that copies one-time passwords and other codes from SMS and notifications automatically. The mechanism is not a keyboard or a shortcut, it is a notification listener. The app sets up a NotificationListener and reads all notifications sent by any app. The documentation is explicit about the consequence: because it reads everything, it can detect codes that arrive in emails and probably in any other app that sends a notification, not only in messaging apps.
The pipeline is simple and worth understanding before you install it. When a notification arrives, the app builds a single string from all the text in the notification. That string is then checked against an ignore rule to see whether it should be discarded. If it is not ignored, it is matched against a code detection regex. Whatever code the regex extracts is then handled according to your settings.
The project is written in Kotlin, with Jetpack Compose and Material Design among its repository topics, and it ships as io.github.jd1378.otphelper. It is distributed through F-Droid, Google Play and Bazaar, and an APK is available from the latest release page. This is a mature distribution footprint for a utility of its size, with translations contributed on Weblate covering German, Spanish, Turkish, Bangla, Vietnamese, Chinese, Russian, Italian, French, Arabic, Hindi, Ukrainian, Portuguese, Polish, Japanese and Korean.
The ignore check runs before the regex ever sees the text
The order of the two checks is the design decision that makes this approach tolerable. The ignore logic, kept in a file named CodeIgnore.kt, runs first. Only text that survives it is handed to the code detection regex in CodeExtractor.kt.
That ordering matters because the alternative would be worse. A notification listener on Android receives everything, including the messages from apps that have nothing to do with one-time codes: chat messages, delivery updates, marketing pushes. Matching all of them against a code pattern would produce a steady stream of false positives, and the clipboard would fill with digits that nobody asked for. Filtering first means the pattern only ever runs on text you have already decided is worth looking at.
The application handles the extracted code according to your settings rather than always doing one fixed thing, which is the usual shape for these tools: copy it, show it, or both. The documentation does not enumerate every handling option in the excerpt available here, so treat the settings screen rather than the README as the source of truth for what happens to a detected code. The same applies to the contents of the ignore list, which the documentation describes as configurable but does not enumerate.
SMS mode reuses the same two checks
The second mode is separate but structurally identical. The app listens to all incoming SMS messages and processes them in the same way as the notification mode: it checks whether the message should be ignored, and if not, matches it against the code detection regex. The extracted code is then handled according to your settings.
So there are two input paths and one processing path. Notifications come in through the listener, SMS comes in through the message receiver, and both converge on the ignore check and the regex. For a user this means a code that arrives by SMS behaves the same as a code that arrives as a notification, and the same settings govern both.
The reason the notification path exists at all is that the SMS path alone is not enough for many services. Codes delivered by email, or pushed by a banking app or a service that sends its codes inside an app notification, never pass through the SMS receiver. That is the gap the listener fills, and it is also the reason the permission request is as broad as it is. The trade is between catching codes from any source and trusting one app with a view of every notification your phone receives.
Offline by design, with no internet permission requested
The application works completely offline and without the internet permission, and the documentation says plainly that this is meant to reassure users that their data does not leave the device. That is a meaningful design constraint rather than a marketing line. One-time codes are the most sensitive short-lived data on an Android phone, and an app that could reach the network could exfiltrate them. The offline guarantee removes that category of risk by construction, and it also means the app is usable on a phone with no data connection, which is exactly when you might be waiting on a code.
The repository layout backs the Android-specific parts of the story. There is an app/ module with the Kotlin sources, the shared SmsUtils.kt at the top level, a build.gradle.kts and settings.gradle.kts pair, the gradlew wrapper and gradlew.bat, a gradle/ directory, plus fastlane/ and GPLAY_GUIDE.md for the store listing and docs/ for the rest.
The honest counterpoint is that a no-internet app can still be a serious listener, and this one is. The code it copies is handled locally, but every notification text on your device passes through it. The trust question is not about the network, it is about the scope of the notification access itself.
Building the release APK with the Gradle wrapper
The build step is documented as a single command, run from the repository root:
./gradlew :app:assembleReleaseThe resulting APK is then available in the apps/build/outputs/apk/release/ directory, which the README gives as apps/build/outputs/apk/release/. The wrapper is committed, so a build does not need a system Gradle installation, and the module selector :app:assembleRelease targets the application module directly rather than the whole project.
For a project distributed through several stores, the release build is the interesting one, since a signed release artefact is what a store listing needs. The repository carries fastlane/ and GPLAY_GUIDE.md at the top level, which are the conventional ingredients for automated store submissions, and the release history shows the app tagged regularly through the 1.20 line, with v1.20.6 published on 2026-08-24 and v1.20.5 on 2026-06-21. The last push to the repository was on 2026-08-29. So the code that builds the APK you install from source is the same tree that produced the recent tagged builds, rather than a stalled snapshot.
Notification access versus an SMS-only approach
The alternative approach to this app is to use something that only handles incoming SMS and nothing else. Such a tool needs the SMS permission, sees only messages, and never touches the notification stream, so it never sees a code that arrives as a push inside another app. That is a much smaller blast radius, and for a user whose bank sends everything by SMS it is entirely sufficient.
OTP Helper takes the opposite position. The notification listener catches codes from any source, including email and other apps, which is a real advantage when services are inconsistent about how they deliver codes. The cost is that the app is granted a view of every notification on the device, so any vulnerability in its parsing or handling has access to a stream of personal content that an SMS-only tool would never see. It is also the reason the ignore list exists and why it is worth spending time on.
Neither approach dominates. An SMS-only extractor is the right choice if every code you expect arrives by message. A notification-based reader is the right choice if your codes arrive in a mix of channels, and the price of that coverage is permanent, broad access to the notification stream on one device.
Editorial conclusion
OTP Helper suits Android users who receive one-time codes as notifications rather than as plain SMS and who want them copied without opening the sending app, and it does not suit anyone unwilling to grant a notification listener access to every message that reaches their screen. Before installing, read what the app does with a detected code after extraction, check the ignore list so banking codes from apps you do not want touched are excluded, and note that the licence is AGPL-3.0, which matters if you plan to fork and ship your own build.
Frequently asked questions
How does OTP Helper detect one-time codes on Android?
It runs in two modes. As a notification listener it reads all notifications from any app, builds one string from the notification text, checks whether it should be ignored, and then matches it against a code detection regex. As an SMS listener it processes incoming messages through the same ignore check and the same regex.
Does OTP Helper send my data anywhere?
The application works completely offline and does not request the internet permission, and the documentation says this is so your data does not leave your device. Everything the app processes, including the notifications it reads, stays on the phone.
How do I build the OTP Helper APK from source?
Run ./gradlew :app:assembleRelease from the repository root. The APK is then written to the apps/build/outputs/apk/release/ directory, and the Gradle wrapper is included so no local Gradle install is needed.
Where can I download OTP Helper?
It is listed on F-Droid, Google Play and Bazaar, and the README also links the APK from the latest release page on GitHub. The project id used across those listings is io.github.jd1378.otphelper.
Official sources
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.
[](https://hysenlabs.com/projects/jd1378-otphelper)Was this useful?