10 KiB
NIP-44 Places
draft
optional
A kind 37515
Place event represents a place on Earth.
Rationale
This NIP provides a decentralized mechanism for people to publish places that matter to them on a map without any governing intermediaries such as Google Maps or OpenStreetMaps.
A Place event is cryptographically owned by its creator who has the sole ability to edit it.
Places can be zapped, reviewed, labeled, commented on, or shared like any other nostr event.
High quality places can be found by following pubkeys who publish them, reviews, NIP-51 lists, or even attached NIP-13 proof-of-work.
Properties of a Place may be defined by its creator, but may also be crowdsourced as discussed below, enabling a balance between ownership and open-source contribution.
Tip
The 7515 in 37515 is alphanumeric code for GEO
Good Use Cases
- If you own a business, you can truly own your place on the map by publishing a Place.
- Large facilities and campuses with many points of interest can group and share their Places by using a NIP-51 list called a World. Clients can use World lists to filter the Places on the map for focused experiences.
- Publish temporary points of interest like a speed trap or meetup location.
- Create a Place for each of your favorite camping spots or hiking paths.
- Create a list of your favorite bars for a pub crawl to share with others.
- Copy useful geo data from other sources to make it available on nostr.
Bad Use Cases
- Replicating OpenStreetMaps data for every tree, river, road and municipality. This is background noise and should be handled in your client by tile services like Mapbox or OpenMapTiles.
- Publicizing your house. Don't publish places that put anyone's privacy at risk.
Place Event Structure
A Place is comprised of two main parts: GeoJSON defines the geospatial structure of the Place in a standard format that can be displayed on a map, and prop
tags enable the definition of properties for the Place that adhere to existing mapping standards while also enabling crowdsourcing of properties.
{
kind: 37515,
content: '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"coordinates":[-63.704031143965054,27.04213619251243],"type":"Point"}}]}' // stringified JSON. Use https://geojson.io to easily create GeoJSON objects for testing.
tags: [
["d", "something unique"], // unique identifier for replaceable event
["L", "osm"], // specify usage of OpenStreetMaps namespace
["prop", "name", "Jitter's Coffee Shop", "osm"],
["prop", "opening_hours", "Mo-Fr_6:00-20:00,Sa-Su_6:00-17:00", "osm"],
["L", "schema/Place"], // specify usage of schema.org/Place namespace
["prop", "logo", "https://nostr.build/logo.png", "schema/Place"],
["L", "schema/PostalAddress"], // specify usage of schema.org/PostalAddress namespace, even though this is technically also underneath schema/Place's `address` property:
["prop", "addressCountry", "USA", "schema/PostalAddress"],
["admin", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"]
["admin", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"]
["g", "dtee7"], // geohash of place; should be as accurate as possible
["g", "dtee"], // all less-precise geohashes must be defined to allow for searching -- see https://github.com/nostr-protocol/nips/pull/136#issuecomment-1788549584
["g", "dte"],
["g", "dt"],
["g", "d"],
],
pubkey: ...
created_at: ...
}
Content
GeoJSON is used to define the Place's geospatial structure. This GeoJSON is stringified and stored in the content
field of the event.
geojson.io is a great tool to play around with GeoJSON data structures on a map. It also validates them.
The coordinates
property of the GeoJSON object will provide the [longitude, latitude] coordinate(s) to position the Place on a map.
Important
GeoJSON can contain multiple features, which means your Place may be a feature collection made up of multiple points or lines or polygons. Each feature can have its own
properties
object which may not be empty if the data is copied from somewhere else. However, theproperties
of a feature don't necessarily apply to the overall Place. Therefore, clients SHOULD NOT use theproperties
object as properties for the Place. See below for how to define properties that apply to the Place. If you have multiple features rich in properties, consider splitting them into separate Places.
Prop Tags
A Place creator can describe the properties of their Place using prop
tags which represent key = value
pairs. Prop tags take the following form:
"tags": [
["L", <namespace>]
["prop", <key>, <value>, <namespace>]
]
The osm
(Open Street Maps) and schema/Place
(schema.org/Place) namespaces both provide extensive property lists that can be utilized in the prop tag for a Place. Other namespaces may be used as well. Clients can choose which keys/namespaces they support and provide auto-complete or property selection when creating a Place; they may also use the namespace as contextual information for how to interpret/display the prop.
Requirements
- The
"L"
tag MUST be present as specified in NIP-32. - The
key
andvalue
SHOULD be defined in the referenced namespace. - The last element in the prop tag MUST be a
namespace
defined in the"L"
tag. - Multiple
"prop"
tags MAY be used in a single event. - Multiple
"L"
tags MAY be used in a single event, but each namespace MUST be referenced by at least 1 prop tag. key
MUST not be empty.- If
value
is empty, it denotes the complete removal of the property from the Place. This is NOT the same as using something likefalse
as the value.
Using Props
Prop tags are not indexed by relays. Props can be used for client-side filtering and interpretation of Places after they are queried from the relays; the g
tag is the preferred method to query for Places in an area.
How to Translate Props from Various Namespaces
Some namespaces are hierarchical (including Schema) where a property may contain another collection of properties instead of a simple text value. An example of this is the address
property of schema/Place
which may be either text or a schema/PostalAddress
object. If you wanted to specify individual properties of PostalAddress
, you would do so like this:
"tags": [
["L", "schema/PostalAddress"],
["prop", "addressCountry", "USA", "schema/PostalAddress"],
["prop", "postalCode", "90743", "schema/PostalAddress"]
]
As you can see, these properties don't actually belong to schema/Place
, even though addressCountry
and postalCode
can technically be considered a subproperty of the address
property of schema/Place
. Essentially, by specifying the specific namespace, all properties can be represented in a flat key=value structure. This prevents the need to store anything but strict key=value strings in a "prop"
tag.
If a namespace has multiple levels of keys and you want to specify a lower one, you can do so like this.
Imagine a fictional namespace called kitchen
:
- kitchen
- blender - brand name of blender
- fridge
- status - true for on, false for off
- freezer
- temperature - in degrees F
- spaceAvailable - as a percentage of space left unused
- toaster
- status - true for on, false for off
- cookTime - how long to cook in seconds
This is how we would specify a prop for the temperature of the freezer:
"tags": [ ["L", "kitchen/fridge/freezer"], ["prop", "temperature", "34", "kitchen/fridge/freezer"] ]
Because the kitchen
namespace is not flat, we can traverse it with a /
so that our prop only contains a simple key=value pair.
Admin Tags
The Place creator can designate other pubkeys via admin
tags. If these admin
pubkeys publish kind 1754
events to apply properties to the Place, clients SHOULD give their props higher consideration than props applied by non-admin pubkeys.
Other Tags
"d"
tag is necessary for a replaceable event if you desire to make more than one of them."g"
tag MUST be present and as accurate to the GeoJSON geometry as possible. This allows for indexed relay queries to retrieve Places in an area. Retrieving Places based on the geohash closest to the screen's viewport will be the primary method of retrieving Places from relays."expiration"
may be used for temporary Places such as marking a speed trap.
Prop Application Kind 1754
A kind 1754
event MAY be used to apply props to other Places. This enables crowdsourcing of useful Place information, but clients ultimately decide how this information is used.
If a pubkey is listed in a Place's "admin"
tag, clients SHOULD consider its 1754
events authoritative, but still subordinate to the Place's own prop tags.
Content
The content
field MAY include a human-readable explanation or note for the event.
Prop Target
The prop event MUST include one or more "a"
tags indicating
the target Places the props should be applied to.
Examples
Crowdsourcing a prop for wheelchair accessibility to an existing Place using an OpenStreetMap (osm
) tag:
{
"kind": 1754,
"content": "Adding local observations regarding wheelchair accessibility at Jitter's Coffee Shop.",
"tags": [
["L", "osm"],
["prop", "access:wheelchair", "yes", "osm"]
["a", "37515:0af3b...:something unique"]
],
}
Implementations
- https://go.yondar.me (work in progress)
Resources
- https://geojson.io - useful playground for creating GeoJSON
- https://taginfo.openstreetmap.org - find Place props used in OpenStreetMaps
- https://schema.org/Place - find Place props defined in Schema