TidyMetrics
DOCUMENTATION

TidyMetrics docs

Overview

TidyMetrics is small, privacy-friendly analytics for SaaS. It counts visitors like any web analytics tool, then follows every Polar.sh payment back to the channel, campaign, page or in-app prompt that earned it.

Every number you can filter by — country, source, device, page, goal — comes with revenue next to it. So instead of "we got 4,000 visitors" you get "Hacker News brought 300 visitors and $2,400."

The dashboard overview with sample data
The dashboard overview with sample data

Getting started

TidyMetrics is open source and self-hosted. You run your own copy and sign in as the owner.

  1. Clone the repository from GitHub and deploy it to your own hosting.
  2. Connect a Postgres database with auth and run the included migrations.
  3. Turn on Google sign-in in your auth service and sign in. There's no sign-up page — it's just you.
  4. Open Setup, add your domain, and copy the snippet.
  5. Paste the snippet into your site, then connect Polar.sh.

Install the snippet

Add one script tag to the <head> of every page:

<script defer data-website-id="YOUR_WEBSITE_ID"
  src="https://your-tidymetrics.com/api/public/script.js"></script>

Pageviews, referrers, UTM tags and single-page app navigation are tracked automatically.

Site + app subdomains

Use one website for your marketing site and your app (for example wayflo.com and app.wayflo.com). Put the same snippet with the same ID on both. The visitor ID is shared across your root domain, so a visitor who arrives from Twitter, signs up, and later upgrades from a NudgeKit prompt is one journey — not two strangers.

Connect Polar.sh

  1. In Polar, go to Settings → Webhooks → Add endpoint.
  2. Paste the webhook URL from the Setup page, pick format Raw, and subscribe to order.created and subscription.created.
  3. Save Polar's signing secret as the POLAR_WEBHOOK_SECRET server secret. Unsigned requests are rejected.

For the most accurate attribution, pass the tracker's metadata into your checkout:

const meta = window.datafast.getMetadata();
// → { visitor_id, session_id, nudgekit_campaign_id }

await polar.checkouts.create({
  products: [productId],
  metadata: meta,
});

Identify users

Call this after sign-in or sign-up. If a payment arrives without metadata, TidyMetrics matches the buyer's email to the visitor.

window.datafast.identify(user.id, { email: user.email });

Dashboard

The top row shows unique visitors, pageviews, paying customers, revenue and revenue per visitor, each compared with the previous period. The chart shows visitors and revenue per day.

Below that are breakdown cards: sources and channels, pages, NudgeKit prompts, locations and technology, and goals. Every row shows revenue.

Breakdown cards: channels, pages, NudgeKit and countries
Breakdown cards: channels, pages, NudgeKit and countries

Channels & AI referrals

Each visit is grouped into a channel: AI assistants, Search, Social, Email, Paid, Referral or Direct. The AI tab lists ChatGPT, Perplexity, Claude and friends individually. Switch to Referrers, Source, Medium or Campaign for the raw values.

Filters

Click any row — a country, a channel, a page, a goal — and the whole dashboard filters to it. Remove the filter with the × on the chip above the numbers.

The dashboard filtered to visitors from the United States
The dashboard filtered to visitors from the United States

Goals & custom events

Track conversions that aren't payments, like a sign-up or a demo request. No code needed — add an attribute to a form or button:

<form data-track-goal="signup" data-track-prop-plan="free">
  ...
</form>

Or from JavaScript:

window.datafast.track("signup", { plan: "free" });

Goals appear in the Goals & custom events card with uniques, totals and conversion rate. Click one to see where those converters came from.

NudgeKit prompts

If NudgeKit is on your app, TidyMetrics picks up its events automatically. The NudgeKit card shows views, clicks, click rate and the revenue from people who clicked a prompt before paying. The In-app nudges tab has the full list.

Setup page

Add websites, copy the snippet (plain HTML or Next.js), and find your Polar webhook URL.

The Setup page
The Setup page

FAQs

How is revenue attributed?

Each payment gets the visitor's first-touch source (the referrer or UTM campaign that first brought them in) and, if they clicked a NudgeKit prompt before buying, that prompt as the last touch.

Does TidyMetrics use cookies?

Only one first-party visitor ID, scoped to your own domain so your site and app can share it. No ad networks, no cross-site tracking, no data brokers.

Why does a payment show up as Direct?

The buyer couldn't be matched to a visit. Pass window.datafast.getMetadata() into your Polar checkout metadata, or call identify() with their email after sign-in.

Which AI assistants are recognized?

ChatGPT, Perplexity, Claude, Gemini, Copilot, You.com, Phind, DeepSeek, Meta AI, Grok and Mistral — by referrer host or utm_source.

Will the script slow down my site?

No. It's about 3KB, loads with defer, and batches events with sendBeacon.

Are bots counted?

No. Common crawlers and headless browsers are filtered out on arrival.

Is there a hosted version?

No. TidyMetrics is open source — grab it from GitHub and run your own copy.