Technology · · 7 min read

The Invisible Half of a Blog Post

Every post on this blog carries a pile of metadata nobody reads: social preview cards, structured data, feeds, citation tags. What each layer does, and why the real problem is discipline, not difficulty.

Photograph © Ken Reid

The Invisible Half of a Blog Post

4 August 2026 · technology writing

When I publish a post here, the words are roughly half the file. The other half is metadata: twenty-eight meta tags and two blocks of JSON-LD in the page's head, plus entries in two site-wide XML files. Skipping it all would change nothing about the reading experience, but it's necessary and is checked by a machine. This post describes it. Part of the series on how this site is built.

Quick jargon guide

  • Metadata: data about the page rather than in it: its title, summary, author, date, and preview image, written in machine-readable form.
  • Open Graph: the tag family (invented by Facebook, used by everyone) that controls the card shown when your link is shared in a chat or feed.
  • Canonical URL: a tag declaring "this address is the one true home of this page", so search engines don't treat variants as duplicates.
  • JSON-LD / structured data: a machine-readable summary of the page (this is an article, by this person, on this date) in a format search engines parse directly.
  • RSS feed: a site-wide XML file listing recent posts, so feed readers can check for new writing without visiting.
  • Sitemap: a plain list of every page you'd like search engines to know about.

The card in the chat window

Open Graph: ten tags giving the post's title, description, preview image (with its size and alt text), address, type, the site's name, and its locale. When someone pastes your link into a group chat or a social feed, the platform reads these tags to build the preview card. Without them, your link renders as bare blue text or, worse, a card assembled from whatever the scraper found first. With them, every share has a title, summary sentence, and a card image: the post's hero photograph with the title set over it in the site's own type, rendered by a script when the post is published so a shared link looks like the site it leads to. Twitter's near-identical tag family sits alongside for the platforms that read that instead.

<meta property="og:title" content="The Invisible Half of a Blog Post">
<meta property="og:description" content="Every post on this blog carries a pile
      of metadata nobody reads: social preview cards, structured data, feeds, citation tags.">
<meta property="og:image" content="https://www.kenreid.co.uk/img/og/invisible-half-of-a-blog-post.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="The Invisible Half of a Blog Post">
<meta property="og:url" content="https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html">
<meta property="og:type" content="article">
<meta property="og:site_name" content="Ken Reid">
<meta property="og:locale" content="en_GB">

The description gets written by a human (me), because it's the sentence that decides whether a stranger clicks. And the image tag points at a 1200 by 630 card drawn from the big photograph at the top of the page, not a thumbnail, because preview scrapers resize down gracefully and up horribly. The size is in the markup so a scraper can lay out the big card on the first share without fetching the image to measure it. The card is a JPEG on this site rather than the full-size photo on GitHub's release, because a release file redirects to a signed, expiring download that scrapers reject, and they then grab whatever other image they can find in the page.

The librarian's copy

Below the social tags sits a block of JSON-LD: the same facts (headline, author, dates, image) restated in schema.org's vocabulary, which is the format Google actually parses for rich results, plus a few the tags don't carry: the series the post belongs to, its language, its word count and read time, and its keywords. Where the Open Graph tags talk to chat apps, this block talks to crawlers, and it's how I explain that this page is an article by me. The author isn't spelled out in full on every post: "@id": "https://www.kenreid.co.uk/#ken" points at one description of me on the homepage, so the facts about me live in one place.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html"
  },
  "url": "https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html",
  "headline": "The Invisible Half of a Blog Post",
  "description": "Every post on this blog carries a pile of metadata nobody reads: ...",
  "image": {
    "@type": "ImageObject",
    "url": "https://www.kenreid.co.uk/img/og/invisible-half-of-a-blog-post.jpg",
    "width": 1200,
    "height": 630
  },
  "datePublished": "2026-08-04",
  "dateModified": "2026-08-04",
  "author": {
    "@type": "Person",
    "@id": "https://www.kenreid.co.uk/#ken",
    "name": "Ken Reid",
    "url": "https://www.kenreid.co.uk/"
  },
  "publisher": { ... the same Person ... },
  "isPartOf": [
    { "@id": "https://www.kenreid.co.uk/#website" },
    {
      "@type": "CreativeWorkSeries",
      "@id": "https://www.kenreid.co.uk/series-how-this-site-is-built.html#series",
      "name": "How This Site Is Built",
      "url": "https://www.kenreid.co.uk/series-how-this-site-is-built.html"
    }
  ],
  "inLanguage": "en-GB",
  "articleSection": "Technology",
  "wordCount": 1525,
  "timeRequired": "PT7M",
  "keywords": ["metadata", "seo", "open graph", "rss", "structured data"]
}
</script>

