Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision 7922694b27fd0b9c421adfef80ab3c17ddde3a35)
+++ src/routes/activitypub.js	(revision 30871c19bf329fcc6ba2eb4c80c4450c11a044e8)
@@ -169,4 +169,15 @@
 // URIs so their own client can build a friends list; everyone else gets the
 // count only (privacy).
+// FEP-9876: enrichment is opt-in via `Prefer: return=representation` (RFC 7240).
+// Returns true and sets the response headers when the owner asked for it.
+function wantsEnriched(req, res) {
+  res.set('Vary', 'Prefer');   // enriched and bare are two representations
+  if (AP.prefersEnriched(req.get('Prefer'))) {
+    res.set('Preference-Applied', 'return=representation');
+    return true;
+  }
+  return false;
+}
+
 router.get('/ap/users/:slug/followers', (req, res) => {
   const auth = OAuth.verifyBearer(req.headers.authorization);
@@ -176,5 +187,6 @@
   if (owner) {
     const uris = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ? ORDER BY created_at').all(site.slug).map((r) => r.actor_uri);
-    const items = uris.map((u) => AP.buildActorRef(site.slug, u));   // name + avatar (shaer-aa3)
+    // Default = bare references; enrich only when the client asks (FEP-9876).
+    const items = wantsEnriched(req, res) ? uris.map((u) => AP.buildActorRef(site.slug, u)) : uris;
     return AP.sendAP(res, AP.buildFollowers(baseUrl(req), site, items.length, items));
   }
@@ -190,6 +202,10 @@
   if (!site) return res.status(404).end();
   if (owner) {
+    const enrich = wantsEnriched(req, res);   // FEP-9876 opt-in
     let items = [];
-    try { items = db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted' ORDER BY created_at").all(site.slug).map((r) => AP.buildActorRef(site.slug, r.actor_uri)); } catch { /* table may not exist */ }
+    try {
+      const uris = db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted' ORDER BY created_at").all(site.slug).map((r) => r.actor_uri);
+      items = enrich ? uris.map((u) => AP.buildActorRef(site.slug, u)) : uris;
+    } catch { /* table may not exist */ }
     return AP.sendAP(res, AP.buildFollowing(baseUrl(req), site, items.length, items));
   }
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 7922694b27fd0b9c421adfef80ab3c17ddde3a35)
+++ src/services/ActivityPubService.js	(revision 30871c19bf329fcc6ba2eb4c80c4450c11a044e8)
@@ -667,4 +667,10 @@
   } catch { /* ignore */ }
   return { name: null, handle: deriveHandle(uri), icon: null };
+}
+
+// FEP-9876: does this `Prefer` header ask for enriched (embedded) members?
+// Pure and testable; the route sets the response headers around it.
+export function prefersEnriched(preferHeader) {
+  return /(^|[,;\s])return=representation($|[,;\s])/i.test(String(preferHeader || ''));
 }
 
@@ -3070,4 +3076,4 @@
   linkifyBody, bakePostContent, bakePostContentWithMentions, listFollowers, removeFollower, listConnections,
   noteVisibility, isRejectedObject, rejectInteraction, interactionReportTarget,
-  getMessages, notificationsSeenAt, ingestOutboxActivity, c2sVisibility, actorDisplay, buildActorRef,
+  getMessages, notificationsSeenAt, ingestOutboxActivity, c2sVisibility, actorDisplay, buildActorRef, prefersEnriched,
 };
