8.0 KiB
Nostr Sites
This NIP describes a way to render a selection of Nostr events on a website.
A web page that is part of the Nostr Site must include nostr:site
meta tag:
<meta property="nostr:site" content="<naddr>" />
The site
event, referenced by naddr
from nostr:site
meta tag, is a parameterized replaceable event of kind 30512
. The content
field MAY contain a rich description of the site in markdown syntax (NIP-23), all tags are optional (except d
).
Tags:
{
"tags":[
// absolute url of the nostr site root, may include /path/, must not include query string, must end with /
["r", "https://site.com/"],
["name", "<pwa name>"],
["title", "<site title>"],
["summary", "<site description>"],
["image", "<site code image url>"],
// contributors, if omitted - event's author is the single site contributor
["p", "<contributor-pubkey>"],
// filters for fetching published events
// <tag> - single-letter tag
["include", "<tag>", "<value>"],
// list of included event kinds
["kind", "30023"],
// override contributors' outbox relays to fetch content
["relay", "<relay>"],
// event id and package hash of the extensions (themes, plugin)
["x", "<id>", "<relay>", "<package-hash>", "<petname>"],
// renderer engine, preferably reverse-domain notation, should match theme engine and plugin engine, i.e. `pro.npub.v1`
["z", "<engine>"],
// meta tags for website rendering, seo, social, navigation
["icon", "<favicon url>"],
["logo", "<header logo url>"],
["color", "<#hex - accent color, PWA theme_color>"],
["lang", "<language code>"],
["meta_title", "<overrides title>"],
["meta_description", "<overrided summary>"],
["og_title", "<open-graph title, overrides title>"],
["og_description", "<open-graph description, overrides summary>"],
["og_image", "<open-graph image url, overrides image>"],
["twitter_image", "<twitter image url, overrides image>"],
["twitter_title", "<twitter title, overrides title>"],
["twitter_description", "<twitter description, overrides title>"],
// primary navigation, one tag per link
["nav", "</relative/url>", "<label>"],
]
}
By default, no events are published on the site.
Admin MAY use include
tags to specify which events, authored by contributors, should be displayed on the site. include
contains a key:value
pair of single-letter tag and it's value that will be used as filters to fetch published events, i.e. t:bitcoin
or g:<geohash>
. A special value of *
means "everything".
If kind
tags are specified, only these kinds will be fetched.
If relay
tags are specified, only these relays will be used, overriding the outbox relays of the contributors.
If include
has a special value of ?
then "manual" submission is enabled and contributors MAY create submit
events that reference the target events to be published on the site.
"Submit" events
Events of kind 512
are used by Nostr Site contributors to submit an event to the site (manual submission must be enabled with include=?
). content
field may be empty, tags may include:
{
"tags":[
["a", "<addr>", "<relay>", "site"], // addr of the target site
["a"/"e", "<addr/id>", <relay>], // addr/id of the submitted event
["a"/"e", "<addr/id>", <relay>], // addr/id of the submitted event
["k", "<kind>"], // submitted event's kind, to allow filtering by target event's kind
["r", "<slug>"] // optional slug for submitted event, to be used in the website url, i.e. /posts/<slug>.
]
}
Only zero or one event may be referenced with a
or e
tag.
If relay
tags are specified in site
event, submit
events will only be fetched from those relays.
If target event is authored by none of the contributors, it should be rendered as a repost
by the contributor and show the original author.
If r
tag's value starts with /
then this a relative url of a static page
(i.e. r:/path/to/static/page
). The submitted events referenced by a
or e
tags of static pages
SHOULD NOT be included when listing published events, but are only rendered at the specified url. If no a
or e
tags are specified in a submit
event, then it's content
field will be rendered as the content of the static page - this allows to exclude such static pages from social media feeds.
If several submit
events published by contributors have the same r
tag then the most recent one should be preferred.
To override default meta tags of a page, submit
event may include meta info tags of the site
event (title
, image
, meta_title
, og_title
etc).
Hashtag pages
Sites may need to display additional info on web pages dedicated to hashtags, and may use hashtag
event published by contributors for that. The hashtag
event is a parameterized replaceable event of kind 30513
. the content
field may include a string of text in the same format as "long-form content" NIP-23, to be used as the body of the hashtag web page. Hashtag event will have tags:
{
"tags":[
["t", "<hashtag>"], // target hashtag, must be included exactly once
["a", "<addr>"], // nostr site address
["r", "<slug>"], // optional slug for hashtag, to be used in the website url, i.e. /tags/<slug>.
]
}
To override default meta tags of a hashtag page, hashtag
event may include meta info tags of the site
event (title
, image
, meta_title
, og_title
etc).
If r
tag starts with /
then it is a static hashtag webpage, and this hashtag should not be listed under posts and in other hashtag lists.
If several hashtag
events published by contributors have the same r
tag then the most recent one should be preferred.
Themes and Plugins
The theme
event is parameterized replaceable event of kind 30514
, it's content
field may have a "rich" description in the same syntax as NIP-23 long-form notes. It has the following tags:
{
"tags":[
["title", "<theme name>"],
["summary", "<theme description>"],
["version", "<latest version>"],
["license", "<theme license>"], // MIT, etc
["e", "<package id>", "<relay>"], // theme code package event id
["z", "<website engine id>"], // engine, must match the nostr site engine
]
}
The plugin
event is parameterized replaceable event of kind 30515
with the same structure.
The package
event of kind 1036
(see the new NIP-136) is essentially a directory of files - relative urls and hashes. It may contain release notes, and also contains the package hash
- a combined hash of all files
and their relative urls.
The package
event of kind 1036
SHOULD have additional tags:
{
"tags":[
["l", "theme|plugin", "org.nostrsites.ontology"], // type of code
["L", "org.nostrsites.ontology"], // label category
["a", "<addr>"] // address of the theme or plugin replaceable event
]
}
The site
events are linked to the themes and plugins using package event ids, and also the package hash
(see site
event above). This will allow us to handle link rot - if theme package event is deleted by relays, other events with the same package hash
can be found to avoid disruption of every site using the deleted package.
Rendering
Steps to render a Nostr Site to produce an HTML page:
- parse site event
naddr
from meta-tags of the HTML fetched from the server (or from settings for server-side rendering) - fetch
site event
from relays specified innaddr
- if not found, fall back to fetching
naddr
author's outbox relays - fetch extensions (plugins and themes)
- fetch authors' relays (will be omitted if single admin-author)
- if
include
tags are specified then - fetch by tags from those authors from their outbox relays
- also if
include="?"
is specified: - fetch
submit
events from authors' outbox relays - fetch targets (may include fetching target authors' relays)
- init template engine and render the target events into html
- if root url is specified, renderer should put all internal links as sub-path to root