A second, smaller block is a BreadcrumbList: Home, then Blog, then this post, the trail a search result can show under the title instead of a bare URL.

Each post carries citation tags (the format Google Scholar reads) and Dublin Core tags (the library world's metadata standard). I spent years in academia, it's eight tags, and if someone ever does want to cite the scrobbles post in their media-studies dissertation, their reference manager will fill every field correctly. It's courteous and costs me nothing but a couple of seconds, and might give another citation or two to my Google Scholar account!

<meta name="citation_title" content="The Invisible Half of a Blog Post">
<meta name="citation_author" content="Reid, Kenneth N.">
<meta name="citation_publication_date" content="2026/08/04">
<meta name="citation_online_date" content="2026/08/04">
<meta name="citation_public_url" content="https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html">
<meta name="DC.title" content="The Invisible Half of a Blog Post">
<meta name="DC.creator" content="Kenneth N. Reid">
<meta name="DC.date" content="2026-08-04">
A four-pane skylight in a dark wooden attic roof, bright sky showing through
© Ken Reid. All rights reserved. The part of the structure you only notice when the light comes through it.

The site-wide ledgers

Two XML files round out every publish. The sitemap is a list of every page, so crawlers miss nothing, and each post's entry carries the date it last changed in substance (the publish date, unless I've set an updated one). The RSS feed is how readers with feed readers (a small, excellent demographic) get new posts delivered without visiting, and it's essential infrastructure here. RSS predates the social platforms and will outlive several of them.

<!-- feed.xml -->
<item>
  <title>The Invisible Half of a Blog Post</title>
  <link>https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html</link>
  <guid>https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html</guid>
  <pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate>
  <description>Every post on this blog carries a pile of metadata nobody reads: ...</description>
  <category>technology</category>
  <category>writing</category>
</item>

<!-- sitemap.xml -->
<url><loc>https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html</loc><lastmod>2026-08-04</lastmod></url>

The newest twenty items in the feed also carry the whole post in content:encoded, so a feed reader can show it without sending you here at all.

Each post also declares a canonical URL: the www and non-www versions of your site, plus any URL with tracking junk appended, all count as different pages to a search engine, splitting your modest search presence into fragments. One tag per page declares the official address and the fragments reunite.

<link rel="canonical" href="https://www.kenreid.co.uk/blog/invisible-half-of-a-blog-post.html">

The real problem is discipline

Nothing above is hard. The hard part is that it's a whole head of near-identical boilerplate on every post, and near-identical is the operative curse: copy the head from the last post, forget to change the og:image, and next week your post about cats is shared around under a photograph of a dog.

So: automate it, the checking and, as it turned out, most of the writing too. My audit script validates every page's metadata (descriptions present and sensibly sized, canonical matching the filename, preview images existing, JSON-LD parsing, feed and sitemap complete) on every push. And generate_post_head.py owns the template: the share image tags, the hero preload, both JSON-LD blocks and the version stamps on the stylesheet and scripts are rebuilt from posts.json, and if I edit them by hand it puts them back. Other scripts write the sitemap and the feed and draw the share cards. What's left for me is the title, the description and the keywords, which are the bits a person should be choosing anyway. The head stays correct because a robot writes it and another one reads it. Without that, my recommendation would be to keep less metadata: only what you can maintain, because wrong metadata is worse than none.

Common questions

What's the minimum set worth having?

Title, description, canonical, and the Open Graph tags with a real image. That covers search snippets and share cards, which is where the visible benefit lives. Add RSS if you post regularly; it's one generated file and your most loyal readers will use it. Everything beyond that is diminishing returns done for craft.

Does any of this improve search ranking?

Mostly no, and be suspicious of anyone selling otherwise. Metadata doesn't make a page rank higher; it makes the page present correctly wherever it appears: the right snippet, the right card, the right attribution.

How do I check what my links look like when shared?

Paste the URL into a private chat with yourself and see what unfurls.

Why not generate all this with a static site generator?

A generator absolutely would, from a few front-matter fields, and it's a fine reason to use one. This site is hand-built by choice (a decision explained elsewhere), so the equivalent is a template that a script fills in from posts.json and the audit checks: same output, different division of labour between me and the machines.