NIPs by PolleramaCommunity NIPs, surfaced by trustConnect
npub14rg4vrt2v37...

Gaming on Nostr

Published Jan 1, 2026
kind 8343kind 8344kind 8345kind 8346kind 25211kind 25212kind 25213kind 38743kind 38744kind 38745kind 38746

NIP-XX: Gaming on Nostr

draft optional

This NIP defines event kinds and protocols for enabling online gaming experiences on Nostr, including MMO (Massively Multiplayer Online) games, Battle Royale games, trading systems, turn-based games, real-time multiplayer, and more.

Motivation

Gaming is one of the most engaging forms of digital interaction, but current gaming platforms suffer from centralization issues:

  • Player data and achievements are locked to specific platforms
  • In-game items and currencies cannot be truly owned or transferred
  • Game servers can shut down, losing all player progress
  • Cross-platform play is limited by corporate decisions
  • Players have no control over their gaming identity

Nostr's decentralized architecture solves these problems by:

  • Giving players true ownership of their gaming identity and achievements
  • Enabling cross-game item trading and currency exchange
  • Allowing games to persist even if original developers stop supporting them
  • Creating interoperable gaming experiences across different clients
  • Enabling community-driven game development and moderation

Overview

This NIP introduces three categories of gaming events:

  1. Ephemeral Events (20000-29999): Real-time game state that doesn't need permanent storage
  2. Addressable Events (30000-39999): Game sessions, player profiles, and updateable game data
  3. Regular Events (1000-9999): Permanent game records, achievements, and results

Event Kinds

Game Session Management

kind:38743 - Game Session (Addressable)

A game session represents an instance of a game that players can join. This is an addressable event that can be updated as the game progresses.

{
  "kind": 38743,
  "tags": [
    ["d", "<unique-session-id>"],                    // Required: Unique session identifier
    ["game", "<game-identifier>"],                   // Required: Game type/name
    ["title", "<session-title>"],                    // Required: Display name for the session
    ["description", "<session-description>"],        // Optional: Session description
    ["status", "<waiting|in-progress|completed>"],   // Required: Current session status
    ["max-players", "<number>"],                     // Required: Maximum player count
    ["current-players", "<number>"],                 // Optional: Current player count
    ["game-mode", "<mode>"],                         // Optional: Game mode (e.g., "battle-royale", "team-deathmatch")
    ["difficulty", "<easy|medium|hard|custom>"],     // Optional: Difficulty level
    ["map", "<map-identifier>"],                     // Optional: Map or world identifier
    ["rules", "<json-rules>"],                       // Optional: Game-specific rules as JSON
    ["entry-fee", "<amount>", "<currency>"],         // Optional: Entry fee (amount, currency/token)
    ["prize-pool", "<amount>", "<currency>"],        // Optional: Prize pool
    ["starts", "<unix-timestamp>"],                  // Optional: Scheduled start time
    ["ends", "<unix-timestamp>"],                    // Optional: Expected/actual end time
    ["version", "<game-version>"],                   // Optional: Game version/protocol version
    ["p", "<pubkey>", "<relay-hint>", "<role>"],    // Required: Host and players with roles
    ["relay", "<wss://relay-url>"],                  // Optional: Preferred relays for this session
    ["image", "<preview-image-url>"],                // Optional: Session preview image
    ["t", "<hashtag>"]                               // Optional: Hashtags for discovery
  ],
  "content": "",  // Optional: Additional session details or configuration
  // other fields...
}

**Roles for p tags:**

  • host - Session creator/administrator
  • player - Active participant
  • spectator - Observer only
  • moderator - Can moderate but not play
  • bot - AI player

Status values:

  • waiting - Session created, waiting for players
  • in-progress - Game is currently running
  • paused - Game temporarily paused
  • completed - Game has ended
  • cancelled - Game was cancelled

Example:

