Professional View Counter

Advanced serverless analytics with enterprise-grade admin management

โšก High Performance ๐Ÿ”’ Secure Admin ๐Ÿ“Š Advanced Analytics ๐Ÿ’ฐ Cost Optimized
API status: checking...
Current endpoint:
Checking domain routing...

๐Ÿ“Š Global Statistics

0
Total Views
0
Active Projects
0
Unique Visitors

โœจ Key Features

โšก

Ultra Fast

Optimized for minimal latency with intelligent caching and efficient database queries.

๐Ÿ”’

Secure Admin

Password-protected admin panel with environment-based configuration and role management.

๐Ÿ“Š

Rich Analytics

Detailed view tracking, visitor analytics, and comprehensive reporting dashboard.

๐Ÿ’ฐ

Cost Effective

Designed to stay within Cloudflare's free tier with optional premium features.

๐ŸŒ™

Dark Mode

Beautiful light and dark themes with smooth transitions and persistent user preferences.

๐ŸŽฏ

Easy Integration

Simple one-line webhook integration with RESTful API and auto-generated badges for any project.

๐Ÿš€ Live Demo

Try out the view counter with real-time updates

๐ŸŽฏ Quick Test

๐ŸŽจ Badge Generator

๐Ÿ“š Complete Documentation

Everything you need to integrate ViewFlare into your projects

๐Ÿš€ Quick Start ๐Ÿ“– API Reference ๐Ÿ’ก Examples โš™๏ธ Configuration

๐Ÿš€ Quick Start

Get your view counter running in under 2 minutes:

1. Basic Setup

// Step 1: Track a view (POST request) fetch('https://your-domain.com/api/views/my-project', { method: 'POST' }) .then(response => response.json()) .then(data => console.log('โœ… View tracked!', data.totalViews)); // Step 2: Display view count (GET request) fetch('https://your-domain.com/api/views/my-project') .then(response => response.json()) .then(data => { document.getElementById('view-count').textContent = data.totalViews; });

2. Add to Your HTML

<!-- View counter display --> <div> <span>Views: </span> <span id="view-count">Loading...</span> </div> <!-- Or use a badge --> <img src="https://your-domain.com/api/views/my-project/badge" alt="View Count" />

3. GitHub README Integration

# Add to your README.md ![Views](https://your-domain.com/api/views/my-repo/badge?color=blue&label=views) # With custom styling [![Project Views](https://your-domain.com/api/views/my-repo/badge?color=brightgreen&style=flat&label=project%20views)](https://your-domain.com)

๐Ÿ”— Complete API Reference

๐Ÿ“ˆ POST /api/views/{project-name}

Purpose: Increment view count for a project

Parameter Type Description Required
project-name string Unique project identifier (alphanumeric, hyphens, underscores, max 100 chars) โœ… Yes
// Request POST /api/views/my-awesome-project // Response (200 OK) { "success": true, "projectName": "my-awesome-project", "totalViews": 1337, "uniqueViews": 892, "timestamp": "2025-08-28T13:45:30Z" }

๐Ÿ“Š GET /api/views/{project-name}

Purpose: Get current statistics for a project

// Request GET /api/views/my-awesome-project // Response (200 OK) { "success": true, "projectName": "my-awesome-project", "totalViews": 1337, "uniqueViews": 892, "description": null, "createdAt": "2025-08-01T10:30:00Z" } // Response for non-existent project (initializes automatically with 0 views) { "success": true, "projectName": "new-project", "totalViews": 0, "uniqueViews": 0, "description": null, "createdAt": null }

๐ŸŽจ GET /api/views/{project-name}/badge

Purpose: Generate SVG badge with view count

Parameter Type Default Options / Description
color string blue blue, green, red, orange, purple, brightgreen, yellow
label string views Any custom text (URL encoded)
style string flat flat, flat-square, for-the-badge
inc boolean false Set to true to auto-track/increment views when the badge loads
// Basic badge GET /api/views/my-project/badge // Custom color, label, and auto-increment view tracker enabled GET /api/views/my-project/badge?color=brightgreen&label=downloads&inc=true // Response: SVG image (image/svg+xml) // Caching: Cached for 1 hour on Cloudflare Edge

๐Ÿ’Š GET /health

Purpose: Health check endpoint

// Response (200 OK) { "success": true, "status": "ok", "timestamp": "2025-08-28T13:45:30Z", "worker": "viewflare-api", "version": "2.4.0" }

๐Ÿงฉ Multi-Instance Setup (No Interference)

