Skip to content

Hackathon

Relay Shadow

A Nostr data vending machine that recommends relays against a stated threat model, scoring measured privacy, reliability, performance and social-graph data from the BigBrotr archive.

Aug 20253rd prize, Baltic Honeybadger 2025NostrMeasurementPrivacy

Relay Shadow answers “which relays should I use?”, as a service other software can call, over Nostr itself. It takes a threat level and a use case, scores candidate relays against measured data, and returns a ranked set.

Built for
Bitcoin++ Privacy Edition hackathon, 2025
Result
3rd prize, Baltic Honeybadger 2025
Interface
NIP-90 DVM, kinds 5600 / 5601 / 7000
Data
BigBrotr archive, in PostgreSQL
Repository
BigBrotr/relay-shadow-dvm
BigBrotr/relay-shadow-dvmData Vending Machine providing privacy-focused relay recommendations using BigBrotr data.JavaScript

The problem

Every Nostr client ships a default relay list, and almost nobody changes it. That list decides what a user can see, who can see them, and which operators observe their traffic, and it is usually a handful of well-known hostnames chosen once, by a developer, for everyone.

There is measured data that could inform the choice. It sits in an archive, in a shape useful to an analyst rather than to a client at runtime.

What I built

A data vending machine: a service that receives jobs as Nostr events and replies with Nostr events, so any client that already speaks the protocol can consume it without a new API.

Requests arrive as kind 5600, carrying their parameters in tags: threat level, use case, the relay set the user currently has, how many results they want. Results are signed and published as kind 5601, with kind 7000 used for job feedback. Four request types are supported: recommend, analyze for evaluating a relay set already in use, discover for widening coverage, and health.

Underneath is a PostgreSQL copy of the BigBrotr relay data with the scoring implemented as query functions that combine four weighted factors: social graph, privacy, reliability, and performance. The default weighting places most of the emphasis on the social graph. There is a React demo client and a small Express endpoint exposing service info.

Hard parts

There is no best relay set, so the request has to say who is asking. Threat level is a request parameter ranging from low to nation-state, and it reaches the scoring query rather than being cosmetic. A relay that is excellent for reach can be exactly the wrong answer for someone whose concern is who observes them, and a recommender returning one ranking for everybody is answering a question nobody asked.

Recommending your own contacts back to you. Weighting the social graph most heavily is what makes a recommendation useful. A relay where nobody you follow publishes is not useful, but this weighting also means the service reads which relays a requester’s contacts use in order to answer. That is a tension a privacy-focused recommender sits with rather than resolves.

Answering when the data cannot. The service falls back to a static list per threat level when the query returns nothing, so a request gets a degraded answer rather than an error. The scoring weights are design inputs rather than measured optima, so the response remains a recommendation, not a privacy guarantee.