{
  "kind": 38743,
  "tags": [
    ["d", "br-island-match-001"],
    ["game", "nostr-royale"],
    ["title", "Nostr Island Showdown #1"],
    ["description", "100-player battle royale on Island map"],
    ["status", "waiting"],
    ["max-players", "100"],
    ["current-players", "47"],
    ["game-mode", "battle-royale"],
    ["map", "island-v2"],
    ["starts", "1735689600"],
    ["version", "1.0.0"],
    ["p", "91cf9..4e5ca", "wss://relay.nostr.band", "host"],
    ["p", "14aeb..8dad4", "", "player"],
    ["image", "https://example.com/island-preview.jpg"],
    ["t", "gaming"],
    ["t", "battle-royale"]
  ],
  "content": ""
}

Real-time Game State (Ephemeral)

kind:25211 - Game Action (Ephemeral)

Ephemeral events for real-time game actions. These are not stored permanently by relays and are used for live gameplay.

{
  "kind": 25211,
  "tags": [
    ["a", "38743:<host-pubkey>:<session-id>"],      // Required: Reference to game session
    ["action", "<action-type>"],                     // Required: Type of action
    ["data", "<json-action-data>"],                  // Optional: Action-specific data as JSON
    ["seq", "<sequence-number>"],                    // Optional: Sequence number for ordering
    ["tick", "<game-tick>"],                         // Optional: Game tick/frame number
    ["p", "<target-pubkey>"]                         // Optional: Target player (for interactions)
  ],
  "content": "",  // Optional: Additional action data
  // other fields...
}

Common action types:

  • move - Player movement
  • attack - Attack action
  • use-item - Item usage
  • chat - In-game chat message
  • ping - Keep-alive/latency check
  • spawn - Player spawn/respawn
  • pickup - Item pickup
  • trade-request - Initiate trade
  • vote-kick - Vote to remove player

Example (Movement):

{
  "kind": 25211,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-island-match-001"],
    ["action", "move"],
    ["data", "{\"x\": 125.5, \"y\": 67.2, \"z\": 10.0, \"rotation\": 45}"],
    ["tick", "12847"]
  ],
  "content": ""
}

Example (Attack):

{
  "kind": 25211,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-island-match-001"],
    ["action", "attack"],
    ["data", "{\"weapon\": \"rifle\", \"direction\": [0.8, 0.6, 0], \"damage\": 25}"],
    ["p", "14aeb..8dad4"],  // Target player
    ["tick", "12848"]
  ],
  "content": ""
}
kind:25212 - Game State Update (Ephemeral)

Broadcast game state updates from the authoritative server/host. Used for synchronizing game state across all clients.

{
  "kind": 25212,
  "tags": [
    ["a", "38743:<host-pubkey>:<session-id>"],      // Required: Reference to game session
    ["state-type", "<type>"],                        // Required: Type of state update
    ["data", "<json-state-data>"],                   // Required: State data as JSON
    ["tick", "<game-tick>"],                         // Optional: Game tick/frame number
    ["hash", "<state-hash>"]                         // Optional: Hash for validation
  ],
  "content": "",  // Optional: Additional state data
  // other fields...
}

Common state types:

  • world-state - Overall world/map state
  • player-state - Player positions and stats
  • inventory - Inventory updates
  • score - Score updates
  • environment - Environmental changes
  • event - In-game events (storm closing, supply drop, etc.)

Example:

{
  "kind": 25212,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-island-match-001"],
    ["state-type", "environment"],
    ["data", "{\"storm\": {\"center\": [100, 100], \"radius\": 500}, \"remaining-players\": 23}"],
    ["tick", "15000"]
  ],
  "content": ""
}

Player Data

kind:38744 - Player Gaming Profile (Addressable)

A player's gaming profile that tracks stats, achievements, and preferences across games.

