← Documentation Home πŸš€ Try the App

Technical Specification - Instagram Unfollow Tracker

Version: 1.5.0 Last Updated: January 16, 2026

1. Project Overview

Goal

A privacy-focused, local web application that analyzes Instagram Data Download (ZIP) files to provide insights into follower relationships without requiring Instagram authentication or sending data to external servers.

Core Features

Privacy Principles


2. Technical Architecture

Frontend Stack

| Technology | Purpose | |β€”β€”β€”β€”|β€”β€”β€”| | React 18 | UI framework with hooks and functional components | | TypeScript | Strict mode, zero any types | | Vite | Build tool and development server | | vite-react-ssg | Static Site Generation (80+ pre-rendered pages) | | shadcn/ui | Composable UI components built on Radix UI | | Tailwind CSS | Utility-first styling with OKLCH color system | | Zustand | Lightweight state management (<1KB UI state only) | | i18next | Internationalization (11 languages) |

Data Storage & Processing

| Technology | Purpose | |β€”β€”β€”β€”|β€”β€”β€”| | IndexedDB v2 | Columnar storage with 40x compression | | FastBitSet.js | Bitwise filtering operations (75x faster) | | Comlink | Type-safe Web Worker communication | | TanStack Virtual | Virtual scrolling for 1M+ items at 60 FPS | | Web Workers | Off-thread filtering (INP: 180ms) |

Build & Deployment

| Technology | Purpose | |β€”β€”β€”β€”|β€”β€”β€”| | Vercel | Hosting with Edge Functions | | vite-plugin-pwa | PWA with 176 precached assets | | @fontsource | Self-hosted fonts (Inter, Plus Jakarta Sans) | | @vercel/og | Dynamic OG image generation |

Testing & Quality

| Technology | Purpose | |β€”β€”β€”β€”|β€”β€”β€”| | Vitest | Fast unit testing (1,601 tests) | | React Testing Library | Component testing | | @vitest/web-worker | Web Worker testing | | 98% coverage | Comprehensive test suite | | ESLint | Code quality (zero warnings) | | Husky | Git hooks for quality gates |


3. State Management

Zustand Store (<1KB constraint)

interface AppState {
  // Filter state
  filters: Set<BadgeKey>;
  setFilters: (filters: Set<BadgeKey>) => void;

  // Upload state
  uploadStatus: 'idle' | 'loading' | 'success' | 'error';
  uploadError: string | null;
  currentFileName: string | null;

  // File metadata (NOT account data)
  fileMetadata: FileMetadata | null;

  // Theme (3-way toggle)
  theme: 'light' | 'dark' | 'system';
  setTheme: (theme: 'light' | 'dark' | 'system') => void;

  // Hydration
  _hasHydrated: boolean;
}

Critical Constraints:

Language Detection (URL as Source of Truth)

// src/config/languages.ts
export const SUPPORTED_LANGUAGES = ['en', 'es', 'ru', 'de', 'pt', 'tr', 'hi', 'id', 'ja', 'ar', 'fr'];
export const RTL_LANGUAGES = ['ar'];

export function detectLanguageFromUrl(): SupportedLanguage {
  const pathname = window.location.pathname;
  const match = pathname.match(/^\/(en|es|ru|de|pt|tr|hi|id|ja|ar|fr)(\/|$)/);
  return match ? match[1] as SupportedLanguage : 'en';
}

4. IndexedDB v2 Architecture

Database: instagram-tracker-v2

Store Purpose Key
files File metadata registry hash
columns Username/href as packed Uint8Arrays ${hash}:${column}
bitsets Badge presence (1-bit per account) ${hash}:${badge}
timestamps Sparse time data for temporal badges ${hash}:timestamps
indexes Trigram/prefix search indexes (3-day TTL) ${hash}:search

Data Flow

Upload ZIP
    ↓
Parse Worker (Web Worker)
    β”œβ”€β”€ Extract ZIP (JSZip)
    β”œβ”€β”€ Parse JSON files
    └── Emit 10k account chunks
    ↓
IndexedDB Service
    β”œβ”€β”€ Pack columns (Uint8Array)
    └── Update bitsets (FastBitSet)
    ↓
Background: Build search indexes (trigram + prefix)
    ↓
Zustand: uploadStatus = 'success'

Filter Flow (via Web Worker)

FilterChips.onClick(badge)
    ↓
useFilterWorker.filterToIndices(query, filters)
    ↓
Web Worker (filter-worker.ts via Comlink)
    β”œβ”€β”€ Load bitsets (cached)
    β”œβ”€β”€ Intersect bitsets (FastBitSet.intersection)
    └── Apply search if query
    ↓
Result: number[] indices
    ↓
TanStack Virtual: render visible items (~20)
    ↓
useAccountDataSource: lazy load accounts by indices

5. Performance Specifications

Benchmarks (1M accounts)

