docs/GeohashPresenceSpec.md
The Geohash Presence feature provides a mechanism to track online participants in geohash-based location channels. It uses a dedicated ephemeral Nostr event kind to broadcast "heartbeats," ensuring accurate and privacy-preserving online counts.
A new ephemeral event kind is defined for presence heartbeats:
20001 (GEOHASH_PRESENCE)The presence event mimics the structure of a geohash chat message (Kind 20000) but without content or nickname metadata, to minimize overhead and focus purely on "liveness".
{
"kind": 20001,
"created_at": <timestamp>,
"tags": [
["g", "<geohash>"]
],
"content": "",
"pubkey": "<geohash_derived_pubkey>",
"id": "<event_id>",
"sig": "<signature>"
}
content: Must be empty string.tags: Must include ["g", "<geohash>"]. Should NOT include ["n", "<nickname>"].pubkey: The ephemeral identity derived specifically for this geohash (same as used for chat messages).Clients MUST broadcast a Kind 20001 presence event globally when the app is open, regardless of which screen the user is viewing.
REGION (precision 2), PROVINCE (precision 4), CITY (precision 5).NEIGHBORHOOD (precision 6), BLOCK (precision 7), BUILDING (precision 8+).Clients must update their Nostr filters to listen for both chat and presence events on geohash channels.
kinds: [20000, 20001]#g: ["<geohash>"]The "online participants" count shown in the UI aggregates unique public keys from both presence heartbeats and active chat messages.
pubkey -> last_seen_timestamp for each geohash.last_seen_timestamp upon receiving a valid Kind 20001 (Presence) OR Kind 20000 (Chat) event.last_seen_timestamp is within the last 5 minutes.The presentation of the participant count depends on the geohash precision level and data availability.
[N people].0.[? people]NostrKind.GEOHASH_PRESENCE: Added constant 20001.NostrProtocol.createGeohashPresenceEvent: Helper to generate the event.GeohashViewModel:
startGlobalPresenceHeartbeat(): Coroutine that collectLatest on LocationChannelManager.availableChannels.precision <= 5 before broadcasting.GeohashMessageHandler:
onEvent to update participant counts for both Kind 20000 and 20001.LocationChannelsSheet:
[? people] display logic for high-precision, zero-count channels.?) when privacy rules prevent accurate passive counting.