{
  "kind": 38744,
  "tags": [
    ["d", "<game-identifier>"],                      // Required: Specific game or "global" for all games
    ["game", "<game-identifier>"],                   // Required: Game this profile is for
    ["level", "<number>"],                           // Optional: Player level
    ["rank", "<rank-identifier>"],                   // Optional: Player rank/tier
    ["wins", "<number>"],                            // Optional: Total wins
    ["losses", "<number>"],                          // Optional: Total losses
    ["draws", "<number>"],                           // Optional: Total draws
    ["playtime", "<seconds>"],                       // Optional: Total playtime in seconds
    ["rating", "<number>"],                          // Optional: Skill rating (e.g., ELO)
    ["avatar", "<image-url>"],                       // Optional: In-game avatar
    ["faction", "<faction-id>"],                     // Optional: Team/faction membership
    ["achievement", "<achievement-id>", "<unlocked-timestamp>"],  // Optional: Unlocked achievements
    ["stat", "<stat-name>", "<value>"]               // Optional: Custom game-specific stats
  ],
  "content": "",  // Optional: Additional profile data
  // other fields...
}

Example:

{
  "kind": 38744,
  "tags": [
    ["d", "nostr-royale"],
    ["game", "nostr-royale"],
    ["level", "47"],
    ["rank", "diamond"],
    ["wins", "342"],
    ["losses", "289"],
    ["playtime", "892340"],
    ["rating", "2450"],
    ["achievement", "first-win", "1698765432"],
    ["achievement", "hundred-wins", "1702345678"],
    ["stat", "kills", "4521"],
    ["stat", "headshots", "892"],
    ["avatar", "https://example.com/avatar.png"]
  ],
  "content": ""
}

Game Results & Records

kind:8343 - Game Result (Regular)

Permanent record of a game's outcome. Published when a game session completes.

{
  "kind": 8343,
  "tags": [
    ["a", "38743:<host-pubkey>:<session-id>"],      // Required: Reference to game session
    ["game", "<game-identifier>"],                   // Required: Game identifier
    ["duration", "<seconds>"],                       // Optional: Game duration
    ["completed-at", "<unix-timestamp>"],            // Optional: Completion timestamp
    ["p", "<pubkey>", "<relay-hint>", "winner"],    // Winners
    ["p", "<pubkey>", "<relay-hint>", "loser"],     // Losers
    ["p", "<pubkey>", "<relay-hint>", "draw"],      // Draw participants
    ["score", "<pubkey>", "<score>"],               // Player scores
    ["stat", "<pubkey>", "<stat-name>", "<value>"], // Player statistics
    ["replay", "<replay-data-url>"]                  // Optional: Link to replay data
  ],
  "content": "",  // Optional: Game summary or commentary
  // other fields...
}

Example:

{
  "kind": 8343,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-island-match-001"],
    ["game", "nostr-royale"],
    ["duration", "1847"],
    ["completed-at", "1735693200"],
    ["p", "14aeb..8dad4", "wss://relay.nostr.band", "winner"],
    ["score", "14aeb..8dad4", "8"],  // 8 kills
    ["stat", "14aeb..8dad4", "damage-dealt", "2450"],
    ["stat", "14aeb..8dad4", "survival-time", "1847"],
    ["replay", "https://replays.example.com/br-island-match-001.json"]
  ],
  "content": "Epic final showdown in the storm! 🏆"
}

Trading & Economy

kind:38745 - Trade Offer (Addressable)

A trade offer between players for in-game items, currency, or NFTs.

{
  "kind": 38745,
  "tags": [
    ["d", "<unique-trade-id>"],                      // Required: Unique trade identifier
    ["game", "<game-identifier>"],                   // Required: Game context
    ["status", "<pending|accepted|rejected|expired|completed>"], // Required: Trade status
    ["p", "<counterparty-pubkey>"],                  // Required: Other party in trade
    ["offer-item", "<item-id>", "<quantity>", "<metadata>"],     // Items being offered
    ["request-item", "<item-id>", "<quantity>", "<metadata>"],   // Items being requested
    ["expires", "<unix-timestamp>"],                 // Optional: Expiration time
    ["escrow", "<escrow-pubkey>"]                    // Optional: Escrow service pubkey
  ],
  "content": "",  // Optional: Trade message or notes
  // other fields...
}

