Where the store says what happened — as a port.
A store that cannot see its own funnel cannot be improved, and a store that ships its customers' payment details to an analytics vendor should not exist. Both facts are handled by the same seam: the pipeline emits DOMAIN events with named fields, and an adapter decides what leaves the building.
Ships with a no-op, a logger, an in-memory recorder for tests, and an Umami adapter — Umami because it is self-hostable, so the funnel of a Monero store need not be posted to an advertising network to be measured.
Where the store says what happened — as a port. A store that cannot see its own funnel cannot be improved, and a store that ships its customers' payment details to an analytics vendor should not exist. Both facts are handled by the same seam: the pipeline emits DOMAIN events with named fields, and an adapter decides what leaves the building. Ships with a no-op, a logger, an in-memory recorder for tests, and an Umami adapter — Umami because it is self-hostable, so the funnel of a Monero store need not be posted to an advertising network to be measured.
(composite sinks)Every one of sinks, in order. One that throws does not stop the others —
a broken vendor must not take the funnel down with it.
Every one of `sinks`, in order. One that throws does not stop the others — a broken vendor must not take the funnel down with it.
(track! this event)Record event, which is
{:event/name keyword — :checkout/opened, :invoice/settled, … :event/visitor an opaque, store-assigned id; never an email :event/variants {experiment variant} in force for this visitor :event/props a map of small, non-identifying values}
Must not throw: analytics is never a reason to fail a payment. Adapters swallow their own failures and say so in the log.
Record `event`, which is
{:event/name keyword — :checkout/opened, :invoice/settled, …
:event/visitor an opaque, store-assigned id; never an email
:event/variants {experiment variant} in force for this visitor
:event/props a map of small, non-identifying values}
Must not throw: analytics is never a reason to fail a payment. Adapters
swallow their own failures and say so in the log.(memory)Analytics that remembers, for tests. (events analytics) reads it back.
Analytics that remembers, for tests. `(events analytics)` reads it back.
(noop)Analytics that measures nothing. The default.
Analytics that measures nothing. The default.
(scrub props)props with every forbidden key removed, and every value reduced to
something countable.
Deliberately strict: an unrecognised value type becomes its class name rather than being passed through, because the failure mode of a permissive scrubber is silent and permanent.
`props` with every forbidden key removed, and every value reduced to something countable. Deliberately strict: an unrecognised value type becomes its class name rather than being passed through, because the failure mode of a permissive scrubber is silent and permanent.
(umami {:keys [client base-url website-id hostname user-agent]
:or {hostname "store" user-agent "monero-store/1.0"}
:as config})IAnalytics over a self-hosted Umami instance.
:base-url is the Umami origin, :website-id the site's uuid. Umami rejects
a request with no User-Agent, so one is always sent. Failures are logged and
swallowed: a customer paying an invoice does not care that a dashboard is
down.
IAnalytics over a self-hosted Umami instance. `:base-url` is the Umami origin, `:website-id` the site's uuid. Umami rejects a request with no User-Agent, so one is always sent. Failures are logged and swallowed: a customer paying an invoice does not care that a dashboard is down.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |