orchard
mirrorEvery 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
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><head></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 }}