You can replicate this project for your own domain and data, completely isolated from this instance.

# 1) Fork and Clone the repository git clone https://github.com/Life-Experimentalist/ViewFlare.git cd ViewFlare # 2) Create your own Cloudflare Pages project + D1 DB # Configure your database bindings and ID in wrangler.toml # 3) Use your own custom domain (recommended) # Example: counter.yourdomain.com # 4) Keep your secrets unique # Set ADMIN_PASSWORD, DB binding, and project endpoints # 5) API calls auto-bind to current origin # The client dashboard uses window.location.origin automatically
Important: Do not hardcode counter.vkrishna04.me in your fork. Use your own domain and Cloudflare project settings to keep your data isolated.

โšก Integration Examples

๐ŸŒ JavaScript (Browser)

// Modern async/await approach async function trackView(projectName) { try { const response = await fetch(`/api/views/${projectName}`, { method: 'POST' }); const data = await response.json(); if (data.success) { console.log(`๐Ÿ“ˆ Views: ${data.totalViews}`); updateViewCounter(data.totalViews); } } catch (error) { console.error('โŒ Failed to track view:', error); } } // Get and display current stats async function displayViewCount(projectName) { try { const response = await fetch(`/api/views/${projectName}`); const data = await response.json(); document.getElementById('view-count').textContent = data.totalViews.toLocaleString(); document.getElementById('unique-count').textContent = data.uniqueViews.toLocaleString(); } catch (error) { console.error('โŒ Failed to load stats:', error); } } // Auto-track when page loads document.addEventListener('DOMContentLoaded', () => { trackView('my-website'); displayViewCount('my-website'); });

๐Ÿš€ Node.js (Server-side)

// Using fetch (Node.js 18+) async function trackServerView(projectName) { try { const response = await fetch(`https://your-domain.com/api/views/${projectName}`, { method: 'POST', headers: { 'User-Agent': 'YourApp/1.0.0' } }); const data = await response.json(); console.log(`โœ… Tracked view for ${projectName}: ${data.totalViews} total`); return data; } catch (error) { console.error('โŒ Tracking failed:', error); throw error; } } // Using Axios const axios = require('axios'); async function getProjectStats(projectName) { try { const { data } = await axios.get(`https://your-domain.com/api/views/${projectName}`); return { views: data.totalViews, unique: data.uniqueViews, created: data.createdAt }; } catch (error) { if (error.response?.status === 404) { return { views: 0, unique: 0, created: null }; } throw error; } }

๐Ÿ Python

# Using requests library import requests from typing import Dict, Optional class ViewCounter: def __init__(self, base_url: str): self.base_url = base_url.rstrip('/') def track_view(self, project_name: str) -> Dict: """Track a view for the given project.""" url = f"{self.base_url}/api/views/{project_name}" try: response = requests.post(url, timeout=5) response.raise_for_status() return response.json() except requests.RequestException as e: print(f"โŒ Failed to track view: {e}") return {"success": False, "error": str(e)} def get_stats(self, project_name: str) -> Dict: """Get current statistics for a project.""" url = f"{self.base_url}/api/views/{project_name}" try: response = requests.get(url, timeout=5) response.raise_for_status() return response.json() except requests.RequestException as e: print(f"โŒ Failed to get stats: {e}") return {"success": False, "error": str(e)} # Usage counter = ViewCounter("https://your-domain.com") result = counter.track_view("my-python-project") if result.get("success"): print(f"๐Ÿ“ˆ Total views: {result['totalViews']}")

๐Ÿฆ€ Rust

// Add to Cargo.toml: reqwest = { version = "0.11", features = ["json"] } use reqwest; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize)] struct ViewResponse { success: bool, #[serde(rename = "totalViews")] total_views: u32, #[serde(rename = "uniqueViews")] unique_views: u32, #[serde(rename = "projectName")] project_name: String, } async fn track_view(project_name: &str) -> Result<ViewResponse, reqwest::Error> { let url = format!("https://your-domain.com/api/views/{}", project_name); let client = reqwest::Client::new(); let response = client.post(&url).send().await?.json::<ViewResponse>().await?; Ok(response) }

๐ŸŽฏ Advanced Usage

โš™๏ธ Environment Configuration

Configure your ViewFlare instance with these environment variables:

Variable Default Description
ADMIN_PASSWORD admin123 Password for admin panel access
ENABLE_ADMIN true Enable/disable admin functionality
ENABLE_ANALYTICS false Enable detailed visitor tracking (uses more DB queries)
MAX_PROJECTS 100 Maximum number of projects to prevent abuse