Metric Target Achieved
Filter (single badge) <10ms ~3ms
Filter (3 badges) <10ms ~5ms
Search (indexed) <5ms ~2ms
Storage <20MB ~5MB
Memory (runtime) <20MB ~5MB
INP <200ms 180ms
LCP <2.5s ~1.3s

Optimization Strategies


6. Internationalization (i18n)

Supported Languages (11)

Language Code RTL Locale
English en β€” en_US
EspaΓ±ol es β€” es_ES
Русский ru β€” ru_RU
Deutsch de β€” de_DE
PortuguΓͺs pt β€” pt_BR
TΓΌrkΓ§e tr β€” tr_TR
ΰ€Ήΰ€Ώΰ€¨ΰ₯ΰ€¦ΰ₯€ hi β€” hi_IN
Bahasa Indonesia id β€” id_ID
ζ—₯本θͺž ja β€” ja_JP
Ψ§Ω„ΨΉΨ±Ψ¨ΩŠΨ© ar βœ… ar_SA
FranΓ§ais fr β€” fr_FR

SSG Architecture


7. File Structure

src/
β”œβ”€β”€ core/                 # Domain logic
β”‚   β”œβ”€β”€ types.ts          # Core types (Account, BadgeKey, etc.)
β”‚   β”œβ”€β”€ badges/           # Badge computation logic
β”‚   └── parsers/          # Instagram ZIP parsing
β”œβ”€β”€ lib/                  # Infrastructure
β”‚   β”œβ”€β”€ store.ts          # Zustand (UI state only!)
β”‚   β”œβ”€β”€ indexeddb/        # Columnar storage, bitsets
β”‚   β”œβ”€β”€ filtering/        # BitSet filter engine
β”‚   └── search-index.ts   # Trigram/prefix indexes
β”œβ”€β”€ config/               # Configuration
β”‚   └── languages.ts      # Language config (single source of truth)
β”œβ”€β”€ hooks/                # React hooks
β”‚   β”œβ”€β”€ useInstagramData.ts
β”‚   β”œβ”€β”€ useAccountFiltering.ts
β”‚   β”œβ”€β”€ useAccountDataSource.ts
β”‚   β”œβ”€β”€ useFilterWorker.ts      # Web Worker hook
β”‚   β”œβ”€β”€ useLanguageFromPath.ts  # Sync language from URL
β”‚   └── useLanguagePrefix.ts    # Get language prefix for nav
β”œβ”€β”€ workers/              # Web Workers
β”‚   └── filter-worker.ts  # IndexedDBFilterEngine (Comlink)
β”œβ”€β”€ pages/                # SSG page components
β”‚   β”œβ”€β”€ HomePage.tsx      # / route
β”‚   β”œβ”€β”€ WizardPage.tsx    # /wizard route
β”‚   β”œβ”€β”€ UploadPage.tsx    # /upload route
β”‚   β”œβ”€β”€ ResultsPage.tsx   # /results route
β”‚   └── ...               # 8 pages total
β”œβ”€β”€ components/           # UI components
β”‚   β”œβ”€β”€ ui/               # shadcn/ui primitives
β”‚   β”œβ”€β”€ Layout.tsx        # Root layout (ThemeProvider, Header, Footer)
β”‚   └── *.tsx             # App components
β”œβ”€β”€ locales/              # i18n translations
β”‚   β”œβ”€β”€ en/               # English
β”‚   β”œβ”€β”€ es/               # Spanish
β”‚   └── ...               # 11 languages
β”œβ”€β”€ routes.tsx            # SSG route definitions
β”œβ”€β”€ main.tsx              # ViteReactSSG entry point
└── __tests__/            # Tests (mirror structure)

8. Data Schema

Input Format (Instagram Data Download)

connections/followers_and_following/
β”œβ”€β”€ following.json              # Accounts you follow
β”œβ”€β”€ followers_1.json            # Your followers (may be split)
β”œβ”€β”€ close_friends.json          # Close friends list (optional)
β”œβ”€β”€ pending_follow_requests.json    # Pending requests (optional)
β”œβ”€β”€ recently_unfollowed_profiles.json  # Recently unfollowed (optional)
└── restricted_profiles.json    # Restricted accounts (optional)

Core Calculations


9. Browser Compatibility

Supported Browsers

Required Features


10. Security Considerations

Client-Side Security

Data Privacy


11. PWA Configuration

Workbox Strategy

Manifest

{
  "name": "Instagram Unfollow Tracker",
  "short_name": "Unfollow Radar",
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#000000"
}

12. Development Commands

npm run dev          # Dev server (http://localhost:5173)
npm run build        # Production build (SSG)
npm run test         # Run tests (Vitest)
npm run test:coverage # Tests with 85% threshold
npm run lint:strict  # ESLint (zero warnings)
npm run type-check   # TypeScript validation
npm run code:check   # lint:strict + type-check

This specification reflects v1.5.0 architecture. See CHANGELOG.md for version history.