Fix duplicate Nostr events (Kind 30000+ parameterized replaceable events) caused by missing d-tag. Use when: (1) Same content appears multiple times on relay for same pubkey, (2) Events aren't being replaced/updated as expected, (3) Publishing NIP-71 video events (Kind 34236) or other addressable events and seeing duplicates. The d-tag is REQUIRED for addressability - without it, each publish creates a new non-replaceable event.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add divinevideo/divine-mobile --skill nostr-addressable-event-d-tag-requirement --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Nostr Addressable Event D Tag Requirement?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/divinevideo-nostr-addressable-event-d-tag-requirement-divine-mobile)More formats (shields.io, HTML) on the badges page.
---
name: nostr-addressable-event-d-tag-requirement
description: |
Fix duplicate Nostr events (Kind 30000+ parameterized replaceable events) caused by missing d-tag.
Use when: (1) Same content appears multiple times on relay for same pubkey, (2) Events aren't
being replaced/updated as expected, (3) Publishing NIP-71 video events (Kind 34236) or other
addressable events and seeing duplicates. The d-tag is REQUIRED for addressability - without it,
each publish creates a new non-replaceable event.
author: Claude Code
version: 1.0.0
date: 2026-01-29
---
# Nostr Addressable Event d-tag Requirement
## Problem
When publishing parameterized replaceable events (Kind 30000-39999, including NIP-71 video
events Kind 34236), events appear as duplicates on the relay instead of replacing each other.
The same content shows up multiple times for the same user.
## Context / Trigger Conditions
- Publishing Kind 30000+ events (parameterized replaceable events)
- Same video/content appears multiple times in user's feed
- Events have identical pubkey, kind, and content but different event IDs
- Relay returns multiple events when you expect one
- Using NIP-71 (Kind 34236) for video events
- Using NIP-23 (Kind 30023) for long-form content
- Any addressable event type showing duplicates
## Solution
### Root Cause
Parameterized replaceable events (Kind 30000-39999) require a `d` tag to be addressable.
The combination of `pubkey + kind + d-tag value` forms the unique address. Without a `d` tag,
the relay treats each event as a separate non-replaceable event.
### Fix
Always include a `d` tag with a unique identifier for the content:
```typescript
// CORRECT - has d tag, will be replaceable
const event = {
kind: 34236, // NIP-71 video
pubkey: userPubkey,
content: "Video description",
tags: [
["d", videoId], // REQUIRED for addressability
["title", "My Video"],
["url", "https://..."],
// ... other tags
]
};
// WRONG - missing d tag, creates new event each time
const badEvent = {
kind: 34236,
pubkey: userPubkey,
content: "Video description",
tags: [
["title", "My Video"], // No d tag!
["url", "https://..."],
]
};
```
### For NIP-71 Video Events
Use the video's unique identifier (vine_id, video_id, etc.) as the d-tag value:
```typescript
tags.push(["d", video.id]);
```
### Cleaning Up Existing Duplicates
1. Fetch all events for the pubkey: `{ kinds: [34236], authors: [pubkey] }`
2. Identify events without d-tags (these are the duplicates)
3. Publish NIP-09 deletion events (Kind 5) referencing the bad event IDs
4. Republish with proper d-tags
## Verification
After adding the d-tag:
1. Publish the same content twice
2. Query the relay for events with that pubkey+kind
3. Should return only ONE event (the latest)
4. Event ID will change but d-tag address remains constant
```javascript
// Verify no duplicates
const events = await ndk.fetchEvents({ kinds: [34236], authors: [pubkey] });
const byDTag = new Map();
for (const e of events) {
const d = e.tags.find(t => t[0] === 'd')?.[1];
if (!byDTag.has(d)) byDTag.set(d, []);
byDTag.get(d).push(e);
}
// Each d-tag value should have exactly 1 event
for (const [d, evts] of byDTag) {
if (evts.length > 1) console.log(`Duplicate: d=${d} has ${evts.length} events`);
}
```
## Example
Before fix - events without d-tag create duplicates:
```
Event 1: id=abc123, kind=34236, tags=[["title", "My Video"]]
Event 2: id=def456, kind=34236, tags=[["title", "My Video"]] // Duplicate!
```
After fix - events with d-tag replace each other:
```
Event 1: id=abc123, kind=34236, tags=[["d", "video-001"], ["title", "My Video"]]
// Republishing same content...
Event 2: id=xyz789, kind=34236, tags=[["d", "video-001"], ["title", "My Video Updated"]]
// Event 1 is replaced, only Event 2 exists
```
## Notes
- The d-tag value should be stable across republishes (use content ID, not random)
- Empty string `["d", ""]` is valid but means only one event of that kind per pubkey
- Regular replaceable events (Kind 0, 3, 10000-19999) don't need d-tag
- This applies to ALL parameterized replaceable events, not just videos
- Frontend caching may show old duplicates even after relay is cleaned - hard refresh
## References
- [NIP-01: d-tag for parameterized replaceable events](https://github.com/nostr-protocol/nips/blob/master/01.md)
- [NIP-71: Video Events](https://github.com/nostr-protocol/nips/blob/master/71.md)
- [NIP-33: Parameterized Replaceable Events](https://github.com/nostr-protocol/nips/blob/master/33.md)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!