repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

5.7 KB · 142 lines · HTML Raw History
  1{{ define "extra_head" }}{{ template "social" . }}{{ end }}
  2{{ define "extra_css" }}{{ range .PageStyles }}<link href="{{ . }}" rel="stylesheet">{{ end }}{{ end }}
  3{{ define "breadcrumb_bar" }}{{ end }}
  4{{ define "main" }}
  5<section class="hero">
  6  <div class="container">
  7    <div class="row">
  8      <div class="col-12 col-lg-7">
  9        <span class="hero-eyebrow">
 10          <span class="eyebrow-dot" aria-hidden="true"></span>
 11          v0.1.0 · alpha · self-hosted
 12        </span>
 13        <h1 class="hero-title">
 14          Website analytics for operators who host their <span class="accent">own pipeline</span>.
 15        </h1>
 16        <p class="hero-sub">
 17          Page views, clicks, scrolls, sessions, and custom events. GeoIP maps,
 18          UTM attribution, device and browser breakdowns, and PDF reports. One
 19          POST endpoint you run. Your data never leaves your infrastructure.
 20        </p>
 21        <div class="hero-ctas">
 22          <a href="/login" class="btn btn-primary">Access dashboard →</a>
 23          <a href="/documentation" class="btn btn-outline-light">Docs</a>
 24          <a href="{{ .SourceURL }}" target="_blank" rel="noopener" class="btn btn-outline-light">View source</a>
 25        </div>
 26      </div>
 27      <div class="col-12 col-lg-5 mt-5 mt-lg-0 d-flex align-items-center">
 28        <div class="terminal-block w-100">
 29          <span class="t-line"><span class="t-comment"># collector push</span></span>
 30          <span class="t-line"><span class="t-prompt">site$</span><span class="t-out">POST /collect/</span></span>
 31          <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>
 32          <span class="t-line"><span class="t-key">referrer</span>=<span class="t-val">bing.com</span></span>
 33          <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>
 34          <span class="t-line"><span class="t-prompt">site$</span> <span class="t-cursor"></span></span>
 35        </div>
 36      </div>
 37    </div>
 38  </div>
 39</section>
 40
 41<section class="stat-strip">
 42  <div class="container">
 43    <div class="row g-4">
 44      <div class="col-6 col-md-3">
 45        <div class="stat">
 46          <div class="stat-label">properties</div>
 47          <div class="stat-value">{{ num .TotalProperties }}</div>
 48        </div>
 49      </div>
 50      <div class="col-6 col-md-3">
 51        <div class="stat">
 52          <div class="stat-label">events logged</div>
 53          <div class="stat-value">{{ num .TotalEvents }}</div>
 54        </div>
 55      </div>
 56      <div class="col-6 col-md-3">
 57        <div class="stat">
 58          <div class="stat-label">operators</div>
 59          <div class="stat-value">{{ num .TotalUsers }}</div>
 60        </div>
 61      </div>
 62      <div class="col-6 col-md-3">
 63        <div class="stat">
 64          <div class="stat-label">collecting since</div>
 65          <div class="stat-value" style="font-size: 1.05rem;">
 66            {{ if .FirstEventAt }}{{ .FirstEventAt }}{{ else }}—{{ end }}
 67          </div>
 68        </div>
 69      </div>
 70    </div>
 71  </div>
 72</section>
 73
 74<section class="container my-5 py-4">
 75  <div class="row g-4">
 76    <div class="col-12 col-md-6 col-lg-4">
 77      <div class="feature">
 78        <div class="feature-label">collection</div>
 79        <div class="feature-title">One-line site tag</div>
 80        <p class="feature-desc">
 81          Drop a small async script in your <code>&lt;head&gt;</code>. It posts
 82          page views, clicks, scrolls, sessions, and custom events to one
 83          endpoint.
 84        </p>
 85      </div>
 86    </div>
 87    <div class="col-12 col-md-6 col-lg-4">
 88      <div class="feature">
 89        <div class="feature-label">attribution</div>
 90        <div class="feature-title">UTM + referrer tracking</div>
 91        <p class="feature-desc">
 92          Slice traffic by source, medium, and campaign. Referrers, pages, and
 93          custom events rank with period-over-period deltas.
 94        </p>
 95      </div>
 96    </div>
 97    <div class="col-12 col-md-6 col-lg-4">
 98      <div class="feature">
 99        <div class="feature-label">geo + device</div>
100        <div class="feature-title">Maps, browsers, platforms</div>
101        <p class="feature-desc">
102          A Natural Earth world map with admin-1 drill-down, plus device,
103          browser, and platform breakdowns. GeoIP runs locally so addresses
104          stay on your host.
105        </p>
106      </div>
107    </div>
108    <div class="col-12 col-md-6 col-lg-4">
109      <div class="feature">
110        <div class="feature-label">reports</div>
111        <div class="feature-title">Dashboard + PDF export</div>
112        <p class="feature-desc">
113          Flip any date range to PDF or markdown in one click, rendered in
114          process by Typst. Custom cards pin whatever metric you want.
115        </p>
116      </div>
117    </div>
118    <div class="col-12 col-md-6 col-lg-4">
119      <div class="feature">
120        <div class="feature-label">schema</div>
121        <div class="feature-title">Typed schema, JSON extras</div>
122        <p class="feature-desc">
123          Hot fields live in typed columns for fast queries, and custom keys
124          land in an <code>extra</code> JSON column. Bot traffic routes to its
125          own table at write time.
126        </p>
127      </div>
128    </div>
129    <div class="col-12 col-md-6 col-lg-4">
130      <div class="feature">
131        <div class="feature-label">stack</div>
132        <div class="feature-title">One Go binary and a file</div>
133        <p class="feature-desc">
134          Go and SQLite, shipped as one small Alpine image behind your own
135          reverse proxy. Your domain, your retention policy.
136        </p>
137      </div>
138    </div>
139  </div>
140</section>
141{{ end }}