Example:

{
  "kind": 38745,
  "tags": [
    ["d", "trade-20250101-abc"],
    ["game", "nostr-quest"],
    ["status", "pending"],
    ["p", "14aeb..8dad4"],
    ["offer-item", "sword-legendary-001", "1", "{\"rarity\": \"legendary\"}"],
    ["offer-item", "gold-coins", "500", "{}"],
    ["request-item", "armor-epic-042", "1", "{\"rarity\": \"epic\"}"],
    ["expires", "1735779600"]
  ],
  "content": "Looking to trade my legendary sword for epic armor. Fair trade!"
}
kind:8344 - Trade Completion (Regular)

Permanent record of a completed trade.

{
  "kind": 8344,
  "tags": [
    ["e", "<trade-offer-event-id>"],                 // Required: Reference to trade offer
    ["p", "<party-1-pubkey>"],                       // Required: First party
    ["p", "<party-2-pubkey>"],                       // Required: Second party
    ["completed-at", "<unix-timestamp>"],            // Required: Completion time
    ["item", "<from-pubkey>", "<to-pubkey>", "<item-id>", "<quantity>"]  // Items transferred
  ],
  "content": "",  // Optional: Trade notes
  // other fields...
}

Achievements & Badges

kind:8345 - Achievement Unlock (Regular)

Permanent record of achievement unlocked by a player.

{
  "kind": 8345,
  "tags": [
    ["game", "<game-identifier>"],                   // Required: Game identifier
    ["achievement", "<achievement-id>"],             // Required: Achievement identifier
    ["title", "<achievement-title>"],                // Required: Achievement name
    ["description", "<achievement-description>"],    // Optional: Description
    ["rarity", "<common|rare|epic|legendary>"],     // Optional: Rarity tier
    ["points", "<number>"],                          // Optional: Points value
    ["image", "<badge-image-url>"],                  // Optional: Badge image
    ["proof", "<proof-data>"]                        // Optional: Proof of achievement
  ],
  "content": "",  // Optional: Achievement story or context
  // other fields...
}

Example:

{
  "kind": 8345,
  "tags": [
    ["game", "nostr-royale"],
    ["achievement", "double-digit-wins"],
    ["title", "Perfect Ten"],
    ["description", "Win 10 consecutive matches"],
    ["rarity", "epic"],
    ["points", "100"],
    ["image", "https://example.com/achievements/perfect-ten.png"],
    ["proof", "{\"matches\": [\"match1\", \"match2\", ...]}"]
  ],
  "content": "Achieved 10 consecutive victories! 🔥"
}

Matchmaking & Invitations

kind:25213 - Matchmaking Request (Ephemeral)

Request to join matchmaking queue.

{
  "kind": 25213,
  "tags": [
    ["game", "<game-identifier>"],                   // Required: Game identifier
    ["mode", "<game-mode>"],                         // Required: Game mode
    ["rank", "<rank-range-min>", "<rank-range-max>"], // Optional: Rank range
    ["region", "<region-code>"],                     // Optional: Preferred region
    ["party", "<party-leader-pubkey>"]               // Optional: Party leader if in group
  ],
  "content": "",
  // other fields...
}
kind:8346 - Game Invitation (Regular)

Invitation to join a game session.

{
  "kind": 8346,
  "tags": [
    ["a", "38743:<host-pubkey>:<session-id>"],      // Required: Game session reference
    ["p", "<invited-pubkey>"],                       // Required: Invited player
    ["expires", "<unix-timestamp>"],                 // Optional: Invitation expiry
    ["role", "<player|spectator>"]                   // Optional: Invited role
  ],
  "content": "Join me for a battle royale match!",
  // other fields...
}

Leaderboards & Rankings

kind:38746 - Leaderboard (Addressable)

