Analy is an open-source tracker & dashboard for website analytics.
I've been building this project in public on Twitter for quite a while now (got serious with it around mid-January).
And, so far I've been enjoying the journey!
Moreover, the product itself is fundamentally in working condition (both tracker script & dashboard web app)
In this post, I'll be talking about how I've been making decisions as I coded.
Starting with Remix (w/ TypeScript obviously!)
I've been always trying to get my hands on Remix.js until I got the idea for this project & it seemed like a perfect situation to try remix building a real-world project.
It is an interesting framework that had a sort of upper hand in the JS framework market (until Next.js 13 showed up) with Developer-friendly features like Router outlets, layouts, type-safe loaders/actions along with convenient hooks like useLoaderData
, useTransition
, etc. to access data.
After choosing the desired framework, I looked for which UI library to flavour it with.
Options that appealed the most to me were ChakraUI & Tailwind due to Chakra's vast library of rich components & well, tailwind being... tailwind.
For the most part, Tailwind & Chakra worked together like a charm, but there was one disadvantage to using CharkaUI, Its bundle size.
And to this day I continue to use ChakraUI simply because I haven't found any better UI library with smaller-sized tree-shakeable components.
β Fast forward a month β
The dashboard app is looking something like this
And I'm starting to struggle with Remix. I prefer readable code over spaghetti code & especially when things are open-source with a teeny bit of chance of someone stopping by to understand or even contribute to the code.
Remix was making it harder for me to work with API endpoints.
Fetchers, types of loaders & actions & somewhat lack of flexibility in the framework, in my opinion, were what made me reconsider switching to Next.js.
So I did, spending the next 2-3 days migrating from Remix over to Next.js.
And not JUST Next.js this time, I migrated the app to the T3 stack.
Taking a chance on a library called tRPC (turns out IT IS AWESOME)
Now, I could've been biased here as I've worked with Next.js at every place that required SSR and known it more than any other framework so I may have been accustomed to the flexibility & freedom you get with it.
And tbh, Remix felt somewhat opinionated and I honestly was looking for something opinionated too (the one on the extreme side is Redwood.js), but after using it, I realized that I don't agree with many of these opinions (e.g Angular) & thus, Next.js felt much better.
Migrating to Create-T3-App
Let's move our focus towards why I chose specifically T3 stack and not just went with file-based API endpoint and then call them with fetch or even React query.
You see, when you write API endpoints in separate files & use something like fetch or react-query for more advanced features, you either have to manually define types for the data returned by these endpoints or just roll with the "any" type.
My goal on the other side, with building this open-source app, is to make the code as easy to read as possible (along with, of course, making the actual freakin' product)
This is exactly where tRPC comes into the picture.
It provides a way to infer the type of data returned by all the API routes you define in it which is exactly what I was looking for in a framework/library.
Because, TypeScript is best utilized NOT with manual type definitions, but with inferred types.
Talking more about tRPC, I love its 2 features that give a massive productivity boost:
Request Batching
tRPC groups requests while sending from the client to the server, this means it will ping your tRPC server endpoint only once for queries made at the same time and avoids duplicate requests.
Therefore, I can query the same route in multiple nested components and returned data will be shared among them instead of being fetched multiple times.React query
I absolutely love how react-query handles the querying state & manages it and with tRPC, I can access theuseQuery
of react-query effortlessly.
Also, I felt lazy setting up TypeScript, Tailwind, tRPC & Prisma all by myself so I created the Next.js app with create-t3-app
and it provided me with the basic boilerplate code to get me started.
It's been almost a month since I started to make some real progress with the t3 stack & so far, everything has been going really well.
And because Next when used with tRPC & react-query collectively solve my previous problems in Remix with data-fetching & state, I hope I hold on to this stack for a long time π
Current State of Analy
Analy Dashboard
The Analy Dashboard currently track basic analytics like date ranges for page views, the number of sessions & unique page visits along with real-time stats, top visited pages, top referrers and from the past week, user feedback too!
Here's a Twitter thread I wrote explaining the feedback-collecting functionality
Analy NPM Tracker Script
The script ensures total privacy for the user thus, uses no cookies,
Instead, anonymously identifies users & their sessions with self-generated ids.
It currently tracks some default events like page loads, new users along with the capability to track custom events with a callable function trackEvent
or via HTML attributes analy-event
& analy-dom-event
to specify the event name & dom event name (e.g "click" or "hover") respectively.
What's Next?
Future plans are to integrate advanced features into the dashboard like custom events & session recordings to create & analyze funnels in order to understand more about dropoffs & where those dropoffs are happening.
Everything I do is posted on my Twitter as threads β¨
Thanks for reading!
I hope you enjoyed this little post about me talking about my experience building my first open-source SaaS product in public - Analy π
I love talking to strangers and my DMs are always open to interesting ideas & feedback π€
Some relevant links are thrown here:
Twitter - BhardwajKuvam
Analy Dashboard Source Code - kuvamdazeus/analy-dashboard
Analy Tracker Script Source Code - kuvamdazeus/analy
Top comments (0)