DEV Community

Dan Oluwatunmibi
Dan Oluwatunmibi

Posted on

I Built Full Source-Attributed Analytics for Indie Developers — No Third-Party Tools

Rubies Unleashed Project Analytics Page

When I started building Rubies Unleashed — an open publishing platform for indie games, apps, and tools — I knew eventually I'd need analytics. Creators publishing their work deserve to understand how it's performing.

What I didn't want to do was bolt on Google Analytics or Mixpanel. Not because of cost. Because they answer the wrong questions.

GA tells you how many people visited a URL. I wanted to tell creators why someone arrived — was it through the Explore page? A search result? Someone's public profile? A spotlight feature? An external link from another site?

That's a fundamentally different question. And it requires building from scratch.

Here's what I built, how it works, and what creators can now see on Rubies Unleashed.


The architecture

Every view is tracked through a custom track_project_view RPC in Postgres. It takes four arguments: project ID, a hashed visitor fingerprint, traffic source, and user type (authenticated or guest).

The deduplication logic is simple: one view per visitor per day per project. The hash is derived from IP + user agent and never stored in plain text. No cookies. No persistent identifiers.

Downloads work the same way — a separate download_events table, same deduplication logic, same source attribution.

View counts are incremented by a database trigger (trg_view_count), not inside the RPC itself. That keeps the RPC fast and the count logic centralized.


Source detection

The trickiest part was getting source attribution right across the platform.

Every internal link that points to a project page gets a ?from= parameter injected at the point of navigation:

  • Explore page → ?from=explore
  • Search results → ?from=search
  • A creator's profile → ?from=profile
  • The homepage feed → ?from=feed
  • The weekly digest email → ?from=editors_choice
  • A spotlight feature → ?from=spotlight

On the project page, a sourceDetector.js utility reads ?from= first, then falls back to document.referrer for external traffic. After capturing the source, the URL is cleaned via window.history.replaceState so the parameter doesn't persist in the user's browser history.

Eight sources in total: explore, profile, search, direct, external, feed, spotlight, editors_choice.


What creators can see

Every published project now has a dedicated analytics page at /{username}/dashboard/project/{id}/analytics.

Stat cards — views, downloads, wishlists, average rating, conversion rate (views → downloads). Period toggle: 7 days, 30 days, all time.

Sparkline charts — SVG charts showing daily views and downloads. 7-day view shows Sun–Sat with today highlighted and future days dimmed. 30-day view shows six 5-day buckets.

Traffic sources — horizontal bar chart showing what percentage of views came from each of the 8 sources. This is the data I find most useful as a builder: knowing that 60% of your views are coming from the Explore page vs 30% from external links tells you something very different about how people are finding your work.

Audience section — authenticated users vs guests, unique viewer count, total views, views per unique user ratio. Tells you if you have a small loyal audience or broad shallow reach.

Engagement funnel — views → wishlists → downloads. Horizontal funnel showing the conversion at each stage.

Reviews section — average rating, per-star distribution bars, total review count.

Reports section — if your project has been flagged by the community, you see it here. Flagged reason, status, date. Full transparency.

Recognition section — whether your project has Editor's Choice status, your save rate (wishlists / views), your download conversion rate.


Creator overview

Beyond per-project analytics, every creator has an overview page at /{username}/analytics.

Aggregate stats across all published projects. Combined sparklines for total views and downloads this week. Traffic sources and audience split for the last 30 days across all your projects. And a sortable breakdown table — click any row to jump straight to that project's analytics.


What's not tracked (intentionally)

Downloads from trusted external platforms — Steam, Google Play, App Store — skip the warning modal and therefore skip download tracking. This is a known gap. Users clicking to a trusted platform don't need a safety warning, but that means we lose the click data. I'll fix this with a lightweight beacon instead of the modal, but it's not done yet.

HTML5 embeds aren't tracked as downloads either. Also on the list.


Why I built it this way

The alternative was Plausible, Fathom, or just Google Analytics. Fast to set up. Zero maintenance.

But I wanted creators to have source-level data that third-party tools can't provide, because third-party tools don't know the internal structure of the platform. They don't know that a view came from the Editor's Choice spotlight vs a search result. They just see a pageview.

Building it in Postgres means the analytics data lives next to the content data. Joins are free. The project_analytics view aggregates everything — total views, 7d/30d breakdowns, source distribution, audience split — in a single query. The API route checks ownership before returning anything.

It's more work. But it's the right kind of data.


Current state

80 projects live. 67 creators. Every single one of them now has per-project analytics and a creator overview dashboard.

No paywalls. No tiers. No "analytics is a Pro feature."

rubiesunleashed.app


Daniel Oluwatunmibi — Founder, Rubies Unleashed. Building open infrastructure for indie creators.

Top comments (0)