Source & license
Upstream license: MIT
License TL;DR
You can use it, change it, self-host it and sell it. Keep the original copyright and license notice with copies of the code. You don’t have to publish your changes. The authors don’t promise it will work.
Explain MIT in plain English →Summary of the main license. Separate packages and assets can have different terms.
Inspect repository ↗Read this project’s actual license ↗Repository owner
See the upstream repository for the original creator and contributors.
Maintain this project? Maintainer verification →Cloudflare hosting
Free tier eligible within limits
The browser build can be statically hosted; the optional Cloudflare Worker/R2 sync relay can fit small Free request/CPU and standard R2 allowances. Local study does not need that relay. Additional folder-sync providers, if chosen, have separate limits and fees.
Hosting requirements
- The diagram distinguishes local browser storage from optional cloud synchronization; a configured R2 relay is not the application database.
- Keep relay CPU under 10ms/request and standard R2 under 10GB-month, 1M Class A and 10M Class B/month. No sync or native-client runtime was tested.
- Source and configuration review establishes a deployment path and conditional costs; this candidate was not executed or load-tested.
Sources checked 01/10/2026
Repository snapshot: 9e1b513. Hosting eligibility reflects the deployment documentation and listed assumptions.
- anki ↗
The web build is a Vite SPA that can be served by any static host (Nginx, GitHub Pages, Cloudflare Pages, etc.).
- workers ↗
name = "recall-sync-relay" main = "src/worker.ts" compatibility_date = "2024-09-01" [vars] ENVIRONMENT = "production" [[r2_buckets]] binding = "RECALL_SYNC" bucket_name = "recall-sync-blobs"
- r2 ↗
name = "recall-sync-relay" main = "src/worker.ts" compatibility_date = "2024-09-01" [vars] ENVIRONMENT = "production" [[r2_buckets]] binding = "RECALL_SYNC" bucket_name = "recall-sync-blobs"
- free-tier-eligible ↗
name = "recall-sync-relay" main = "src/worker.ts" compatibility_date = "2024-09-01" [vars] ENVIRONMENT = "production" [[r2_buckets]] binding = "RECALL_SYNC" bucket_name = "recall-sync-blobs"
- free-tier-eligible ↗
| **Free** | 100,000 per day | No charge for duration | 10 milliseconds of CPU time per invocation |
- free-tier-eligible ↗
| Storage | 10 GB-month / month |
- free-tier-eligible ↗
| Class A Operations | 1 million requests / month |
- free-tier-eligible ↗
| Class B Operations | 10 million requests / month |
- MIT ↗
MIT License Copyright (c) 2026 Madlezz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- architecture ↗
name = "recall-sync-relay" main = "src/worker.ts" compatibility_date = "2024-09-01" [vars] ENVIRONMENT = "production" [[r2_buckets]] binding = "RECALL_SYNC" bucket_name = "recall-sync-blobs"
- architecture ↗
your machine (SQLite desktop / IndexedDB browser) - JSON / `.recall` export - **Optional E2E cloud sync** - AES-256-GCM + PBKDF2; you deploy `sync-relay/` (Cloudflare Worker + R2) yourself - no maintainer-funded public relay - Optional folder sync (Dropbox, Drive, etc.) ### Customization - **6 accent colors** - zinc, blue, green, rose, amber, violet - **Dyslexia-friendly font** - **Dark / Light / High-contrast** - **English + Bahasa Indonesia** --- ## Quick Start ### Prerequisites - **Node.js** 22+ (dev pin: `.node-version` → 24.18.0) and **pnpm** 10+ - **Rust** stable (`rustup install stable`) for desktop builds - Platform libraries - see [CONTRIBUTING.md](CONTRIBUTING.md#prerequisites) ### Run ```bash pnpm install pnpm tauri dev # Desktop (Tauri) # or pnpm dev
- architecture ↗
name = "recall-sync-relay" main = "src/worker.ts" compatibility_date = "2024-09-01" [vars] ENVIRONMENT = "production" [[r2_buckets]] binding = "RECALL_SYNC" bucket_name = "recall-sync-blobs"
- architecture ↗
name = "recall-sync-relay" main = "src/worker.ts" compatibility_date = "2024-09-01" [vars] ENVIRONMENT = "production" [[r2_buckets]] binding = "RECALL_SYNC" bucket_name = "recall-sync-blobs"
Upstream screenshot · Madlezz/Recall repository contributors ↗. Depicts the upstream project. We have not deployed and tested a fresh installation here.
What it can replace
Compare the workflow you need. These mappings describe overlap; full feature parity requires a separate comparison.
Flashcard authoring and spaced-repetition study; no Anki add-on compatibility, deck migration guarantees or complete ecosystem parity.
See supporting source ↗How it works
The shape of Recall on Cloudflare, and how it stacks up against the rented tools it replaces.
Architecture
Diagram of deployment declarations at the reviewed commit. Each app has its own entrypoint; declared resources do not prove runtime calls. Follow file and line sources below.
View upstream source ↗Configuration and workflow sources
Reviewed commit 9e1b5131bfbf. Files were read as data; upstream applications and CI jobs were not executed.
Deployment configuration · 1 files
Cloudflare Workers · compatibility 2024-09-01
recall-sync-relay · default
Entrypoint: src/worker.ts
RECALL_SYNC→ R2
Named environments are separate deployments. Bindings are shown only where declared. Configured routes are URL patterns, not verified application endpoints.
Runtime source · handlers, binding usage and workflow steps
Observed TypeScript/JavaScript declarations from Worker entrypoints and resolved relative imports. Calls and workflow steps may run conditionally; their listed order is not a proven end-to-end request flow. Router declarations may be mounted under a prefix or may not be registered. This shows code wiring, not a successful deployment or runtime test. Dynamic wiring, aliases and generated code may not resolve.
- L54 · fetch handler exported · references RECALL_SYNC · calls corsHeaders, JSON.stringify, path.match, test, env.RECALL_SYNC.get, revisionOf, object.text, request.text, JSON.parse, env.RECALL_SYNC.head, stripEtagQuotes, request.headers.get, String, Number.parseInt, env.RECALL_SYNC.put, toISOString, env.RECALL_SYNC.delete, console.error
- L38 · stripEtagQuotes calls (conditional paths may differ): value.trim, t.startsWith, stripEtagQuotes, t.slice, t.endsWith
Environment references: env.RECALL_SYNC
Build and deployment pipeline · 4 GitHub Actions workflows
Repository CI declarations, separate from runtime request processing. Job dependencies and conditions are shown as written; long commands are shortened with an ellipsis; a workflow file does not prove a recent successful run.
Triggers: push, pull_request
check · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 - Shell command
pnpm install --frozen-lockfile - Lint
pnpm lint - Unit tests with coverage
pnpm test:coverage - Build
pnpm build
e2e · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 - Shell command
pnpm install --frozen-lockfile - Install Playwright browsers
npx playwright install --with-deps chromium - E2E tests
pnpm test:e2e
rust-audit · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - Install cargo-audit
for i in 1 2 3; do cargo install cargo-audit --locked && break echo "Attempt $i failed, retrying in 10s..." sleep 10 done - Audit Rust dependencies
cargo audit
rust-quality · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - Install Tauri system dependencies
sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - Rust fmt check
cargo fmt --check - Rust clippy
cargo clippy -- -D warnings - Rust tests
cargo test
Triggers: push, pull_request, schedule
Analyze JavaScript/TypeScript · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a
github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a - github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a
github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a - github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a
github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a
Analyze Rust · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a
github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a - Install Tauri system dependencies
sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a
github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a - github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a
github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a
Triggers: push, workflow_dispatch
build · no job dependencies declared
- actions/checkout@v7
actions/checkout@v7 - pnpm/action-setup@v6.0.9
pnpm/action-setup@v6.0.9 - actions/setup-node@v7
actions/setup-node@v7 - Shell command
pnpm install --frozen-lockfile - Build PWA
npx vite build --mode pages - Setup Pages
actions/configure-pages@v6 - Upload artifact
actions/upload-pages-artifact@v5
deploy · after build
- actions/deploy-pages@v5
actions/deploy-pages@v5
Triggers: push
build-tauri · no job dependencies declared
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - Install Linux dependencies
sudo apt-get update sudo apt-get install -y \ libwebkit2gtk-4.1-dev \ libappindicator3-dev \ librsvg2-dev \ patchelfCondition: matrix.platform == 'ubuntu-22.04' - pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 - dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c
dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c - swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4
swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 - Shell command
pnpm install --frozen-lockfile - tauri-apps/tauri-action@1deb371b0cd8bd54025b384f1cd735e725c4060f
tauri-apps/tauri-action@1deb371b0cd8bd54025b384f1cd735e725c4060f
checksums · after build-tauri
- actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - Download release assets
mkdir -p assets gh release download ${{ github.ref_name }} -D assets -p '*' - Generate SHA256SUMS
cd assets sha256sum * > SHA256SUMS cat SHA256SUMS - Upload SHA256SUMS
gh release upload ${{ github.ref_name }} assets/SHA256SUMS --clobber - Update release notes
gh api repos/{owner}/{repo}/releases/generate-notes \ -f tag_name=${{ github.ref_name }} \ --jq .body > notes.md gh release edit ${{ github.ref_name }} -F notes.md
build: tsc -b && vite build
deploy: wrangler deploy
Repository README
View original on GitHub ↗Full upstream document by @Madlezz · README.md · snapshot 9e1b513

