sk2andy/candy-browser
Gesture-first Android browser with Material 3 Expressive design and local privacy tools
About sk2andy/candy-browser
sk2andy/candy-browser is an open-source project on GitHub, mainly written in Kotlin. Gesture-first Android browser with Material 3 Expressive design and local privacy tools It currently holds 536 stars and 18 forks with 46 open issues, and was last pushed on 2026-10-10 (repository created 2026-08-06).
Project Overview
Git Homed tracks it on the Today's Trending board, currently at rank #49 with 22 new stars today.
GitHub Repository Details
README
Candy Browser
Firefox extensions on Android, powered by GeckoView.
A gesture-first browser with selectable GeckoView and Android System WebView engines,
an iOS WKWebView/Liquid Glass target, and local privacy tools.
GitHub Pages website · Privacy · Releases
[!NOTE]
Next release: stability fixes. I'm focusing on finding and fixing as many bugs as possible
and testing the changes over an extended period to make Candy Browser more reliable.
🎉 Firefox extensions on Android
Candy uses GeckoView by default and supports Mozilla-signed Firefox extensions directly inside the Android app. A fresh Gecko profile comes with uBlock Origin and I still don't care about cookies, while additional compatible extensions can be installed and managed from Candy's browser settings.
Extension actions, popups, options, permissions, updates, and enable/disable controls stay inside Candy's browser chrome. See Platform engines for the supported GeckoView integration and current compatibility boundaries.
Cross-device sync
Candy Sync turns every connected Android, Chromium, or Firefox device into a writable profile. Open a desktop profile on your phone to inspect its live tab list, open new tabs, navigate, pin, reorder, or close them. The same small tab changes flow back to every connected client instead of re-uploading the complete browser state.
Changes are encrypted locally and written to a durable outbox. REST commits provide ordered, retry-safe storage; authenticated WebSocket notifications deliver committed changes immediately. After suspension or network loss, clients recover missing changes through REST.
E2EE in short
The first client creates a random 256-bit workspace key. The immutable passphrase derives a local recovery key with Argon2id; HKDF-SHA-256 derives purpose- and device-specific keys, and AES-256-GCM encrypts and authenticates tab data. Every device also creates its own P-256 private key locally. The passphrase, workspace key, private keys, URLs, titles, device names, and icons never reach the server in plaintext—the server stores ciphertext plus the routing metadata required for sync.
Start Candy Sync
cd sync/server
cp .env.example .env
Set a unique username, password, public URL, and TLS host in .env.
Never put the E2EE passphrase in server configuration.
docker compose pull candy-sync
docker compose up -d
The public sk2andy/candy-sync:latest image supports Linux AMD64 and ARM64. Contributors can still
build the server locally with docker compose up --build -d.
Build and load the WebExtension from sync/extension/, open its browser-managed Options Page, and
enter the endpoint plus an E2EE passphrase. In Candy Browser, open Settings → Synchronization
and join with the same endpoint, credentials, and passphrase.
See the Candy Sync guide for server deployment, local TLS, Chromium/Firefox loading, Android setup, backups, protocol details, and the full security model.
Candy Sync roadmap
- [ ] Add multi-user support
- [ ] Publish the extension to the Chrome Web Store and Mozilla Add-ons
- [x] Publish a prebuilt server image to Docker Hub
- [ ] Offer a hosted solution for people who do not want to self-host
See Candy in motion
Watch or download the 16:9 feature showcase (MP4, 60 fps)
After its gesture-first opener, the showcase moves straight to the Android engine choice and Firefox extensions. It then combines self-hosted Android/Chromium/Firefox tab sync with E2EE, live API 36 emulator footage, current Topping scripts, and repository screenshots to show Link Peek, Spoilerfree Sports, Hacker News Comfort, Privacy X-Ray, Reader Studio, Candy Trails, and profiles. Its original soundtrack, kinetic typography, and camera motion are generated entirely from repository-owned sources.
Why Candy?
- Made for gestures. Switch tabs from the address bar on phones, use a scrollable tab strip on
- Private by design. Filtering, history, favorites, profiles, and privacy telemetry stay local.
- Cross-device without surrendering your data. Self-hosted E2EE sync exposes desktop and Android
- Pick the engine that fits. Use GeckoView for Mozilla-signed Firefox extensions such as uBlock
- Feels at home on Android. Dynamic color, edge-to-edge content, Predictive Back, Autofill,
Architecture
Candy keeps browser behavior and production UI in shared Kotlin. The address bar, gestures, menus, tab switcher, Hero/Grid/List previews, settings structure, and their motion rules are not rebuilt for each platform. Small platform adapters connect that shared product layer to the native browser engine, image types, resources, haptics, and visual effects.
flowchart TD
K[Shared Kotlin behavior and state] --> C[Shared Compose UI and motion]
C --> A[Android platform adapter]
C --> I[iOS platform adapter]
A --> E{Selected Android engine}
E --> G[GeckoView sessions]
E --> S[System WebView sessions]
G --> F[Signed Firefox WebExtensions]
K --> T[Shared Topping model and grants]
T --> GT[Gecko userScripts host]
T --> ST[System WebView userScripts host]
T --> WT[WKUserScript host]
I --> W[WKWebView sessions]
W --> WT
Android defaults to GeckoView and can switch the whole app to Android System WebView from Browser settings. Candy checkpoints tab URLs and restarts into a fresh process, keeping tabs, bookmarks, history, profiles, and settings shared while cookies, logins, native back-forward lists, and other engine-owned session state stay separate. Firefox extensions remain available only in GeckoView; System WebView keeps Toppings and Candy protection. iOS uses WKWebView behind the same shared Kotlin contracts and Compose browser chrome, with native Liquid Glass supplied through an iOS effect adapter.
Implementation boundaries, invariants, and the current parity status are documented in Platform engines and Platform feature parity.
Tablet and Foldable support
At 600 dp and wider, the floating address bar shows a horizontally scrollable tab strip. Tap another tab to open it, or tap the current tab to edit its address. Configurable actions and the More menu stay in place. Horizontal swipes scroll the strip; the upward overview gesture remains. The visual tab overview also adapts its previews and grid to larger screens.

Tablet browsing with floating, scrollable tabs and website favicons.

Unfolded foldable layout with the same tab strip and fixed browser actions.
Features
Browsing and gestures
- Floating chrome over edge-to-edge browser-engine content, with configurable actions around the
- Pull to refresh, direct URL navigation, QR scanning, local domain completion, and optional
- Google, DuckDuckGo, Bing, Brave, Ecosia, Startpage, Qwant, Kagi, Perplexity, ChatGPT, and configurable SearXNG search
- Optional Google AI Mode routing through a toggleable address-bar logo, enabled from search settings
- Address commands with
>for tab, profile, cache, cookie, and navigation actions - Candy Recall: optional, profile-scoped local full-text search across visited pages from the
>recall, with no private-tab or cloud indexing
- Background tabs, sharing, printing, external apps, assistant summaries, and built-in or external
- Link Peek: long-press a link to inspect it in a live, disposable preview without creating a
- External Link Preview: optionally open links from other apps in a temporary Candy preview
Appearance and browser chrome
- System, light, dark, and AMOLED appearances with Material You, Candy, or neutral color palettes
- Clear or frosted browser surfaces plus angular, rounded, or extra-rounded shapes
- Independent transparency controls for general browser chrome and the address bar, with adjustable
Tabs, profiles, and journeys
- Persistent tabs with saved page previews, favicons, pinning, reordering, and automatic cleanup
- Coverflow, compact grid, and preview-free list layouts
- Candy Stacks: group compatible tabs by name and color, choose the stack preview,
- Tab snoozing with scheduled returns, notifications, and a dedicated snoozed-tab manager
- Per-profile browser-engine storage isolation with private sessions kept in memory
- Optional profile controls for a simpler single-profile setup
- Private tabs that keep their session and journey data in memory only
- Candy Trails: persistent branching navigation graphs with pan, zoom, direct navigation,
- Site Capsules: profile-bound home-screen shortcuts with configurable navigation boundaries
Reading and page tools
- Reader Studio: local article extraction with typography, alignment, paper and night themes,
- Find in page with live match counts and previous/next navigation that stays visible above the
- Toppings: Candy's lightweight, transparent alternative to traditional browser extensions.
GM_* APIs. The reviewed catalog lives in
candy-browser-toppings, so new Toppings do
not require a Candy Browser release
- Per-domain mute controls for silencing noisy sites
- Optional full immersive mode and a setting that prevents video autoplay
Firefox extension support
- A clean Android Gecko profile gets uBlock Origin and I still don't care about cookies by
- Existing installs are matched by Firefox extension ID and left unchanged. Disabling a default is
- Android can install Mozilla-signed Firefox extensions directly from an HTTPS XPI URL. Candy uses
- Failed installs retain GeckoView's reason: Candy distinguishes download, package integrity,
- Supported extension UI stays inside Candy's shared browser chrome: browser/page actions, popups,
- Candy supports the public WebExtension APIs exposed by the pinned GeckoView 155 runtime. This is
tabs.update({ muted: ... }) and tabs.update({ pinned: ... }) are rejected by GeckoView 155's
extension schema.
- See the tested Firefox WebExtension capability matrix
Pinned source URLs, versions, hashes, licenses, and delivery modes live in
app/src/gecko/assets/gecko_default_extensions/catalog.json. Maintainers verify local assets with
python3 scripts/generate_gecko_default_extensions.py verify, audit both upstream files with
python3 scripts/generate_gecko_default_extensions.py audit-remote, and refresh the bundled XPI
only with python3 scripts/generate_gecko_default_extensions.py refresh.
Media, fullscreen, and picture-in-picture
- Native fullscreen support for HTML5 and YouTube video, including rotation-aware Android system UI
- Automatic Android picture-in-picture when leaving Candy with an active regular-tab video
- Website picture-in-picture buttons for eligible top-level and fullscreen-capable embedded HTML5 video
- Google Cast playback for compatible direct HTML5 MP4, WebM, HLS and DASH video in regular tabs
- Seamless PiP entry and return without pausing or recreating the decoder surface, even when a site
- Draggable in-app mini-player when switching tabs, plus background audio playback where supported
- Android media notification and system controls for play, pause, stop, and seek
- Private-tab media remains transient and never enters PiP, the mini-player, or system media controls
Local protection
- EasyList/EasyPrivacy hosts and cosmetics, a pinned safely representable uAssets subset, and a
- Third-party-cookie blocking and cosmetic cookie-banner hiding
- Privacy X-Ray: live per-tab block counts, categories, domains, and exceptions
- Permission Radar: per-site camera, microphone, location, and other WebView permission activity
- Filter Studio: global or profile rules, import/export, and confirmed HTTPS subscriptions
- Safe Browsing, TLS failure handling, blocked unsafe schemes, and external-scheme allowlisting
Download
Candy Browser requires Android 13 (API 33) or newer.
Standard and User CA production builds check GitHub for updates at startup and offer a signed APK for download. Standard installs on ARM64 devices prefer the smaller ARM64 APK and fall back to the universal APK when needed. Both use the same application ID, version, and signing key, so either can update an existing standard install. The FOSS build disables this updater. Android still requires you to open a downloaded file and approve installation.
Obtainium
Use the filtered setup link so Obtainium always selects the standard certificate-trust channel:
The standard and User CA channels use separate application IDs, so both can stay installed and keep independent profiles, settings, and caches. Keep the asset filter: it prevents Obtainium from selecting a different channel than the configured app.
F-Droid
Candy includes a separately installable foss distribution flavor for the official F-Droid
repository. It uses the application ID dev.sk2andy.materialbrowser.foss, removes Google Play
services, Google Cast, Google Code Scanner, and Candy's GitHub update checker, and keeps its profiles,
settings, and caches isolated from the other channels. Remote search suggestions default to off.
F-Droid builds this variant from tagged public source and verifies it against Candy's upstream-signed
FOSS APK.
The isolated F-Droid listing starts with 0.37; older FOSS APKs used the universal application ID
and cannot become versions of the new package. Submission files and maintainer steps live in
distribution/fdroid. Candy publishes a signed FOSS reference APK
so F-Droid can verify its source build and preserve update compatibility with the upstream signing
key.
Releases contain four APK channels plus an architecture-optimized standard APK:
| APK suffix | Certificate trust | Intended use |
| --- | --- | --- |
| -release.apk | Android system CAs only | Universal compatibility fallback |
| -arm64-v8a-release.apk | Android system CAs only | Recommended smaller APK for ARM64 devices |
| -systemwebview-release.apk | Android system CAs only | Small, separately installed build using only Android System WebView |
| -foss-release.apk | Android system CAs only | F-Droid reproducible-build reference without proprietary Google integrations |
| -ca-release.apk | System CAs plus every CA in Android's user store | Explicit opt-in for HTTPS filtering/proxy tools such as AdGuard |
Both standard APKs use dev.sk2andy.materialbrowser and the same release signature. The System
WebView-only build uses dev.sk2andy.materialbrowser.systemwebview, the FOSS build uses
dev.sk2andy.materialbrowser.foss, and the User CA build uses
dev.sk2andy.materialbrowser.ca. Android therefore installs all four channels side by side with
isolated app data. Their launcher labels distinguish the channels; the warning under
Settings → Protection & data additionally identifies the User CA build's broader trust policy.
Updates stay on the installed channel. The System WebView build never downloads a GeckoView APK.
Releases through v0.36 used the standard application ID for all three APKs. Android cannot migrate
an installed package to a different application ID, so the isolated FOSS and CA channels start with
fresh app data. The new CA asset name is -ca-release.apk; legacy CA installs therefore do not get
offered an incompatible package as an in-place update.
Security warning: a trusted user CA can inspect and modify all HTTPS traffic made by Candy, including normal and private tabs, suggestions, filter subscriptions, and update metadata. Only install the User CA APK when you trust every CA in Android's user credential store and the software that controls its private key. APK signature verification still protects Candy updates from APKs signed by another key.
Advanced users who intentionally need this channel can use the filtered User CA Obtainium setup%7B1%2C2%7D-ca-release%5C%5C%5C%5C.apk%24%5C%22%7D%22%7D).
Build from source
Requirements: Android SDK 37.1 and JDK 17. Point JAVA_HOME to your JDK 17 installation.
./gradlew testFullDebugUnitTest lintFullDebug assembleFullDebug
To verify the F-Droid-compatible