Leaderboard for a specific game, mode, or timeframe.

{
  "kind": 38746,
  "tags": [
    ["d", "<leaderboard-id>"],                       // Required: Leaderboard identifier
    ["game", "<game-identifier>"],                   // Required: Game identifier
    ["type", "<global|seasonal|event>"],             // Required: Leaderboard type
    ["metric", "<rating|wins|kills|score>"],         // Required: Ranking metric
    ["season", "<season-id>"],                       // Optional: Season identifier
    ["starts", "<unix-timestamp>"],                  // Optional: Leaderboard period start
    ["ends", "<unix-timestamp>"],                    // Optional: Leaderboard period end
    ["entry", "<rank>", "<pubkey>", "<score>", "<data>"]  // Leaderboard entries
  ],
  "content": "",
  // other fields...
}

Example:

{
  "kind": 38746,
  "tags": [
    ["d", "global-rating-2025-q1"],
    ["game", "nostr-royale"],
    ["type", "seasonal"],
    ["metric", "rating"],
    ["season", "2025-q1"],
    ["starts", "1735689600"],
    ["ends", "1743552000"],
    ["entry", "1", "14aeb..8dad4", "3250", "{\"wins\": 142, \"losses\": 34}"],
    ["entry", "2", "91cf9..4e5ca", "3180", "{\"wins\": 128, \"losses\": 41}"],
    ["entry", "3", "a1b2c..3d4e5", "3095", "{\"wins\": 115, \"losses\": 38}"]
  ],
  "content": ""
}

Implementation Guidelines

Client Behavior

Game Clients SHOULD:

  1. Subscribe to the game session (kind:38743) and monitor for updates
  2. Subscribe to real-time game actions (kind:25211, kind:25212) with appropriate filters
  3. Implement proper conflict resolution for concurrent actions
  4. Validate game state updates against known game rules
  5. Handle network latency and packet loss gracefully
  6. Cache recent game state locally for offline replay
  7. Implement anti-cheat measures where applicable

Game Clients MAY:

  1. Act as authoritative servers for peer-to-peer games
  2. Validate other players' actions and broadcast violations
  3. Implement client-side prediction for better responsiveness
  4. Store replay data locally or publish to blob storage
  5. Cross-reference achievements with game results for validation

Relay Behavior

Relays MAY:

  1. Implement specialized gaming relays with lower latency
  2. Provide game-specific query filters and indexes
  3. Validate game events against game rules
  4. Rate-limit game action events to prevent spam
  5. Store game results (kind:8343) while discarding ephemeral events
  6. Implement geographic routing for regional matchmaking

Relays SHOULD:

  1. Respect ephemeral event lifetimes
  2. Index game sessions by game identifier and status
  3. Maintain leaderboards and rankings efficiently
  4. Provide WebSocket connections optimized for gaming

Anti-Cheat Considerations

This NIP does not mandate specific anti-cheat mechanisms, but implementations SHOULD consider:

  1. Server-Authoritative Design: Critical game state should be validated by a trusted host/server
  2. Proof of Work: Require PoW for game actions to rate-limit spam
  3. Reputation Systems: Track player behavior and flag suspicious patterns
  4. Cryptographic Signatures: Verify all events are properly signed
  5. State Validation: Cross-validate game state across multiple observers
  6. Replay Analysis: Store and analyze game replays for cheating patterns
  7. Community Moderation: Allow players to report and vote on suspicious behavior

Interoperability

To maximize interoperability between games and clients:

  1. Standardize Common Elements: Use consistent item identifiers, stat names, and achievement structures where possible
  2. Version Compatibility: Include version tags in all game-specific events
  3. Fallback Behavior: Gracefully handle unknown tags or event types
  4. Documentation: Game developers SHOULD publish schemas for their custom tags
  5. Cross-Game Items: Consider supporting cross-game item transfers where applicable

Examples

