xmr.club ask search guides
← home

Colophon

What runs xmr.club, why we picked it, and what we deliberately rejected. Public so anyone auditing the site (or wanting to fork it) doesn't have to guess.

Runtime

  • Cloudflare Workers — request-time SSR + JSON APIs. Chosen for first-byte latency at the edge (every public page rendered server-side; SPA hydrates after).
  • Cloudflare D1 — SQLite at the edge. Holds providers, audit log, reviews, sponsorships, onion-probe results. Read-replicated; writes serialised through the primary.
  • Cloudflare KV — small hot caches (rate-limit counters, idempotency keys, /ask classifier cache). Eventually-consistent; we never store anything we can't rebuild.
  • Cloudflare R2 — provider logos + OG images + the public /data.json snapshot. CC-BY-4.0; mirror-friendly.
  • Tor hidden service — independent Docker container on the same VPS as kyc.rip's onion, host-matched Caddy site block proxying to https://xmr.club with an X-Onion-Origin header so the worker can rewrite outbound links to provider .onions. Fingerprint published at /transparency.

Frontend

  • SSR-first. Every public page renders meaningful HTML before any JS executes. Tested with Tor's safest mode + Lynx + curl. AI-surface map exposes the plain-text twin of every page.
  • React + react-router-dom for interactive surfaces (admin, /q filters, /search). SSR is the floor; SPA is the upgrade. Pages that work better without JS (glossary, transparency, peers, this page) are SSR-only — the SPA shim hard-navs back to the server render so we never replace good HTML with empty client markup.
  • No CSS framework. One hand-rolled stylesheet at /src/styles.css. Monochrome on bg + a single accent. Three themes: light / dark / auto, switchable via cookie-based /toggle-theme route so noscript clients can flip too.
  • No analytics, no fingerprinting. No GA, no Plausible, no Cloudflare Web Analytics. We measure traffic via Cloudflare's request logs (already collected for the worker; not user-attributable).
  • Service worker registers on idle for network-first cache fallback. Failures are silent; the site works fine without it.

Data + content

  • Provider records live in D1, edited via the admin worker. Every state change writes an audit row (visible at /audit) and busts the relevant edge cache key.
  • Long-form guides are TypeScript modules under worker/guides.ts. We picked code over Markdown to get free type-checked cross-links, schema.org HowTo blocks, and per-guide TypeScript JSON-LD generation without a build step.
  • Logos are SVG where available, PNG fallback. Stored on R2, served with long Cache-Control + immutable hash in path.
  • Onion verification runs on a daily cron — fetches each listed provider's Onion-Location and diffs against our record. Drift is surfaced at /onion-audit.
  • Open data. /data.json + per-feed JSON twins. CC-BY-4.0. We test our own ingest path against it.

AI-engine surface

  • /llms.txt + /llms-full.txt — RFC-style index of every public surface for LLM crawlers.
  • Per-page plain-text twins at /llm/<page>.txt — same content, no chrome, structured for parsing.
  • JSON Feed v1.1 at /feed.json alongside Atom — preferred by modern crawlers.
  • Speakable schema on long-form pages — voice-assistant friendly summarisation hints.
  • Design choice: every assistant-cited surface points back to a canonical HTML URL and a plain-text twin, so we can be re-checked without scraping.

Editorial bot

  • @xmrclub_bot on Telegram — separate Cloudflare Worker at bot.xmr.club, no relation to the public site beyond a one-way notify webhook. DM forwards into a private support group; replies relay back. The curator's personal Telegram is not exposed.
  • Submissions, corrections, and sponsorship inquiries all flow through the bot or /submit. Both write to D1; the bot pings the support group via a shared-secret X-Bot-Notify header.

What we deliberately rejected

  • No paywall, no signup, no email gate. Authority comes from being public-checkable. A gated directory cannot be cross-verified.
  • No third-party tracking. No GA, no Hotjar, no Sentry session-replay. The price of a tracker is a privacy directory that doesn't believe its own thesis.
  • No client-side framework lock-in. SSR is the source of truth; the SPA is an enhancement we could rip out tomorrow without losing pages.
  • No build-step CMS. No Astro, no Next, no Gatsby. Content edits land in D1 and appear within one edge-cache TTL. Static rebuilds don't scale to per-provider audit timing.
  • No "AI-generated reviews". Every review on this site is hand-written by the curator. We use AI tools to draft schemas and audit code; we do not let an LLM grade a provider.

Stack we'd recommend to a fork

  • If you're starting from scratch and want the same shape: Cloudflare Workers + D1 + KV. ~$5/month all-in until you cross 10M req/day.
  • If you don't want Cloudflare: Bun + SQLite + Caddy works identically. SSR-first means edge isn't load-bearing — it's a latency optimisation.
  • If you want a static fork (no D1): export /data.json, render with anything. License is CC-BY-4.0 with attribution.

Operating cost (transparency)

Approximate monthly cost as of 2026-05: Cloudflare Workers + D1 + KV + R2 ≈ free tier (well under the 100k req/day limit). VPS for the Tor mirror is shared with kyc.rip; xmr.club's marginal cost is the onion-service container (~$0). Domain and the .onion vanity prefix are the only material spends. See /transparency for funding model.

Credits

See /heroes for the open-source projects and ecosystem actors xmr.club depends on. See /peers for the independent directories we cross-reference against.