repos
/ analytics-rust master

analytics-rust

mirror archived upstream

Single-binary self-hosted website analytics on Rust axum: collector API, dashboards, world map, and PDF reports.

analyticsaxumdockerrustself-hostedsqliteviteweb-analytics

6.3 KB · 162 lines · HTML Raw History
  1{% extends 'base.html' %}
  2
  3
  4{% block extra_head %}
  5{% include "includes/social.html" %}
  6{% endblock %}
  7
  8
  9{% block extra_css %}
 10<link href="{{ vite_asset('static_src/pages/index.js', 'css') }}" rel="stylesheet">
 11{% endblock %}
 12
 13
 14{% block breadcrumb_wrapper %}{% endblock %}
 15
 16
 17{% block main %}
 18<section class="hero">
 19  <div class="container">
 20    <div class="row">
 21      <div class="col-12 col-lg-7">
 22        <span class="hero-eyebrow">
 23          <span class="eyebrow-dot" aria-hidden="true"></span>
 24          v0.1.0 · alpha · self-hosted
 25        </span>
 26        <h1 class="hero-title">
 27          Website analytics for operators who host their <span class="accent">own pipeline</span>.
 28        </h1>
 29        <p class="hero-sub">
 30          Page views, clicks, scrolls, sessions, and custom events. GeoIP maps,
 31          UTM attribution, device and browser breakdowns, period-over-period
 32          comparisons, and PDF reports. Collected through a single POST
 33          endpoint you control. No third-party script, no hidden trackers,
 34          no data leaving your infrastructure.
 35        </p>
 36        <div class="hero-ctas">
 37          <a href="/login" class="btn btn-primary">Access dashboard →</a>
 38          <a href="/documentation" class="btn btn-outline-light">Docs</a>
 39          <a href="https://github.com/overshard/analytics-rust" target="_blank" class="btn btn-outline-light">View source</a>
 40        </div>
 41      </div>
 42      <div class="col-12 col-lg-5 mt-5 mt-lg-0 d-flex align-items-center">
 43        <div class="terminal-block w-100">
 44          <span class="t-line"><span class="t-comment"># collector push</span></span>
 45          <span class="t-line"><span class="t-prompt">site$</span><span class="t-out">POST /collect/</span></span>
 46          <span class="t-line"><span class="t-key">event</span>=<span class="t-val">page_view</span> <span class="t-key">url</span>=<span class="t-val">/pricing</span></span>
 47          <span class="t-line"><span class="t-key">referrer</span>=<span class="t-val">bing.com</span></span>
 48          <span class="t-line"><span class="t-key">geo</span>=<span class="t-val">US · CA</span> <span class="t-key">ua</span>=<span class="t-val">firefox · linux</span></span>
 49          <span class="t-line"><span class="t-prompt">site$</span> <span class="t-cursor"></span></span>
 50        </div>
 51      </div>
 52    </div>
 53  </div>
 54</section>
 55
 56<section class="stat-strip">
 57  <div class="container">
 58    <div class="row g-4">
 59      <div class="col-6 col-md-3">
 60        <div class="stat">
 61          <div class="stat-label">properties</div>
 62          <div class="stat-value">{{ total_properties }}</div>
 63        </div>
 64      </div>
 65      <div class="col-6 col-md-3">
 66        <div class="stat">
 67          <div class="stat-label">events logged</div>
 68          <div class="stat-value">{{ total_events }}</div>
 69        </div>
 70      </div>
 71      <div class="col-6 col-md-3">
 72        <div class="stat">
 73          <div class="stat-label">operators</div>
 74          <div class="stat-value">{{ total_users }}</div>
 75        </div>
 76      </div>
 77      <div class="col-6 col-md-3">
 78        <div class="stat">
 79          <div class="stat-label">collecting since</div>
 80          <div class="stat-value" style="font-size: 1.05rem;">
 81            {% if first_event_created_at %}{{ first_event_created_at }}{% else %}—{% endif %}
 82          </div>
 83        </div>
 84      </div>
 85    </div>
 86  </div>
 87</section>
 88
 89<section class="container my-5 py-4">
 90  <div class="row g-4">
 91    <div class="col-12 col-md-6 col-lg-4">
 92      <div class="feature">
 93        <div class="feature-label">collection</div>
 94        <div class="feature-title">One-line site tag</div>
 95        <p class="feature-desc">
 96          Drop a tiny async script in your <code>&lt;head&gt;</code>. It posts
 97          session_start, page_view, click, scroll, and page_leave to one
 98          endpoint. Custom events queue from any frontend code.
 99        </p>
100      </div>
101    </div>
102    <div class="col-12 col-md-6 col-lg-4">
103      <div class="feature">
104        <div class="feature-label">attribution</div>
105        <div class="feature-title">UTM + referrer tracking</div>
106        <p class="feature-desc">
107          Slice traffic by source, medium, and campaign. Top referrers,
108          pages, and custom events rank in the dashboard with
109          period-over-period deltas baked in.
110        </p>
111      </div>
112    </div>
113    <div class="col-12 col-md-6 col-lg-4">
114      <div class="feature">
115        <div class="feature-label">geo + device</div>
116        <div class="feature-title">Maps, browsers, platforms</div>
117        <p class="feature-desc">
118          A Natural Earth world map with click-through admin-1 drill-down.
119          Doughnut breakdowns for device, browser, platform, and screen
120          size. GeoIP runs locally, IPs never leave your host.
121        </p>
122      </div>
123    </div>
124    <div class="col-12 col-md-6 col-lg-4">
125      <div class="feature">
126        <div class="feature-label">reports</div>
127        <div class="feature-title">Dashboard + PDF export</div>
128        <p class="feature-desc">
129          Flip any date range to PDF or markdown with one click, rendered
130          in-process via embedded Typst (no chromium subprocess). Custom
131          cards pin bespoke metrics. A public toggle shares without a login.
132        </p>
133      </div>
134    </div>
135    <div class="col-12 col-md-6 col-lg-4">
136      <div class="feature">
137        <div class="feature-label">schema</div>
138        <div class="feature-title">Typed schema, JSON extras</div>
139        <p class="feature-desc">
140          Hot fields (url, referrer, geo, UA, UTMs) live in typed columns
141          for fast queries. Custom keys land in an <code>extra</code> JSON
142          column, queryable via SQLite JSON1 (json_extract). Bot traffic
143          routes to a separate table at write time so human dashboards
144          never have to filter it.
145        </p>
146      </div>
147    </div>
148    <div class="col-12 col-md-6 col-lg-4">
149      <div class="feature">
150        <div class="feature-label">stack</div>
151        <div class="feature-title">Built in Rust, ultralight</div>
152        <p class="feature-desc">
153          One statically linked Rust binary plus SQLite, shipped as a tiny
154          Alpine Docker image behind your own reverse proxy. Your domain,
155          your retention policy. No vendor, no pixel, no lock-in.
156        </p>
157      </div>
158    </div>
159  </div>
160</section>
161{% endblock %}