Inspiration Singaporeans lost over $1.1 billion to scams in 2024, and seniors remain the most-targeted group. One convincing message can wipe out a life savings. We kept coming back to two uncomfortable truths. First, scams now arrive everywhere — SMS, WhatsApp, Telegram, email, calls — while the most common defence is still "be careful." Second, the scam filters that do exist mostly work by uploading your private messages to someone else's cloud. For the people most at risk, protection came at the price of privacy, and many victims felt too ashamed to ask anyone for help. We asked: what if the scam filter lived in your pocket, never read over your shoulder, and got smarter every time anyone in the community reported a new scam? That question became ScamWatch — spot the scam before it spots you. What it does ScamWatch is a privacy-first, on-device AI scam firewall for Android, backed by a community scam shield.
- Watches 27 messaging apps at once. A native listener reads incoming notifications from WhatsApp, Telegram, Signal, SMS, Messenger, WeChat, Gmail and more — plus calls.
- Classifies every message on-device. A small language model running entirely on the phone scores each message in ~740 ms. No message ever leaves the device. It works offline.
- Warns before you reply. If a message is risky, a full-screen overlay appears over whatever app you're in — "Possible scam — 92%" — with the reason in plain language, not a cryptic score.
- Explains itself. Verdicts come back as suspicious / unclear / likely_safe with named signals: urgency, credential requests, money requests, prize scams, authority impersonation, suspicious links — each with the evidence excerpt.
- Screens calls. Incoming numbers get a trust score (0–100) drawn from community reports; high-risk callers trigger a red alert or can be blocked outright.
- Turns one report into everyone's protection. With one tap, a user can publish an automatically PII-redacted version to the community feed. That report feeds the phone-number trust score and warns everyone else. It's built deliberately for seniors: big type (up to 1.8× text scale), 56–72 px tap targets, four languages (English, Malay, Tamil, Chinese), and a guided tour. How we built it Three components, one privacy boundary. The Android app (Flutter + native Kotlin). A NotificationListenerService in Kotlin captures messages from 27 apps and hands them to an on-device LLM — Gemma 4 E2B, Qwen3 1.7B, Gemini Nano via AICore, or any user-supplied GGUF through llama.cpp. Weights unload after 90 s idle, decoding is greedy for determinism, and a separate background FlutterEngine with wake locks means detection survives process death, re-checking anything it missed. To avoid crying wolf, regex and contact "hints" are rendered into the prompt, and a hard gate requires two or more independent signals at high confidence before any warning fires. Call screening runs through Android's native telephony role. The backend (Go + PostgreSQL). A Go 1.25 API on stdlib net/http with 44 routes under /api/v1, pgx/v5, and 13 migrations. It handles JWT auth (15-minute access + rotating 30-day refresh tokens with theft detection), private detection history, phone trust scores (−15 points per report, 30-day window, neutral 60), and the moderated community feed with full-text search across English, Chinese, Malay and Tamil. The AI redaction service (Python FastAPI). When a user chooses to share a screenshot, PaddleOCR finds every text box, a decision model scores each box for PII (batched 64 per call), and Pillow paints over the boxes. The pipeline is fail-closed — if redaction can't complete, the server returns an error rather than risk leaking data — and the Go server re-scrubs all text again on publish. The website (React 19 + TypeScript + Vite). A marketing landing page plus the full community forum: browsing redacted reports, checking phone numbers, and reading safety guidance. The rule that ties it all together: private checks never touch public tables, uploads are deleted after 24 hours, checks after 30 days. Challenges we ran into False positives are the real enemy. An app that nags about every message gets uninstalled in a day. Our answer was layered: prompt hints from regex and contacts, a hard gate needing 2+ independent signals at high confidence, and honest verdicts — "unclear" is a valid answer, not a failure. On-device AI on a phone that isn't yours. Models must fit in limited RAM, classify in under a second, and not drain the battery. We unload weights after 90 s of idleness, auto-select the model by available RAM, and let users pick CPU/GPU/NPU backends — but getting a 1–3 GB model to feel instant took real tuning. Surviving Android. OEMs kill background services aggressively. Keeping protection alive meant a foreground service, boot receiver, wake locks, a separate background Flutter engine, and re-checking unclassified messages after process death. Redacting PII you can't afford to miss. OCR boxes and PII detection are both probabilistic. We made the pipeline fail-closed, batched the PII scoring 64 boxes at a time to stay fast, and made the server re-scrub everything on publish as a second line of defence — shipping only redacted derivatives, never raws. Letting users share without being exposed. The community is only useful if people can post real scam screenshots. Earning that trust meant content-addressed storage, anonymous posts, a moderation queue with audit trails, and a retention reaper that deletes data on schedule. Accomplishments that we're proud of
- Fully on-device classification across 27 apps at ~740 ms per message — genuinely offline, genuinely private.
- An anti-false-positive gate that requires 2+ independent signals — we measure success by warnings people trust, not warnings we fire.
- A fail-closed PII redaction pipeline (OCR → per-box PII scoring → fill, with server-side re-scrubbing) — privacy enforced by architecture, not promises.
- Native call screening that actually blocks calls through Android's telephony role, driven by a community-built trust score.
- Senior-first design that isn't a checkbox: 1.8× text scaling, 56–72 px tap targets, four languages, plain-language verdicts, and a coach-mark tour.
- A production-shaped backend: rotating refresh tokens with theft detection, 13 migrations, multilingual full-text search, rate limiting, and a scheduled retention reaper. What we learned Privacy is an architecture, not a policy page. The strongest guarantees we shipped — "no message leaves the device," "private checks never touch public tables" — were enforced by separating systems, not by promising to behave. For high-stakes AI, trust beats accuracy. A detector people don't believe is worse than no detector. Explainable verdicts, visible evidence, and an honest "unclear" did more for usability than chasing another point of recall. Small models are enough — with the right guardrails. A 1–3 GB model, greedy decoding, prompt hints, and a multi-signal gate turned out to be a better product than a bigger model with no discipline around false positives. The community is a detection layer. The trust score and feed aren't social features bolted on — they're how a scam reported once protects thousands. What's next for ScamWatch
- Wire up what's already built: the community feed and guidance screens exist in the app codebase but aren't yet in navigation — shipping them is the immediate win.
- iOS support, bringing the on-device firewall to the rest of the at-risk population.
- Closing the loop on-device: feeding aggregated community trust signals back into the on-device classifier's hints, without ever uploading messages.
- Deeper official integration with Singapore's anti-scam ecosystem — the ScamShield 1799 helpline and verified resource catalog are already in the backend.
- More languages and accessibility profiles, expanding beyond the current four to match Singapore's communities.
- Richer scam intelligence: trend detection from the community feed to warn users about new campaigns the moment they appear — "fake delivery fee texts circulating now," pushed before the second victim.
Built With
- docker
- flutter
- get-leetify
- github
- go
- javascript
- kotlin
- litert-lm
- llama.cpp
- openai-chat-completions
- paddleocr
- python
- react
- sglang
- typescript
Log in or sign up for Devpost to join the conversation.