Live event structure (kind 30311)
When a stream goes live, a kind 30311 event (NIP-53 ) is published to Nostr.
- When using Shosho Server, this event is signed and published by the server on behalf of the user.
- When using a generic RTMP server, the user must publish it themselves. An agent may publish on the user’s behalf.
Anti-patterns
- Do not publish a 30311 manually if streaming to a Nostr streaming server. The server publishes the event for you. Manual publication results in duplicate live events on the network.
- Do not forget the host
ptag. Shosho links the stream to the user’s profile via aptag with rolehost. Without it, the stream will not appear on the user’s profile. - Do not forget the
dtag. Nostr requires adtag on all addressable events (kinds 30000-39999). Without it, you can’t reference or update the event later. - Do not forget to set
statustolivewhen the stream starts. Without it, Shosho and other clients won’t display the stream as active. - CRITICAL: Always update
statustoendedwhen the stream ends. If you don’t, the stream will appear perpetually live for up to 12 hours until it ages out (see Liveness below). Always publish the ending event to the same relays.
Tag structure
NIP-53 lists d as the only strictly required tag — all others are optional from the protocol’s perspective. The “Shosho needs” column below reflects what Shosho expects to display the stream properly.
| Tag | Value | NIP-53 | Shosho needs |
|---|---|---|---|
d | Unique stream identifier | Required | Required |
title | Stream title | Optional | Required |
summary | Description | Optional | Optional |
image | Thumbnail/cover URL (via nostr.build) | Optional | Optional |
streaming | HLS playback URL (.m3u8) | Optional | Required |
recording | URL of the edited recording, set after the stream ends | Optional | Optional |
status | live, ended, or planned | Optional | Required |
starts | Unix timestamp | Optional | Optional |
ends | Unix timestamp | Optional | Optional |
p | Participant: ['p', '<hex_pubkey>', '<relay>', '<role>'] — Shosho requires one with role host | Optional | Required (host) |
t | Hashtag | Optional | Optional |
relays | Suggested relay URLs for chat | Optional | Optional |
current_participants | Current viewer count | Optional | Optional |
total_participants | Total participants seen | Optional | Optional |
pinned | Event id of a pinned chat message | Optional | Optional |
Host identification
NIP-53 defines p tags as ['p', '<pubkey>', '<relay-url>', '<role>', '<proof>'] where the role is a displayable string (NIP-53 examples use Host, Speaker, Participant). Shosho writes the role in lowercase (host) and reads it case-insensitively, so both host and Host are accepted on read.
In practice you’ll publish:
['p', '<host_hex_pubkey>', '', 'host']The relay URL slot may be empty. The host tag must be present for Shosho to associate the stream with the host’s profile.
Signer and publication
- Shosho Server — signs with its own key, includes the user’s pubkey as the host
ptag, publishes to the server’s relays. - Generic RTMP server — you sign and publish using the user’s key.
Publishing a live event manually (generic server)
nak event -k 30311 \
--content "" \
-t d=my-stream-2024 \
-t title="My Live Stream" \
-t summary="Streaming live!" \
-t streaming=https://your-server.com/stream.m3u8 \
-t status=live \
-t starts=$(date +%s) \
-t 'p=<your_hex_pubkey>;;host' \
--sec <nsec1...> \
wss://relay.damus.io wss://relay.primal.netViewing on Shosho
Build the stream’s naddr:
nak encode naddr -k 30311 -d <d-tag> -a <author_hex_pubkey> -r wss://relay.damus.ioView at https://shosho.live/live/<naddr>.
Liveness
Shosho considers a stream live when all of the following are true:
statusislive- the event’s
created_atis within the last 12 hours - either no
endstag is set, or theendstimestamp is in the future
NIP-53 suggests clients MAY treat status=live events without an update for 1 hour as ended. Shosho’s window is 12 hours — longer than the NIP recommendation, so a stream that goes silent will appear stuck-live longer on Shosho than on a strict NIP-compliant client. This is why the “always publish status: ended” anti-pattern is critical.