Recall
Recall is FSRS-grade spaced repetition that makes you want to come back. No manual, no account, your data stays yours. Built-in streaks, XP, and focus rituals turn review into a habit - not a chore. Available as a desktop app (Windows / macOS / Linux) and a PWA on mobile.
Documentation
| Doc | What |
|---|---|
| Getting Started | First run, study loop, import |
| Architecture | App layers, DB, Tauri vs browser |
| Sync | Optional E2E self-host relay + folder sync |
| Deployment | Releases, PWA Pages, Worker |
| Card Formatting | Markdown, LaTeX, code, cloze |
| i18n | English + Bahasa Indonesia |
| Accessibility | Keyboard + screen reader |
| Roadmap | Planned work |
| Changelog | Version history |
| Contributing | Dev setup |
Why Recall?
Snapshot comparison for orientation only. Third-party products change - verify Anki / RemNote / Mochi in their own docs before relying on a cell. Anki version pin: 26.05 (upstream release tag as of mid-2026).
| Recall | Anki | RemNote | Mochi | |
|---|---|---|---|---|
| Built-in engagement | Yes (XP, streaks, levels, achievements, focus timer, match game) | Via community add-ons | Some engagement features | Minimal |
| No account, local-first | Yes (SQLite desktop, IndexedDB browser) | Local SQLite (+ optional AnkiWeb sync) | Cloud-first product with offline use | Local-first files; optional Pro sync |
| FSRS on by default | Yes | Legacy SM-2 by default; FSRS opt-in in deck options (Anki manual) | Spaced repetition in a notes app (scheduler details product-defined; check in-app) | Spaced repetition (commonly SM-2-style; check Mochi docs) |
| Open source | Yes (MIT) | Yes (AGPL) | No (proprietary) | App proprietary (some related OSS components) |
| Add-on ecosystem | None (planned) | Very large (long history) | Extensions / plugins (product-defined) | Limited vs Anki |
| Native desktop | Yes (Tauri + Rust) | Yes (Qt + Python) | Yes (desktop clients) | Yes (desktop clients) |
| Mobile | Installable PWA | AnkiMobile / AnkiDroid (separate apps) | Mobile apps | Mobile apps |
| Sync | Optional E2E (AES-256-GCM) via self-hosted relay, or folder/file sync - no maintainer-hosted cloud | AnkiWeb (not client-side E2E in the Anki sense); third-party options exist | Hosted product sync | Pro sync (see Mochi pricing/docs) |
| Stack | React + TypeScript | Python + Qt | React-based web/desktop | ClojureScript (historically) |
Anki pioneered desktop SRS and still has the deepest add-on ecosystem - that is an honest concession. Recall's edge is the habit loop: engagement features are native, not bolted on. FSRS on by default, local-first, MIT, TypeScript-friendly contributions, optional self-hosted E2E sync.
Screenshots
Dashboard - due cards, daily goal, deck grid:

Deck browser:

Deck detail - stats, tags, card list:

Study - card front:

Study - answer revealed + FSRS interval preview:

Stats - activity, retention, forecast:

Tags - hierarchical tree:

Card browser - search, filter, bulk actions:

Settings - theme, accent, language, TTS:

Recapture after UI changes:
pnpm devin one terminal, thennode scripts/take-screenshots.js.
Features
Smart Study
- FSRS scheduling - Again / Hard / Good / Easy
- Cloze deletion -
{{c1::hidden text}} - Rich cards - Markdown, LaTeX, syntax-highlighted code
- Anki import -
.apkg(review history + FSRS state) - CSV / Markdown /
.recallimport - Custom study - deck, count, tag filter, new-only
- Card browser - search, filter, sort, bulk tag/delete/move
- Tags - hierarchical tree, saved searches, autocomplete
- FSRS interval preview on rating buttons
- FSRS optimizer from review history
- Keyboard-first:
Spacereveal,1-4rate,Rreview,Ctrl+Nquick-add
Stay Motivated
- XP & levels - Curious Mind → Legend
- Achievements - streaks, volume, accuracy, time-based
- Daily goal + confetti on completion
- Session summaries
- Onboarding gallery - 6 starter decks
Study Tools
- Focus timer - 15 / 25 / 45m
- Ambient soundscapes - Rain, Cafe, Lofi (synthesized, no assets)
- Match game
- Review calendar heatmap
- Sound effects + optional TTS
- Swipe gestures on mobile
- Voice input in card editor (Web Speech API)
- Command palette -
Ctrl+K
Analytics
- Review volume, rating distribution, time-of-day
- Deck health - retention, leeches, overdue
- Activity heatmap, retention curve, 30-day workload forecast
Privacy First
- No account, no telemetry by default
- Offline on your machine (SQLite desktop / IndexedDB browser)
- JSON /
.recallexport - Optional E2E cloud sync - AES-256-GCM + PBKDF2; you deploy
sync-relay/(Cloudflare Worker + R2) yourself - no maintainer-funded public relay - Optional folder sync (Dropbox, Drive, etc.)
Customization
- 6 accent colors - zinc, blue, green, rose, amber, violet
- Dyslexia-friendly font
- Dark / Light / High-contrast
- English + Bahasa Indonesia
Quick Start
Prerequisites
- Node.js 22+ (dev pin:
.node-version→ 24.18.0) and pnpm 10+ - Rust stable (
rustup install stable) for desktop builds - Platform libraries - see CONTRIBUTING.md
Run
pnpm install
pnpm tauri dev # Desktop (Tauri)
# or
pnpm dev # Browser preview (no Rust)
PWA
Installable PWA: https://madlezz.github.io/Recall
Swipe left / right / up / down to rate after reveal.
Testing
pnpm test # Unit tests (806 as of 2026-07-18; count drifts)
pnpm lint # ESLint
pnpm build # tsc + Vite production build
pnpm test:e2e # Playwright (starts `pnpm dev` via config)
Download
Pre-built binaries on Releases (latest: v1.2.0):
| Platform | File |
|---|---|
| Windows | .msi |
| macOS (Apple Silicon) | .dmg |
| macOS (Intel) | .dmg |
| Linux | .AppImage |
Or build from source - Quick Start.
Security
Local-first: card data stays on device unless you enable sync.
- CI audits:
cargo audit, Dependabot, CodeQL on push/PR - Disclosure: SECURITY.md
Sync codes are E2E key material - never put them in exports or screenshots.
Keyboard Shortcuts
| Keys | Action |
|---|---|
Space |
Reveal answer |
1-4 |
Again / Hard / Good / Easy |
R |
Start review |
B |
Bury card |
S |
Snooze card |
Ctrl+N |
Quick-add (in-app) |
Ctrl+Shift+N |
Quick-add (global, desktop) |
Ctrl+Z |
Undo last review |
Ctrl+K |
Command palette |
T |
Toggle TTS |
? |
All shortcuts |
Contributing
See CONTRIBUTING.md.
good first issue- ROADMAP.md
- Open an issue before large PRs
Tech
| What | With |
|---|---|
| Desktop | Tauri 2 + Rust (rusqlite) |
| Mobile | PWA (vite-plugin-pwa) |
| UI | React 19 + TypeScript (strict) |
| Styling | Tailwind CSS + shadcn/ui primitives |
| Browser storage | Dexie |
| Desktop storage | SQLite via Tauri |
| State | Zustand |
| Algorithm | FSRS (ts-fsrs) |
| Sync | AES-256-GCM + PBKDF2; self-hosted Worker relay or folder sync |
| i18n | react-i18next |
| Icons | Lucide |
License
MIT © Madlezz
Frequently asked about Recall
What is Recall?+
Recall is a self-hosted Anki alternative built on the Cloudflare developer platform. Local-first spaced-repetition flashcards with an optional self-hosted sync relay
What does Recall replace?+
Recall is listed as an alternative to Anki. Compare the features and tradeoffs before migrating.
What Cloudflare primitives does Recall use?+
Recall is built on R2, Workers.
How much does Recall cost to run?+
The browser build can be statically hosted; the optional Cloudflare Worker/R2 sync relay can fit small Free request/CPU and standard R2 allowances. Local study does not need that relay. Additional folder-sync providers, if chosen, have separate limits and fees. The diagram distinguishes local browser storage from optional cloud synchronization; a configured R2 relay is not the application database. Keep relay CPU under 10ms/request and standard R2 under 10GB-month, 1M Class A and 10M Class B/month. No sync or native-client runtime was tested. Source and configuration review establishes a deployment path and conditional costs; this candidate was not executed or load-tested. Check current Cloudflare pricing before deploying.
Is Recall open source?+
The upstream repository declares the MIT license. Read its terms at https://raw.githubusercontent.com/Madlezz/Recall/9e1b5131bfbfe61aa3183edc0ac90dda66d13ac7/LICENSE. Source code and contributor credit are available at https://github.com/Madlezz/Recall.


Discussion · 0
sign in to comment →