I Built a Website Tracker This Weekend — Here's What I Learned

Published: (December 31, 2025 at 01:37 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

The Problem

I needed a tool that could:

  • Track which sites I visit most
  • Monitor site status (up/down) in real time
  • Organize sites by project/client
  • Show usage patterns and analytics
  • Keep everything local (no cloud, no accounts)

Existing solutions were either too complex, required sign‑ups, or lacked the features I needed.

The Solution: SiteOps

SiteOps is a vanilla JavaScript web app that runs entirely in the browser. All data stays in localStorage – no backend, no database, no accounts required.

  • Live Demo:
  • Source Code:

Tech Stack

  • Vanilla HTML / CSS / JavaScript – No frameworks, no build process
  • Chart.js – Analytics visualizations
  • localStorage – Client‑side data persistence
  • PWA‑ready – Installable as a web app

Key Features

1. Real‑Time Status Monitoring

Each website card shows live status (online/offline) with visual indicators.

async function checkWebsiteStatus(url) {
    try {
        const proxyUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`;
        const response = await fetch(proxyUrl, {
            method: 'GET',
            signal: controller.signal
        });
        return response.ok ? 'online' : 'offline';
    } catch (error) {
        return 'offline';
    }
}

2. Visit Tracking & Analytics

Tracks every visit with timestamps, device types, and patterns.

function visitWebsite(url) {
    const website = this.websites.find(w => w.url === url);
    if (website) {
        website.visits = (website.visits || 0) + 1;
        website.lastVisited = new Date().toISOString();

        // Track device type
        website.visitHistory.push({
            timestamp: new Date().toISOString(),
            deviceType: this.getDeviceType(),
            hour: new Date().getHours()
        });

        this.saveWebsites();
    }
    window.open(url, '_blank');
}

3. Comprehensive Analytics Dashboard

Built with Chart.js to visualize:

  • Visit trends over 30 days
  • Category breakdowns
  • Device usage (desktop / mobile / tablet)
  • Most visited websites
  • Peak usage hours and days

4. Local‑First Architecture

All data persists in localStorage.

function saveWebsites() {
    localStorage.setItem('websiteTracker', JSON.stringify(this.websites));
}

function loadWebsites() {
    const stored = localStorage.getItem('websiteTracker');
    return stored ? JSON.parse(stored) : [];
}

Challenges & Learnings

Challenge 1: CORS for Status Checking

Problem: Direct fetches are blocked by CORS.
Solution: Use the allorigins.win proxy.

const proxyUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`;

Learning: Browser security is strict for good reasons; client‑side monitoring requires work‑arounds.

Challenge 2: Responsive Design Without Frameworks

Problem: Building a complex, responsive dashboard with pure CSS.
Solution: CSS Grid with repeat(auto-fit, minmax()).

.websites-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 20px;
}

Learning: Modern CSS Grid handles most layouts without a framework.

Challenge 3: Data Persistence

Problem: Ensuring data survives browser restarts.
Solution: Save to localStorage after every action and provide export/import for backup.

Learning: localStorage is reliable but limited (~5‑10 MB). For larger datasets, IndexedDB is preferable.

Challenge 4: Real‑Time UI Updates

Problem: Updating the UI without a page refresh.
Solution: Event‑driven architecture with manual DOM updates.

function renderWebsites() {
    const filtered = this.getFilteredWebsites();
    grid.innerHTML = filtered.map(website => this.createWebsiteCard(website)).join('');
}

Learning: Vanilla JS can handle complex UIs, but state management becomes harder as the app grows.

Design Decisions

Why Vanilla JavaScript?

  • Simplicity: No build process, no dependencies
  • Performance: Fast load times, minimal bundle size
  • Learning: Deepens understanding of fundamentals
  • Portability: Works anywhere HTML/CSS/JS works

Why localStorage?

  • Privacy: Data never leaves the browser
  • Simplicity: No backend infrastructure needed
  • Speed: Instant saves/loads
  • Offline: Works without internet after the first load

Why Chart.js?

  • Easy integration: CDN, no build step
  • Good defaults: Professional look out of the box
  • Flexibility: Customizable when needed

Features That Make It Special

  • 5‑Star Rating System – Rate websites for quick reference
  • Keyboard Shortcuts – Power‑user friendly (Ctrl + N, Ctrl + F, etc.)
  • Export / Import – Backup data as JSON
  • Device Tracking – Desktop / mobile / tablet usage stats
  • Return‑Visit Rate – Analytics on repeat visits
  • Glassmorphism UI – Modern, clean design

What I’d Do Differently

  • IndexedDB – For larger datasets and better performance
  • Service Worker – True offline functionality and caching
  • WebSockets – Real‑time push updates for status monitoring

Real‑time Status Updates (if I added a backend)

  • Testing – Add unit tests for core functionality
  • TypeScript – For better code maintainability

Try It Out

Visit the live demo and:

  • Add a few websites
  • Visit them a few times
  • Check out the analytics dashboard
  • Export your data

All your data stays in your browser — completely private and local.

Open Source

SiteOps is open source and available on GitHub. Contributions welcome!

Final Thoughts

Building SiteOps taught me:

  • Vanilla JS can build complex apps
  • localStorage is powerful for local‑first apps
  • Good UX matters more than frameworks
  • Sometimes the best solution is the simplest one

If you’re tracking multiple websites, give SiteOps a try. And if you have feedback or suggestions, I’d love to hear them!

Tags: #javascript #webdev #productivity #opensource #pwa #localstorage #analytics #webdevelopment

Back to Blog

Related posts

Read more »

Your Boring Stack Isn't Boring Enough

!Alex Towellhttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2F...