Hey there! 👋
I've been working on this new analytics tool (Analyzr) for a few weeks and would like to share it with you.
In just one line of code, your analytics are up and running—instantly.
There is also real-time stats and no limitations with notifications on Discord, plus Analyzr is completely free and open source.
This is a complete breakdown of how I built it and the features it offers.
TL;DR 🚀
Analyzr does not charge for its services and has an open-source base code with minimal hassle to implement – just a single line.
- Free and Open-Source
- Quick and Simple Setup
- Comprehensive Analytics
- Discord Notifications
- Lightweight, Secure and Versatile
The way this is built is such that it removes the barriers of complexity as well as cost.
The end goal for Analyzr is to provide a faster and easier tool for all developers, small companies, and creators who want to monitor their website performance.
📑 Table of Contents
- Why Did I Build This?
- How Did I Build This?
- Who Is This For?
- What Can It Do?
- How Does It Work?
- Discord Integration
- Custom Event Tracking
- What Makes This Different?
- Want to Try It?
- FAQs
Why Did I Build This? 💡
Let's be honest—most analytics tools feel like a total trap.
And as a developer, I was frustrated by expensive, overcomplicated analytics tools.
I wanted something that’s simple, free, and works out of the box.
It's beyond frustrating, and honestly? It shouldn’t be like this.
That’s exactly why I created Analyzr. I wanted to make analytics simple, affordable, and accessible for everyone.
No paywalls. No hidden fees. Just the insights you actually care about.
Whether you're curious about where your visitors are coming from, what buttons they're clicking, or how fast your website is loading, Analyzr has your back.
And the best part? It's completely free.
I wanted something that’s easy for anyone to use.
Whether you’re a developer, a small business owner, or just someone with a website, Analyzr is for you.
No need to deal with complicated setups or pricey subscriptions. Just add a line of code, and you’re all set.
Analytics should be straightforward and stress-free. That's the aim.
How Did I Build this? 🛠️
I'm super excited to share the behind-the-scenes story of how I built Analyzr.
Let me break it down for you in the most honest way possible.
Tech Stack and Schema
First things first - let me tell you about the tech stack I chose.
I went with:
- Next.js 15 & React 19
- Supabase for the database
- shadcn/ui for the components and charts
- Discord.js for notifications
and this final schema structure:
Tracking Script - Internal Working
Okay, this is where things got really interesting (and by interesting, I mean I spent way too many late nights debugging).
The tracking script is probably the most crucial part of Analyzr.
It's what collects all the data about website visits, user behaviour, and more.
- Tracks page views
- Figures out what device and browser people are using
- Gets location data
You can see the core tracking logic here:
async function trigger(eventName, options) {
try {
const locationData = await getUserLocation();
const operatingSystem = getOperatingSystem();
const deviceType = getDeviceType();
const { browserName } = getBrowserInfo();
var payload = {
event: eventName,
url: location.href,
domain: dataDomain,
source,
city: locationData.city,
region: locationData.region,
country: locationData.country,
operatingSystem,
deviceType,
browserName,
};
sendRequest(payload, options);
} catch (error) {
console.error('Error in trigger:', error);
}
}
I spent a ridiculous amount of time making sure this was as lightweight as possible. And it paid off, the whole script is less than 6KB.
Tracking Performance with Google PageSpeed Insights API
Here's how the "website performance" magic happens:
const apiUrl = `https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodedUrl}&category=performance&category=accessibility&category=best-practices&category=seo&key=${API_KEY}`;
Before moving ahead, you should know that this API returns this massive JSON object with ALL the metrics you could ever want.
But of course, we need to make sense of it:
const metrics: PerformanceMetrics = {
firstContentfulPaint: Math.round(data.lighthouseResult.audits['first-contentful-paint'].numericValue),
largestContentfulPaint: Math.round(data.lighthouseResult.audits['largest-contentful-paint'].numericValue),
timeToInteractive: Math.round(data.lighthouseResult.audits['interactive'].numericValue),
cumulativeLayoutShift: Math.round(data.lighthouseResult.audits['cumulative-layout-shift'].numericValue * 1000),
totalBlockingTime: Math.round(data.lighthouseResult.audits['total-blocking-time'].numericValue),
performance: Math.round(data.lighthouseResult.categories.performance.score * 100),
accessibility: Math.round(data.lighthouseResult.categories.accessibility.score * 100),
bestPractices: Math.round(data.lighthouseResult.categories['best-practices'].score * 100),
seo: Math.round(data.lighthouseResult.categories.seo.score * 100),
speedIndex: Math.round(data.lighthouseResult.audits['speed-index'].numericValue),
};
The next thing: I needed to find a way to combine various metrics into something meaningful.
The secret? I take the average of each metric and then categorize the results based on those averages.
function PerformanceScoreCard({ metrics }: { metrics: PerformanceMetrics }) {
const calculateOverallScore = () => {
const scores = [
metrics.performance,
metrics.accessibility,
metrics.bestPractices,
metrics.seo
].filter(score => score !== null);
if (scores.length === 0) return null;
return Math.round(scores.reduce((a, b) => (a ?? 0) + (b ?? 0), 0) / scores.length);
};
}
export const getCategory = (score: number) => {
if (score >= 90) return {
label: 'EXCELLENT',
color: 'text-green-500',
bg: 'bg-green-500/20',
isGood: true
};
if (score >= 80) return {
label: 'GOOD',
color: 'text-blue-500',
bg: 'bg-blue-500/20',
isGood: true
};
if (score >= 70) return {
label: 'AVERAGE',
color: 'text-yellow-500',
bg: 'bg-yellow-500/20',
isGood: false
};
if (score >= 50) return {
label: 'POOR',
color: 'text-orange-500',
bg: 'bg-orange-500/20',
isGood: false
};
return {
label: 'CRITICAL',
color: 'text-red-500',
bg: 'bg-red-500/20',
isGood: false
};
};
Additionally, I'll display improvement cards when one or more metrics decline.
export const getRecommendations = (metrics: PerformanceMetrics) => {
const recommendations = [];
if (metrics.performance < 90) {
recommendations.push({
title: "Speed Optimization",
description: "Consider optimizing images and implementing caching strategies",
metric: metrics.performance,
icon: "⚡"
});
}
if (metrics.firstContentfulPaint > 1800) {
recommendations.push({
title: "First Contentful Paint",
description: "Reduce server response time and minimize render-blocking resources",
metric: `${(metrics.firstContentfulPaint / 1000).toFixed(1)}s`,
icon: "🎨"
});
}
if (metrics.accessibility < 90) {
recommendations.push({
title: "Accessibility",
description: "Improve ARIA labels and contrast ratios",
metric: metrics.accessibility,
icon: "♿"
});
}
if (metrics.cumulativeLayoutShift > 0.1) {
recommendations.push({
title: "Layout Stability",
description: "Reduce layout shifts by specifying image dimensions",
metric: metrics.cumulativeLayoutShift.toFixed(3),
icon: "📏"
});
}
if (metrics.seo < 90) {
recommendations.push({
title: "SEO Optimization",
description: "Ensure all pages have meta descriptions and proper heading structure",
metric: metrics.seo,
icon: "🔍"
});
}
if (metrics.totalBlockingTime > 300) {
recommendations.push({
title: "Interactivity",
description: "Reduce JavaScript execution time and split long tasks",
metric: `${(metrics.totalBlockingTime / 1000).toFixed(1)}s`,
icon: "⌛"
});
}
return recommendations.slice(0, 6);
};
Example:
Database Actions
The database structure was... well, let's just say it evolved quite a bit from my initial design.
I started with a super simple schema and kept adding to it as I realized I needed more features.
Here's what happens when data comes in:
- The tracking script sends data to our API
- We process it and store it in Supabase
- The data gets organized into different tables for:
- Page views
- Custom events
- Performance metrics
- User sessions
One of the cooler features I implemented was real-time analytics. Check out how the data gets processed: (this is on the UI side)
const processData = () => {
const data: Record<string, { date: string; pageViews: number; visits: number }> = {};
// Process visits
visits
.filter(visit => filterDataByTimePeriod(new Date(visit.created_at)))
.forEach(visit => {
const timestamp = visit.created_at;
if (!data[timestamp]) {
data[timestamp] = { date: timestamp, pageViews: 0, visits: 1 };
} else {
data[timestamp].visits++;
}
});
// Process pageViews
pageViews
.filter(view => filterDataByTimePeriod(new Date(view.created_at)))
.forEach(view => {
const timestamp = view.created_at;
if (!data[timestamp]) {
data[timestamp] = { date: timestamp, pageViews: 1, visits: 0 };
} else {
data[timestamp].pageViews++;
}
});
// Sort by timestamp
const sortedData = Object.values(data).sort(
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
);
// Group the data based on time period
const groupedData = groupByTimeUnit(sortedData, timePeriod);
// Sort the final data
return Object.values(groupedData).sort((a, b) => {
if (a.date.includes('AM') || a.date.includes('PM')) {
// Sort hours
const hourA = parseInt(a.date.split(' ')[0]);
const ampmA = a.date.split(' ')[1];
const hourB = parseInt(b.date.split(' ')[0]);
const ampmB = b.date.split(' ')[1];
if (ampmA === ampmB) return hourA - hourB;
return ampmA === 'AM' ? -1 : 1;
} else {
return new Date(a.date).getTime() - new Date(b.date).getTime();
}
});
};
Client-Side UI
The UI was both fun and challenging to build.
I wanted to make something that looked professional but also felt friendly and approachable.
Some of my favorite parts:
- The dashboard layout (which took way too many iterations to get right)
- The analytics charts (shadcn UI X Recharts is amazing!)
- The custom event tracking UI
Who Is This For? 🎯
Whether you’re a developer, small business owner, or just someone running a side project, Analyzr is built for you.
- Developers: Track your apps or personal projects effortlessly.
- Business owners: Monitor traffic and performance without expensive tools.
- Anyone: Need analytics? Custom events? I've got you covered.
What Can It Do? 🚀
Here’s a quick overview of what Analyzr brings to the table:
- Real-Time Tracking: You can see live stats of what’s happening on your site.
- Custom Events: Keep an eye on specific actions, like when users click buttons.
- Performance Insights: Track how fast your pages load and get tips on how to make ‘em better.
- Visitor Stats: Find out what devices, browsers, and locations your visitors use.
- Discord Alerts: Get instant alerts in Discord about traffic spikes, errors, or other important events - as you set it.
It’s analytics, but way simpler!
How Does It Work? 🤔
- Add the tracking script to your site.
- It gathers data and sends it safely to our Supabase database.
- Just log in to your dashboard to check out the charts and stats.
Are you curious about how it works? For the source code, take a look at our GitHub repo!
Discord Integration 🤖
Discord integration is one of Analyzr's cool features. You can:
- Notifies you when website traffic spikes
- You can track any custom event or errors.
- Get real-time updates on the go without having to constantly check your dashboard.
It takes just a couple of minutes to set one up so that you won't miss any beat.
Custom Event Tracking 📊
One of Analyzr's powerful features is custom event tracking.
Here's how easy it is:
Using JavaScript/Node.js:
Using Python:
Once you’re all set up, you can:
- Track any custom event, which occurs on your website
- Receive notifications to Discord to be informed when such occurrences take place
- It is also useful to go ahead and add some custom fields and emojis to make those notifications look a little better.
- And of course, watch all these events in your dashboard.
And guess what?
Unlike other analytics tools that charge fees for tracking custom events, Analyzr offers this feature for free!
What Makes This Different? 💪
- It’s Free: No trials, no fees—free forever.
- Super Easy Setup: One line of code, and you’re good to go.
- Discord Notifications: Stay in the loop without lifting a finger.
- Open-Source: You can customize it however you want.
Want to Try It? 📦
It's super easy to get started:
1. Add the Tracking Script
For Vanilla/React apps(index.html):
For Next.js apps(layout.tsx):
2. Deploy your app to production.
3. aannnddd.... It's done!
After you are done, start seeing real analytics on your dashboard.
FAQs ❓
Is it really free?
Yep! No fees, and no premium features—it’s all free.
Will it slow down my site?
Not at all. Our tracking script is lightweight and async.
Is my data secure?
Absolutely! Your data stays private and can be deleted anytime.
Can I use it with any platform?
Yes, it works with Next.js, React, Vue, plain HTML, and more.
Final Thoughts ✨
Analyzr is here to simplify analytics for everyone.
Exciting news! Analyzr is releasing tomorrow, i.e. 24th November @ 1:31 PM IST (12:01 AM PST), so watch out for the launch on Product Hunt!
Try it, star it, and let me know what you think.
For detailed setup instructions and advanced features, check out our documentation!
Check it out on Analyzr, view the source on GitHub, or see our launch on Product Hunt!
Have questions or ideas?
Drop an issue on GitHub, DM me on X @ArjunCodess or Discord @ArjunCodess.
I'd love to hear from you!
Happy tracking! 📊
Thanks for 32383!
Top comments (1)
Great work man 🔥