{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreigvf3pk636wifsf4f4vajszetlhju63boliognspbckqbezse6vpi",
"uri": "at://did:plc:xrpvi727ccnv4bnwaedgs3gd/app.bsky.feed.post/3mh4xmghmyvn2"
},
"path": "/ive-added-human-dot-json-to-my-website?utm_campaign=rss",
"publishedAt": "2026-03-14T00:00:00.000Z",
"site": "https://sethmlarson.dev",
"tags": [
"Evan Hahn",
"recently blogged",
"`human.json` protocol",
"BeautifulSoup",
"https://evanhahn.com",
"human.json",
"https://foosel.net"
],
"textContent": "Evan Hahn recently blogged about adding support for the “`human.json` protocol” to his website. I read the specification and thought this seemed like a straightforward protocol to implement. I've followed along, and added a `/human.json` file to my website and `rel=\"human-json\"` in a `<link`> element to the `<head>` section of my HTML. Easy!\n\nVouching was a little more involved because I wanted to auto-discover who uses `human.json` from everyone that I follow using RSS. Then my `vouches` can be kept up-to-date as more people implement the protocol. I updated the script to parse the `<link>` element properly using BeautifulSoup (thanks Evan!). The script below is what I ended up with:\n\n\n import contextlib import pathlib import json import datetime import re import urllib import opml import urllib3 import bs4 http = urllib3.PoolManager( headers={ # Be a good internet netizen: # always set a User-Agent with # your domain and email. \"User-Agent\": \"sethmlarson.dev/1.0 (sethmichaellarson@gmail.com)\", \"Accept\": \"application/json\", }, retries=0, timeout=5, ) today = datetime.date.today().strftime(\"%Y-%m-%d\") human_json_path = pathlib.Path(\"app/static/human.json\") human_json = json.loads(human_json_path.read_text()) vouched_urls = {vouch[\"url\"] for vouch in human_json[\"vouches\"]} doc = opml.OpmlDocument.load(\"archive/feeds.opml\") for outline in doc.outlines: mat = re.search(r\"^(https?://[^/]+)(?:/|$)\", outline.html_url or \"\") if not mat: continue base_url = mat.group(1) urls_to_try = [f\"{base_url}/human.json\"] with contextlib.suppress(Exception): # Find <link rel=\"human-json\" ...> resp = http.request(\"GET\", base_url) html = bs4.BeautifulSoup(resp.data, \"html.parser\") for el in html.find_all( name=\"link\", attrs={\"rel\": \"human-json\"}, recursive=True ): if href := el.attrs.get(\"href\", None): urls_to_try.append(urllib.parse.urljoin(base_url, href)) # Try all candidate URLs. for url in urls_to_try: with contextlib.suppress(Exception): resp = http.request(\"GET\", url) if resp.status < 300 and set(resp.json()) == {\"version\", \"vouches\", \"url\"}: # Use the URL that the domain specifies, not # our own. This helps with canonicalization, # (ie do we use 'www.example.com' or 'example.com'?) human_json_url = resp.json()[\"url\"] if human_json_url in vouched_urls: continue vouched_urls.add(human_json_url) human_json[\"vouches\"].append({\"url\": human_json_url, \"date\": today}) continue human_json_path.write_text(json.dumps(human_json, indent=2))\n\nRunning this script turned up with two websites that I follow already supporting the protocol:\n\n * https://evanhahn.com (human.json)\n * https://foosel.net (human.json)\n\n\n\nMaybe this post will inspire you to add support to your own website? If you do and I follow you via RSS, your website will appear automatically after I regenerate my OPML files. If we're mutuals on Mastodon or Bluesky give me a ping and I'll add you sooner.\n\nI'm probably not going to use the browser extension myself, but if others are using the data from this \"network\" then that is a win.\n\n\n\n\n* * *\n\nThanks for keeping RSS alive! ♥",
"title": "I’ve added human.json to my website",
"updatedAt": "2026-03-14T00:00:00.000Z"
}