Index: src/services/CircleFederation.js
===================================================================
--- src/services/CircleFederation.js	(revision 62b899d95ceecddb71c476a3a1f292529c006d92)
+++ src/services/CircleFederation.js	(revision 221a2097e364410e12aa34d7c668aab224bd16b4)
@@ -85,4 +85,12 @@
 }
 
+// Tags-kolom (JSON-array of comma-separated) -> nette string-array.
+function parseTags(raw) {
+  if (!raw) return [];
+  if (Array.isArray(raw)) return raw.map((t) => String(t).trim()).filter(Boolean);
+  try { const j = JSON.parse(raw); if (Array.isArray(j)) return j.map((t) => String(t).trim()).filter(Boolean); } catch { /* geen JSON */ }
+  return String(raw).split(',').map((t) => t.trim()).filter(Boolean);
+}
+
 function iso(d) {
   const t = d ? new Date(d) : new Date();
@@ -136,5 +144,5 @@
 
   const rows = db.prepare(`
-    SELECT slug, title, excerpt, content, cover_image_url, published_at, created_at, type
+    SELECT slug, title, excerpt, content, cover_image_url, published_at, created_at, type, tags
     FROM posts
     WHERE site_id = ? AND status = 'published'
@@ -148,4 +156,5 @@
     const published = iso(p.published_at || p.created_at);
     const summary = (p.excerpt || stripHtml(p.content)).slice(0, 500);
+    const tags = parseTags(p.tags).slice(0, 12);
     return {
       type: 'Create',
@@ -161,4 +170,6 @@
         published,
         ...(p.cover_image_url ? { image: { type: 'Image', url: abs(base, p.cover_image_url) } } : {}),
+        // ActivityStreams: tags als Hashtag-objecten (href naar de bron-tagpagina).
+        ...(tags.length ? { tag: tags.map((t) => ({ type: 'Hashtag', name: '#' + String(t).replace(/^#/, ''), href: `${base}/tag/${encodeURIComponent(t)}` })) } : {}),
       },
     };
Index: src/services/CircleService.js
===================================================================
--- src/services/CircleService.js	(revision 62b899d95ceecddb71c476a3a1f292529c006d92)
+++ src/services/CircleService.js	(revision 221a2097e364410e12aa34d7c668aab224bd16b4)
@@ -29,4 +29,14 @@
 function baseOf(remoteUrl) {
   return String(remoteUrl).replace(/\/+$/, '');
+}
+
+// AS Hashtag-array -> comma-separated tagnamen (zonder #), gesanitized.
+function extractTags(tag) {
+  if (!Array.isArray(tag)) return null;
+  const names = tag
+    .map((t) => String((t && t.name) || '').replace(/^#/, '').trim())
+    .filter(Boolean)
+    .slice(0, 12);
+  return names.length ? names.join(', ') : null;
 }
 
@@ -83,9 +93,10 @@
     `),
     upsertPost: db.prepare(`
-      INSERT INTO remote_posts (id, actor_id, published, title, summary, url, media_json, raw_json, fetched_at)
-      VALUES (@id, @actor_id, @published, @title, @summary, @url, @media_json, @raw_json, CURRENT_TIMESTAMP)
+      INSERT INTO remote_posts (id, actor_id, published, title, summary, url, media_json, tags, raw_json, fetched_at)
+      VALUES (@id, @actor_id, @published, @title, @summary, @url, @media_json, @tags, @raw_json, CURRENT_TIMESTAMP)
       ON CONFLICT(id) DO UPDATE SET
         published=excluded.published, title=excluded.title, summary=excluded.summary,
-        url=excluded.url, media_json=excluded.media_json, raw_json=excluded.raw_json, fetched_at=CURRENT_TIMESTAMP
+        url=excluded.url, media_json=excluded.media_json, tags=excluded.tags,
+        raw_json=excluded.raw_json, fetched_at=CURRENT_TIMESTAMP
     `),
   };
@@ -169,4 +180,5 @@
       url: obj.url || obj.id,
       media_json: media.length ? JSON.stringify(media) : null,
+      tags: extractTags(obj.tag),
       raw_json: JSON.stringify(obj).slice(0, 20000),
     });
