Go Completely Offline: Build a Privacy-First Personal Finance Assistant with LiteRT and Gemma 4 A developer has created a privacy-first personal finance assistant that runs entirely offline in the browser using LiteRT's LM Web API and the Gemma 4 E2B small language model. The application caches model weights in the browser's Cache Storage and processes transactions on-device with IndexedDB, ensuring complete privacy and zero token costs. The project, available on GitHub, demonstrates a three-phase approach including arithmetic grounding to prevent hallucination and conversation management to stay within browser token limits. Imagine having a personal financial planner that analyzes your sensitive transaction history, flags spending anomalies, and suggests budget optimizations—all while running 100% offline, directly inside your web browser. In this guide, we will build an offline Retrieval-Augmented Generation RAG assistant powered by the LiteRT LM Web API and the highly efficient, on-device Gemma 4 E2B small language model. By caching the model weights directly in the browser's Cache Storage, your application will achieve complete privacy, zero token costs, and genuine offline capability. While Angular and TailwindCSS provide the user interface and styling, the LiteRT LM Web API and the on-device small model power this demo's AI capabilities. npm i --save-exact @litert-lm/core tailwindcss postcss @tailwindcss/postcss jsonrepair dexie npm i --save-exact --save-dev angular-eslint husky lint-staged serve @commitlint/cli We install additional dependencies for on-device AI, CSS Styling, JSON response streaming, and IndexedDB storage. The dev dependencies help automatically catch code smells, enforce code quality, and serve the production bundle. We designed this application to process transactions entirely on-device, ensuring financial data privacy inside the browser. The process operates in three key phases: Model and Data Storage: First, the application downloads and caches the Gemma 4 E2B model weights directly in the browser's Cache Storage so they are available offline. When users log expenses, they are saved locally in IndexedDB. Arithmetic Grounding: Small models hallucinate when processing arithmetic queries, so we aggregate expenses into a monthly total, a daily total, and an expense-by-category breakdown. We supply the precomputed values to the Gemma WebGPU engine as ground truth, along with the user query. Conversation Management: To prevent exceeding browser token limits, the application resets the conversation after three turns but retains a client-side memory of the last two queries. On reset, the application re-primes the model with immutable financial grounding data before replaying those queries. This maintains conversational continuity while keeping memory usage within on-device limits. Next, let's look at how we instantiate this LiteRT LM engine, define the insight service, and design the Angular user interfaces to generate these insights. While the full codebase is available in the NG Personal Finance Assistant https://github.com/railsstudent/ng-on-device-expense-tracker repository, our application relies on an IndexedDB database to track expenses offline. You can find the database implementation in the service file https://github.com/railsstudent/ng-on-device-expense-tracker/blob/main/src/app/core/services/database.service.ts , which is injected via an injection token https://github.com/railsstudent/ng-on-device-expense-tracker/blob/main/src/app/core/consts/app-database.const.ts and initialized at startup using provideAppInitializer https://github.com/railsstudent/ng-on-device-expense-tracker/blob/main/src/app/app.config.ts L18 . With this local database configured to log expenses, we can now focus on the AI integration. The following sections illustrate how to cache the Gemma 4 weights and leverage Angular 22's reactive features to generate secure, local insights directly from this transaction data. Running LLMs locally in the browser requires two steps: Caching the Weights: Storing the model weights ~2GB in the browser's Cache Storage so the application can run 100% offline. Engine Bootstrapping: Creating a single, reusable instance of the LiteRT LM engine so we can stream responses with WebGPU speed and avoid costly re-initialization latencies. When discussing on-device AI, people often assume offline operation, zero server dependency, and total privacy. However, this is only partially true for Web AI. Most tutorials make a fetch request to retrieve the Gemma model from HuggingFace, which works well when online. This fails if the user's connection is unstable or unavailable. This illustrates the benefit of caching a small Gemma model in Cache Storage. The device only needs to be online once to download the model, and the application runs 100% offline. The demo has a download button for users to download the Gemma 4 E2B model that is around 2GB. After a successful download, go to Application Storage Usage to verify that the model occupies 2GB in storage. Let's implement this logic in AiModelCacheService : js export const AI CACHE NAME = 'JMWebAIModels'; export const DEFAULT MODEL FILENAME = 'gemma-4-E2B-it-web.litertlm'; export const GEMMA MODEL URL = https://huggingface.co/litert-community/gemma-4-E2B-it-litert-lm/resolve/main/${DEFAULT MODEL FILENAME} ; @Service export class AiModelCacheService { readonly modelUrl = GEMMA MODEL URL; readonly state = signal { status: 'not-downloaded' } ; async downloadModel : Promise