{
  "path": "/3mjagjjhp3s2g",
  "site": "at://did:plc:ofrbh253gwicbkc5nktqepol/site.standard.publication/3m3x4bgbsh22k",
  "tags": [
    "infra",
    "website"
  ],
  "$type": "site.standard.document",
  "title": "Self-Hosted Analytics with Umami",
  "content": {
    "$type": "pub.leaflet.content",
    "pages": [
      {
        "id": "019d7db7-6cd4-7997-9188-29fe75bd9a46",
        "$type": "pub.leaflet.pages.linearDocument",
        "blocks": [
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 85,
                    "byteStart": 80
                  },
                  "features": [
                    {
                      "uri": "https://umami.is",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "I added analytics to my sites. Not Google Analytics. Not a third-party tracker. Umami, running on my own infrastructure."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "The honest reason? I just like data. Charts, graphs, patterns – something about visualising information scratches an itch in my brain. I wanted to see what pages get visited, where people come from, what browser they're using. Not for optimisation or growth hacking. Just curiosity."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "For a while I ran ewancroft.uk with zero analytics. The stance was simple: I don't want to be tracked, so why would I track you? But the curious part of me wanted signal. Real data, not guesses from social engagement."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "What Umami Does Differently"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "The analytics industry normalised invasive tracking. Google Analytics is free because you're the product – your visitors' behavioural data gets folded into cross-site profiles. That's the bargain: give us your visitors' data, we'll give you charts."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "Umami breaks that:"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.unorderedList",
              "children": [
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "plaintext": "Self-hosted on my own hardware"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "plaintext": "No cookies"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "plaintext": "GDPR compliant – no cookie banner needed"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "plaintext": "Anonymised IPs"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "plaintext": "No cross-site tracking"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 11,
                          "byteStart": 0
                        },
                        "features": [
                          {
                            "uri": "https://github.com/umami-software/umami",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      }
                    ],
                    "plaintext": "Open source (AGPL-3.0)"
                  }
                }
              ]
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "What's collected: page URLs, referrer, browser, OS, country. That's it. No user IDs, no fingerprinting, nothing to sell."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "The Setup"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 34,
                    "byteStart": 21
                  },
                  "features": [
                    {
                      "uri": "https://www.dell.com/en-us/shop/dell-laptops/inspiron-15-3501-laptop/spd/inspiron-15-3501-laptop",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 83,
                    "byteStart": 73
                  },
                  "features": [
                    {
                      "uri": "https://www.postgresql.org/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 98,
                    "byteStart": 93
                  },
                  "features": [
                    {
                      "uri": "https://caddyserver.com/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 150,
                    "byteStart": 133
                  },
                  "features": [
                    {
                      "uri": "https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 241,
                    "byteStart": 220
                  },
                  "features": [
                    {
                      "uri": "https://search.nixos.org/options?channel=unstable&query=services.umami",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Umami runs on an old Inspiron 3501 laptop sitting on a shelf in my room. PostgreSQL backend, Caddy reverse proxy, exposed through my Cloudflare Tunnel. The whole thing took about 30 minutes to configure once I found the native nixpkgs module."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 75,
                    "byteStart": 57
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 112,
                    "byteStart": 92
                  },
                  "features": [
                    {
                      "uri": "https://www.postgresql.org/docs/current/auth-peer.html",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "The main gotcha was peer authentication. The module uses DynamicUser = true by default, but PostgreSQL peer auth requires the system username to match the database username. Small override and it was working."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 56,
                    "byteStart": 44
                  },
                  "features": [
                    {
                      "uri": "https://ewancroft.uk",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 75,
                    "byteStart": 58
                  },
                  "features": [
                    {
                      "uri": "https://docs.ewancroft.uk",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 98,
                    "byteStart": 77
                  },
                  "features": [
                    {
                      "uri": "https://malachite.croft.click",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 194,
                    "byteStart": 171
                  },
                  "features": [
                    {
                      "uri": "https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Adding the tracking script to each site – ewancroft.uk, docs.ewancroft.uk, malachite.croft.click – was a single line per domain with a unique UUID. I also updated the Content Security Policy on the main site to allow scripts from my analytics domain."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "Transparency"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 49,
                    "byteStart": 27
                  },
                  "features": [
                    {
                      "uri": "https://analytics.ewancroft.uk",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "The dashboard is public at analytics.ewancroft.uk. Nothing to hide because nothing sensitive is collected. If I were tracking something I didn't want public, that would be a privacy breach for visitors."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 27,
                    "byteStart": 15
                  },
                  "features": [
                    {
                      "uri": "https://en.wikipedia.org/wiki/Do_Not_Track",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Umami respects Do Not Track. Enable it in your browser and nothing gets sent."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "The Trade-off"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "I'm not claiming this makes my sites perfectly private. Embedded content has its own data practices. But for the analytics layer, the part I control, I've made the most privacy-respecting choice available."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 111,
                    "byteStart": 97
                  },
                  "features": [
                    {
                      "uri": "https://www.raspberrypi.com/products/raspberry-pi-5/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "The hardware costs nothing – it's repurposed kit that would otherwise gather dust. Moving to a Raspberry Pi 5 soon will drop the power draw even further. No behavioural data. No external parties. Just charts I can stare at when the mood strikes."
            }
          }
        ]
      }
    ]
  },
  "bskyPostRef": {
    "cid": "bafyreidogkgkpsnbgl3fldg7asehtappdhzlgbnjexk7cbt47j4q34pdoe",
    "uri": "at://did:plc:ofrbh253gwicbkc5nktqepol/app.bsky.feed.post/3mjagjpg4ts2g",
    "commit": {
      "cid": "bafyreifluz42swvxnfkiolk3srocrvpgucmg7vbloiom6txcdltweho2hi",
      "rev": "3mjagjpko4l2q"
    },
    "validationStatus": "valid"
  },
  "description": "I can see you, anon.",
  "publishedAt": "2026-04-11T18:07:15.928Z"
}