{
"$type": "site.standard.document",
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreigiczvz333ibzigzex32zulrajuxxss72qqy2touaci23pzdqmgbq"
},
"mimeType": "image/webp",
"size": 72204
},
"path": "/3mm4vj547mc2x",
"publishedAt": "2026-05-18T12:40:30.781Z",
"site": "at://did:plc:6zpjzzdzet62go7lnaoq4xog/site.standard.publication/3miuky5ozz22g",
"tags": [
"bluesky",
"AdventCalendar"
],
"textContent": "Blueskyのウワサ(クシュン)\n\nはじめに\n\n本記事はBluesky Advent Calendar 2025の4日目の記事の複製です。\n\n2024年5月ごろに実装されたFeedFeedbackAPIについて、当時書きかけたままサードパーティーへの開放を待っているうちに忘れていた記事を、出すなら今かということで空き枠に滑り込ませてもらいます。(1年以上間が空いているのでつじつま合わない所あったらすみません)\n\n⏪3日目はすいばり(@suibari.com)さんの「Bluesky AI Bot「全肯定botたん」の2025年の軌跡」です\n\n⏩5日目は桃色豆腐(@momoiro.me)さんの「公式pdsから引っ越して、公式pdsに戻ってみるまで試す」です\n\n拙作の記事投稿についてのPostをまとめたカスタムフィード(by Bluefeed)もあります\n\nこれなに\n\nBlueskyの公式アプリのバージョン1.81.0にて、カスタムフィードに対してのフィードバック\"Show more like this(このような投稿の表示を増やす)🙂\",\"Show less like this(このような投稿の表示を減らす)☹\"が送信できるようになりました。(後述しますが他にもフィードバックが送られています。)\n\nこれは先日のProduct Roadmapにあった \"New feedback mechanisms which the algorithmic feeds can request, such as “show more” and “show less” buttons, and a way to track which posts have been seen to stop duplicates from showing so often.\"によるもので、フィードバックによって表示される内容を変化させることができるようになるみたいです。\n\nリリース内容にもありますが、この機能は1.81.0時点では公式のDiscoverフィードに対してのみ動作しますていました。ですが今後は他のカスタムフィードにも開放されるようなので、 その後1年の時を経て1.107.0、1.109.0にてサードパーティーのカスタムフィードに対しても開放されるようになりました。拙作のRepostNextPostにも対応しましたが、その際にGitHubのコードに潜って探索した記録を残しておこうと思います。\n\nスキーマ実装:atproto#2383\n\n\n\n\n\napp.bsky.feed.defs#feedViewPost\nこちらはapp.bsky.feed.getFeedで取得されるPostに付加されるもののようです。(PDS→クライアント)\n\n\n\n\n\nfeedContextが追加 ^feedViewPost\n\n\"feedContext\": {\n \"type\": \"string\",\n \"description\": \"Context provided by feed generator that may be passed back alongside interactions.\",\n \"maxLength\": 2000\n}\n\n\n\n\nreqIdが追加^reqId\n\n\"reqId\": {\n \"type\": \"string\",\n \"description\": \"Unique identifier per request that may be passed back alongside interactions.\",\n \"maxLength\": 100\n}\n\n\n\n\napp.bsky.feed.defs#generatorView\n\n\n\n\n\nacceptsInteractionsが追加 ^generatorView\nこちらはapp.bsky.feed.getFeedGeneratorでフィードジェネレーターの情報を返す際にインタラクションを受け取ることができるかを返すようです。\n\n\"acceptsInteractions\": {\n \"type\": \"boolean\"\n}\n\n\n\n\napp.bsky.feed.defs#skeletonFeedPost\n\n\n\n\n\nfeedContextが追加 ^skeltonFeedPost\nこちらはapp.bsky.feed.getFeedSkeletonで返すPostに付加するもののようです。(フィードジェネレーター→AppView→PDS→クライアントのfeedViewPostへ)\n\n \"feedContext\": {\n \"type\": \"string\",\n \"description\": \"Context that will be passed through to client and may be passed to feed generator back alongside interactions.\",\n \"maxLength\": 2000\n }\n\n\n\n\napp.bsky.feed.defs#interaction が追加^interaction\nフィードジェネレーター側へ送られるフィードバック(interaction)と、getFeedSkeletonで渡したfeedContext、reqIdが定義されています。\n\n\"interaction\": {\n \"type\": \"object\",\n \"properties\": {\n \"item\": { \"type\": \"string\", \"format\": \"at-uri\" },\n \"event\": {\n \"type\": \"string\",\n \"knownValues\": [\n \"app.bsky.feed.defs#requestLess\",\n \"app.bsky.feed.defs#requestMore\",\n \"app.bsky.feed.defs#clickthroughItem\",\n \"app.bsky.feed.defs#clickthroughAuthor\",\n \"app.bsky.feed.defs#clickthroughReposter\",\n \"app.bsky.feed.defs#clickthroughEmbed\",\n \"app.bsky.feed.defs#interactionSeen\",\n \"app.bsky.feed.defs#interactionLike\",\n \"app.bsky.feed.defs#interactionRepost\",\n \"app.bsky.feed.defs#interactionReply\",\n \"app.bsky.feed.defs#interactionQuote\",\n \"app.bsky.feed.defs#interactionShare\"\n ]\n },\n \"feedContext\": {\n \"type\": \"string\",\n \"description\": \"Context on a feed item that was orginally supplied by the feed generator on getFeedSkeleton.\",\n \"maxLength\": 2000\n }\n \"reqId\": {\n \"type\": \"string\",\n \"description\": \"Unique identifier per request that may be passed back alongside interactions.\",\n \"maxLength\": 100\n }\n }\n},\n\n\n\n\n以下、interactionのknownValuesたち\n\n\n\n\n\napp.bsky.feed.defs#requestLess が追加 ^requestLess\nPostのメニューから\"Show less like this(このような投稿の表示を減らす)☹\"を選択された場合に送信されます。\n\n\"requestLess\": {\n \"type\": \"token\",\n \"description\": \"Request that less content like the given feed item be shown in the feed\"\n},\n\n\n\n\napp.bsky.feed.defs#requestMore が追加 ^requestMore\nPostのメニューから\"Show more like this(このような投稿の表示を増やす)🙂\"を選択された場合に送信されます。\n\n\"requestMore\": {\n \"type\": \"token\",\n \"description\": \"Request that more content like the given feed item be shown in the feed\"\n},\n\n\n\n\napp.bsky.feed.defs#clickthroughItem が追加 ^clickthroughItem\nPostをクリック(タップ)してPostの画面を開いた場合に送信されます。\n\n\"clickthroughItem\": {\n \"type\": \"token\",\n \"description\": \"User clicked through to the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#clickthroughAuthor が追加 ^clickthroughAuthor\nPostのアバターや名前をクリックしてプロフィール画面を開いた場合に送信されます。\n\n\"clickthroughAuthor\": {\n \"type\": \"token\",\n \"description\": \"User clicked through to the author of the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#clickthroughReposter が追加 ^clickthroughReposter\nPostの「~~がリポスト」をクリックしてリポスト者を開いた場合に送信されます。\n\n\"clickthroughReposter\": {\n \"type\": \"token\",\n \"description\": \"User clicked through to the reposter of the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#clickthroughEmbed が追加 ^clickthroughEmbed\nPostのリンクカードや引用など埋め込みをクリックして開いた場合に送信されます。\n\n\"clickthroughEmbed\": {\n \"type\": \"token\",\n \"description\": \"User clicked through to the embedded content of the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#interactionSeen が追加 ^interactionSeen\nPostを一定時間表示させた場合に送信されます。\n\n\"interactionSeen\": {\n \"type\": \"token\",\n \"description\": \"Feed item was seen by user\"\n},\n\n\n\n\napp.bsky.feed.defs#interactionLike が追加 ^interactionLike\nPostにいいねした場合に送信されます。\n\n\"interactionLike\": {\n \"type\": \"token\",\n \"description\": \"User liked the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#interactionRepost が追加 ^interactionRepost\nPostをRepostした場合に送信されます。\n\n\"interactionRepost\": {\n \"type\": \"token\",\n \"description\": \"User reposted the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#interactionReply が追加 ^interactionReply\nPostに返信しようとした場合に送信されます。\n\n\"interactionReply\": {\n \"type\": \"token\",\n \"description\": \"User replied to the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#interactionQuote が追加 ^interactionQuote\nPostを引用しようとした場合に送信されます。\n\n\"interactionQuote\": {\n \"type\": \"token\",\n \"description\": \"User quoted the feed item\"\n},\n\n\n\n\napp.bsky.feed.defs#interactionShare が追加 ^interactionShare\nPostを共有しようとした場合に送信されます。\n\n\"interactionShare\": {\n \"type\": \"token\",\n \"description\": \"User shared the feed item\"\n}\n\n\nPDS/Appview実装:atproto#2402\n\nアプリから送信されたInteractionやフィードジェネレーターからのfeedContextをPDSを通してAppViewと送受信する実装です。\n\n公式アプリ実装:social-app#3498\n\nスキーマ側で実装されたInteractionがどのように送信されるかを見ていきます。\n\n\n\n\n\npackages.json\n\n\n\n\n\nlodash/throttleが追加されており、後ほど出てきますが一定間隔でInteractionの送信を制御するのに使用されています。\n\n\n\nsrc/state/feed-feedback.tsx\n\n\n\n\n\nFeedFeedbackの実体です。\n\nfixes(1.82.0で実装):social-app#3968\n\n1.81.0リリース後に行われている修正(改善)です。\n\n\n\n\n\ninteractionSeenの判定する時間を1.5秒に変更\n\n\n\nリプライ元のPostについてもFeedContextを返すように修正(ちゃんと動き読めてないかも)\n\nInclude feedContext in DOM as data-(1.84.0で実装) :social-app#4206\n\n\n\n\n\nskeletonFeedPostのfeedContextが各Postのdivタグにdata-feed-contextとして出力されるように変更\n\nEnable show less / more buttons for third party feeds(1.107.0で実装) social-app#8672\n\n\n\n\n\nサードパーティーのカスタムフィードにもrequestLessとrequestMoreを送信するよう変更\n\nSend inferrable interactions to third-party feeds(1.109.0で実装) social-app#9094\n\n\n\n\n\ninteractionLike、interactionQuote、interactionReply、interactionRepost、interactionSeenも送信するよう変更\n\n\n\n以前Kyoto mini meetupでdan氏にQAでサードパーティーへの開放について聞いてもらった際、PRにも記述があるように、interactionSeenは\"privacy-sensitive\"という回答をもらっていました。ですが、ページネーションで次のページを取得する=それまでの投稿はスクロールで閲覧されているということになるため、既読の情報を送る用にした方がメリットも大きく対応されることとなりました。\n\n結局対応するにはどうすればいいの\n\n自前のカスタムフィードで対応したPRが多少参考にはなると思いますが主に2点変更が必要です。\n\napp.bsky.feed.generatorレコードの変更\n\n\n\n\n\nカスタムフィード登録時のapp.bsky.feed.generatorレコードにacceptsInteractionsを追加します。\n\n{\n ...\n \"$type\": \"app.bsky.feed.generator\",\n ...\n \"acceptsInteractions\": true\n}\n\n\napp.bsky.feed.sendInteractionsのXRPC対応\n\n\n\n\n\nexample.com/xrpc/app.bsky.feed.sendInteractionsに上記のInteractionが送信されてきますので、それに対して処理を行います。\n\n{\n \"interactions\": [\n {\n \"$type\": \"app.bsky.feed.defs#interaction\",\n \"item\": \"at://did:plc:xxxxxxxxxxxxxxxxxxxxxxxx/app.bsky.feed.post/xxxxxxxxxxxxx\",\n \"event\": \"app.bsky.feed.defs#xxxxxxxxxxx\",\n \"feedContext\": \"context\",\n \"reqId\": \"\"\n },\n ...\n ]\n\n\nfeedContextの対応\n\n\n\n\n\nsendInteractionsの中身にコンテキストを転送したい場合はapp.bsky.feed.getFeedSkeletonにfeedContextを追加します。(RepostNextPostでは対応していません)\n\n{\n \"feed\": [\n \"post\": \"at://did:plc:xxxxxxxxxxxxxxxxxxxxxxxx/app.bsky.feed.post/xxxxxxxxxxxxx\",\n \"feedContext\": \"context\"\n ],\n \"cursor\": \"xxxxxxxxxxx\"\n}\n\n\nさいごに\n\nRepostNextPostではrequestLessで投稿を非表示、requestMoreで最後に非表示にした投稿を再表示という処理を入れましたが、 初のDiscoverフィードのように表示内容をいろいろカスタムに活用できるかと思いますので参考になれば幸いです。 それではみなさまよいBlueskyライフを!\n\n(再掲) ⏩5日目は桃色豆腐(@momoiro.me)さんの「公式pdsから引っ越して、公式pdsに戻ってみるまで試す」です",
"title": "FeedFeedbackAPIってなんなんだー?",
"updatedAt": "2026-05-18T12:40:30.781Z"
}