Complete Battle Royale Flow

  1. Host creates game session:
{
  "kind": 38743,
  "tags": [
    ["d", "br-001"],
    ["game", "nostr-royale"],
    ["title", "Evening Battle Royale"],
    ["status", "waiting"],
    ["max-players", "100"],
    ["current-players", "1"],
    ["game-mode", "battle-royale"],
    ["p", "91cf9..4e5ca", "", "host"]
  ],
  "content": ""
}
  1. Players join (host updates session):
{
  "kind": 38743,
  "tags": [
    ["d", "br-001"],
    // ... other tags ...
    ["current-players", "47"],
    ["p", "91cf9..4e5ca", "", "host"],
    ["p", "14aeb..8dad4", "", "player"],
    ["p", "a1b2c..3d4e5", "", "player"]
    // ... more players ...
  ],
  "content": ""
}
  1. Game starts (status update):
{
  "kind": 38743,
  "tags": [
    ["d", "br-001"],
    // ... other tags ...
    ["status", "in-progress"],
    ["starts", "1735693200"]
  ],
  "content": ""
}
  1. Real-time gameplay (ephemeral actions):
// Player movement
{
  "kind": 25211,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-001"],
    ["action", "move"],
    ["data", "{\"x\": 125.5, \"y\": 67.2}"],
    ["tick", "1000"]
  ],
  "content": ""
}

// State update from host
{
  "kind": 25212,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-001"],
    ["state-type", "player-state"],
    ["data", "{\"players\": [{\"pubkey\": \"14aeb..8dad4\", \"pos\": [125.5, 67.2], \"hp\": 100}]}"],
    ["tick", "1000"]
  ],
  "content": ""
}
  1. Game completes (result record):
{
  "kind": 8343,
  "tags": [
    ["a", "38743:91cf9..4e5ca:br-001"],
    ["game", "nostr-royale"],
    ["duration", "1847"],
    ["p", "14aeb..8dad4", "", "winner"],
    ["score", "14aeb..8dad4", "8"]
  ],
  "content": "Incredible victory! 🏆"
}
  1. Achievement unlocked:
{
  "kind": 8345,
  "tags": [
    ["game", "nostr-royale"],
    ["achievement", "first-win"],
    ["title", "First Victory Royale"],
    ["rarity", "common"]
  ],
  "content": "Won my first battle royale!"
}

Turn-Based Game (Chess-like)

For turn-based games, use regular events instead of ephemeral:

{
  "kind": 8347,  // Custom kind for turn-based moves
  "tags": [
    ["a", "38743:host-pubkey:chess-001"],
    ["turn", "42"],
    ["move", "e4"],  // Or use standardized notation
    ["prev", "<previous-move-event-id>"]
  ],
  "content": "",
  // other fields...
}

Security Considerations

  1. Validate Event Signatures: Always verify that events are signed by the claimed pubkey
  2. Rate Limiting: Implement rate limits on game actions to prevent spam
  3. State Validation: Don't trust client-reported state; validate with authoritative source
  4. Replay Protection: Use sequence numbers or timestamps to prevent replay attacks
  5. Privacy: Consider privacy implications of real-time position data
  6. DDoS Protection: Ephemeral events can be used for DDoS; relays should implement protections

Future Extensions

This NIP provides a foundation for gaming on Nostr. Future extensions might include:

  • Guilds/Clans: Kind for persistent gaming organizations
  • Tournaments: Multi-session competitive events
  • Spectator Mode: Enhanced support for watching games
  • Voice Chat: Integration with Nostr-based voice systems
  • Game Assets: NFT-like game items with provable ownership
  • Cross-Chain Integration: Bridge to blockchain-based game economies
  • Mod Support: Distribution and verification of game modifications

References

  • [NIP-01: Basic Protocol](01.md)
  • [NIP-53: Live Activities](53.md)
  • [NIP-64: Chess](64.md)
  • [NIP-72: Moderated Communities](72.md)

License

This NIP is released into the public domain.