Publish a Post

Select a post below and publish it to joe.bitcoins@'s contentmultimap. The post will be stored on-chain using the vrsc::identity.blog.post VDXF key and will appear in the blog above once confirmed (~1 min).

?

How It Works

This page reads a VerusID's contentmultimap and renders any blog content it finds. The data lives entirely on the Verus blockchain — no server, no database. The page is a static HTML file that makes one RPC call to getidentity and displays the result.

Anyone with a VerusID can publish a blog by writing JSON entries to their contentmultimap. The page picks them up automatically.

VDXF Key Standard

Blog data is stored under standard VDXF keys so any app in the ecosystem can recognize the content. Keys follow the vrsc::identity.blog.* namespace.

Each key resolves to a deterministic i-address via getvdxfid. These addresses are the same on every node — they're derived from the key name, not generated randomly.

// Blog VDXF keys — generated via: ./verus getvdxfid "keyname"

// Content types
vrsc::identity.blog.profile         iPoVhbEjPCPXLE6gL3R1WEtpcUHfzVBtH1
vrsc::identity.blog.post            i7uLoCqnFbjJPRq1W2z3qS1P1qSkVysZyW

// Profile fields
vrsc::identity.blog.displayname     iBkGDSZ4ew1hKEDJJL76VyRSwZcSVaGEEA
vrsc::identity.blog.bio             iE3Y58uCrc1posw2AydaAeDNjkDAcchyuM
vrsc::identity.blog.avatar          iBsvP71qRr5cKBWCzfZVUArbUFZoMdB4fu
vrsc::identity.blog.links           iL11UnHkRi9pYMVw2ShjiqHKXxtc4EwtNp

// Post fields
vrsc::identity.blog.post.title      iN1bnLFLmVowWmPsdLwWDKDhAaEAkkxVNh
vrsc::identity.blog.post.content    iLv3Ke5YvBiitYX5aDcFD79EZYWBqf6ssj
vrsc::identity.blog.post.date       iNjVt8AWTGnoRjy74QvfSWYAX2iBPEVK1f
vrsc::identity.blog.post.tags       i4Lt349A8Rnny6DUU5cAm42DGN3bBMm2dT

The naming convention follows the existing vrsc::identity.* vocabulary from verus-typescript-primitives. The blog namespace groups all blog-related keys, with sub-namespaces for profile and post fields.

Why this structure? Any app that understands the vrsc::identity.blog.* namespace can read and display blog content from any VerusID. You don't need to know how the data was written — just look for the standard keys. This is how interoperability works without smart contracts.

Blog Schema

Each entry in the contentmultimap is a hex-encoded JSON object with a type field. The page recognizes two types:

// Profile — author info (one per identity)
{
  "type":        "profile",
  "displayName": "Your Name",          // max 50 chars
  "bio":         "A short bio",          // max 280 chars
  "avatar":      "https://...pic.jpg",   // https only
  "links": {
    "github":  "username",             // alphanumeric only
    "twitter": "handle",               // alphanumeric only
    "website": "https://yoursite.com", // https only
    "discord": "https://discord.gg/..." // https only
  }
}

// Post — a blog entry (multiple allowed, max 50)
{
  "type":    "post",
  "title":   "Post title",              // max 150 chars
  "content": "Plain text body...",       // max 4000 chars
  "date":    1711123200,                // unix timestamp
  "tags":    ["verus", "dev"]           // max 8 tags, 30 chars each
}

Only these fields are read. Everything else is silently ignored. Content is rendered as plain text — no HTML, no scripts, no embeds.

Publish Your Own

You need a VerusID and access to a Verus node (local CLI or Verus Desktop). Each entry must be hex-encoded JSON stored under the blog VDXF key.

# 1. Get the blog VDXF key (same on every node)
./verus getvdxfid "vrsc::identity.blog.post"
# Returns: i7uLoCqnFbjJPRq1W2z3qS1P1qSkVysZyW

# 2. Create your JSON content as hex
PROFILE=$(echo -n '{"type":"profile","displayName":"Alice","bio":"Building on Verus."}' | xxd -p | tr -d '\n')

POST=$(echo -n '{"type":"post","title":"My First Post","content":"Hello from the chain!","date":1711123200,"tags":["verus"]}' | xxd -p | tr -d '\n')

# 3. Push to your identity under the blog key
./verus updateidentity '{
  "name": "yourname",
  "parent": "iParentIdHere",
  "contentmultimap": {
    "i7uLoCqnFbjJPRq1W2z3qS1P1qSkVysZyW": [
      "'$PROFILE'",
      "'$POST'"
    ]
  }
}'

# 4. Done — load your ID on this page to see it

To add more posts, fetch your current contentmultimap with getidentity, append the new post to the array, and call updateidentity again with the full array.

Security Model

This page is a read-only renderer. All data from the chain passes through three layers of protection:

Schema validation — Only recognized fields with the type field set to "profile" or "post" are extracted. Unknown types and fields are dropped. Strings are length-capped. URLs must be https://. GitHub and Twitter handles are stripped to alphanumeric characters only.

Output escaping — All text goes through escapeHtml() before rendering. Content is displayed as plain text with line breaks. No HTML, no markdown rendering, no script execution from user data.

Content Security Policy — The page sets a strict CSP header: scripts can only run from the page itself, network requests only go to api.verus.services, images only load over HTTPS. Even if the other layers fail, the browser blocks anything unexpected.