๐Ÿ—๏ธ Self-Hosting

# Clone the repository git clone https://github.com/Life-Experimentalist/ViewFlare.git cd ViewFlare # Install dependencies npm install # Set up environment variables cp .env.example .env # Create Cloudflare D1 database npm run db:create npm run db:init # Deploy to Cloudflare Pages npm run deploy

๐Ÿ“Š Rate Limiting & Performance

// Implement client-side rate limiting class ViewTracker { constructor(cooldown = 60000) { this.cooldown = cooldown; this.lastTrack = new Map(); } async track(projectName) { const now = Date.now(); const last = this.lastTrack.get(projectName) || 0; if (now - last < this.cooldown) { console.log('โฑ๏ธ Cooldown active, skipping track'); return this.getStats(projectName); } this.lastTrack.set(projectName, now); return this.trackView(projectName); } async trackView(projectName) { // HTTP POST implementation } }

๐Ÿ”„ Batch Operations

// Track multiple projects efficiently async function trackMultiple(projects) { const promises = projects.map(project => fetch(`/api/views/${project}`, { method: 'POST' }) .then(r => r.json()) .catch(err => ({ success: false, project, error: err.message })) ); return await Promise.all(promises); }

๐Ÿ”ง Troubleshooting

โŒ Common Issues

Issue Cause Solution
CORS Error Cross-origin request blocked Use server-side tracking or proxy requests
404 Not Found Project name contains invalid characters Use alphanumeric characters, hyphens, underscores only
Admin Access Denied Wrong password or admin disabled Check ADMIN_PASSWORD environment variable
High Response Times Database not optimized Ensure D1 database is properly initialized

๐Ÿ› Debugging

// Enable detailed logging const DEBUG = true; async function debugTrack(projectName) { if (DEBUG) console.log(`๐Ÿ” Tracking view for: ${projectName}`); try { const start = performance.now(); const response = await fetch(`/api/views/${projectName}`, { method: 'POST' }); const duration = performance.now() - start; if (DEBUG) console.log(`โฑ๏ธ Request took: ${duration.toFixed(2)}ms`); const data = await response.json(); return data; } catch (error) { if (DEBUG) console.error('โŒ Error:', error); throw error; } }

โšก Performance & Limits

๐Ÿ“Š System Specifications

< 100ms
Average Response Time
1000+
RPS Capacity
99.9%
Uptime
1 Hour
Badge Cache

๐Ÿ’ฐ Cost Optimization

ViewFlare is designed to stay within Cloudflare's free tier limits:

  • Database: Optimized queries (1-3 per request)
  • Functions: Minimal compute time
  • Caching: 1-hour badge cache reduces load
  • Analytics: Optional to save resources

๐Ÿ”’ Security Features

# Security headers automatically included Access-Control-Allow-Origin: * Content-Security-Policy: default-src 'self' X-Content-Type-Options: nosniff # Rate limiting built-in Max requests per IP: 60/minute (webhook) Project name validation: Alphanumeric + hyphens/underscores (max 100 chars) # Privacy-friendly visitor tracking IP address hashing: SHA-256 with salt GDPR compliant (no personal data stored)

Self-Hosting Setup

Deploy your own ViewFlare in minutes. Each fork gets its own isolated D1 database โ€” completely separate from any other instance.

1

Fork & Clone

Fork the repo on GitHub, then:

git clone https://github.com/YOUR_USERNAME/cflair-counter.git cd cflair-counter
2

Install Dependencies

npm install
3

Create D1 Database

wrangler d1 create cflaircounter-db

Copy the output database_id and paste it into wrangler.toml.

4

Configure wrangler.toml

[[d1_databases]] binding = "DB" database_name = "cflaircounter-db" database_id = "YOUR_DATABASE_ID_HERE" [vars] ADMIN_PASSWORD = "your-secure-password-here" # Your deployment will be at: YOUR_ORIGIN
5

Initialize Schema

npm run db:init
6

Deploy

npm run deploy

After deploy, Cloudflare will show your Pages URL.

7

Custom Domain (Optional)

In your Cloudflare dashboard: Pages โ†’ your project โ†’ Custom domains โ†’ Add domain.

For external DNS, add a CNAME record pointing to your Pages subdomain (e.g. yourproject.pages.dev).

๐Ÿงช Test Your Deployment

After deploying, verify your instance is working: