Single-binary self-hosted website analytics on Rust axum: collector API, dashboards, world map, and PDF reports.
analyticsaxumdockerrustself-hostedsqliteviteweb-analytics
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 breadcrumbs %}
15<nav aria-label="breadcrumb">
16 <ol class="breadcrumb mb-0">
17 <li class="breadcrumb-item"><a href="/">Home</a></li>
18 <li class="breadcrumb-item active" aria-current="page">{{ page.title }}</li>
19 </ol>
20</nav>
21{% endblock %}
22
23
24{% block main %}
25<div class="container my-5">
26 <div class="row">
27 <div class="col-lg-8 offset-lg-2">
28 <div class="section-label mb-2">collector · recipes</div>
29 <h1 class="fw-bolder text-white" style="letter-spacing: -0.01em;">{{ page.title }}</h1>
30 <p class="docs-lead">
31 All events are sent as JSON to a single <code>POST /collect/</code>
32 endpoint. The site tag pushes page_view, click, scroll, and page_leave
33 automatically — everything else is a one-liner on
34 <code>collectorQueue</code>, or a raw HTTP call from any language.
35 </p>
36 </div>
37 </div>
38
39 <div class="row mt-4">
40 <div class="col-lg-8 offset-lg-2">
41 <div class="accordion docs-accordion" id="docsAccordion">
42
43 <div class="accordion-item">
44 <h2 class="accordion-header" id="headingOne">
45 <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
46 Collect custom clicks
47 </button>
48 </h2>
49 <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#docsAccordion">
50 <div class="accordion-body">
51 <p>Attach a handler to any interactive element. The event name is
52 whatever you want to measure later.</p>
53 <textarea class="codebox" rows="3" readonly>onclick="collectorQueue.push({event: 'signup_cta_click'})"</textarea>
54 </div>
55 </div>
56 </div>
57
58 <div class="accordion-item">
59 <h2 class="accordion-header" id="headingTwo">
60 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
61 Collect custom page views
62 </button>
63 </h2>
64 <div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#docsAccordion">
65 <div class="accordion-body">
66 <p>Use this for SPA route changes, funnel checkpoints
67 ("invoice paid"), or any meaningful page-level moment. Push
68 once per visit:</p>
69 <textarea class="codebox" rows="3" readonly><script>collectorQueue.push({event: 'checkout_success'});</script></textarea>
70 </div>
71 </div>
72 </div>
73
74 <div class="accordion-item">
75 <h2 class="accordion-header" id="headingThree">
76 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
77 Attach custom data to any event
78 </button>
79 </h2>
80 <div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#docsAccordion">
81 <div class="accordion-body">
82 <p>Every event is stored as JSON in an <code>extra</code>
83 column. Add whatever keys you need, no migration required,
84 query with SQLite JSON1
85 <code>json_extract(extra, '$.user_segment')</code> later.</p>
86 <textarea class="codebox" rows="3" readonly><script>collectorQueue.push({event: 'admin_page_view', data: {user_segment: 'admins'}});</script></textarea>
87 </div>
88 </div>
89 </div>
90
91 <div class="accordion-item">
92 <h2 class="accordion-header" id="headingFour">
93 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFour" aria-expanded="false" aria-controls="collapseFour">
94 Send events over raw HTTP
95 </button>
96 </h2>
97 <div id="collapseFour" class="accordion-collapse collapse" aria-labelledby="headingFour" data-bs-parent="#docsAccordion">
98 <div class="accordion-body">
99 <p>The collector endpoint is plain JSON — any HTTP client
100 will do. Include a valid <code>collector_id</code>,
101 <code>event</code>, and optional <code>data</code>.</p>
102 <textarea class="codebox" rows="4" readonly>curl -X POST -H 'Content-Type: application/json' \
103 -d '{"collector_id": "PROPERTY_COLLECTOR_ID", "event": "custom_app_event", "data": {"app_id": 4}}' \
104 YOUR_COLLECTOR_SERVER/collect/</textarea>
105 </div>
106 </div>
107 </div>
108
109 <div class="accordion-item">
110 <h2 class="accordion-header" id="headingFive">
111 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFive" aria-expanded="false" aria-controls="collapseFive">
112 Server-side events (Python)
113 </button>
114 </h2>
115 <div id="collapseFive" class="accordion-collapse collapse" aria-labelledby="headingFive" data-bs-parent="#docsAccordion">
116 <div class="accordion-body">
117 <p>Any backend, any library, any runtime. Here's a Python
118 example using <code>requests</code>:</p>
119 <textarea class="codebox" rows="5" readonly>import requests
120
121requests.post(
122 'YOUR_COLLECTOR_SERVER/collect/',
123 json={'collector_id': 'PROPERTY_COLLECTOR_ID',
124 'event': 'subscription_renewed',
125 'data': {'plan': 'pro', 'mrr': 49}}
126)</textarea>
127 </div>
128 </div>
129 </div>
130
131 </div>
132 </div>
133 </div>
134</div>
135{% endblock %}