FeedFeedbackAPIってなんなんだー?
Table of Contents
Blueskyのウワサ(クシュン)
はじめに
本記事はBluesky Advent Calendar 2025の4日目の記事の複製です。
2024年5月ごろに実装されたFeedFeedbackAPIについて、当時書きかけたままサードパーティーへの開放を待っているうちに忘れていた記事を、出すなら今かということで空き枠に滑り込ませてもらいます。(1年以上間が空いているのでつじつま合わない所あったらすみません)
⏪3日目はすいばり(@suibari.com)さんの「Bluesky AI Bot「全肯定botたん」の2025年の軌跡」です
⏩5日目は桃色豆腐(@momoiro.me)さんの「公式pdsから引っ越して、公式pdsに戻ってみるまで試す」です
拙作の記事投稿についてのPostをまとめたカスタムフィード(by Bluefeed)もあります
これなに
Blueskyの公式アプリのバージョン1.81.0にて、カスタムフィードに対してのフィードバック"Show more like this(このような投稿の表示を増やす)🙂","Show less like this(このような投稿の表示を減らす)☹"が送信できるようになりました。(後述しますが他にもフィードバックが送られています。)
これは先日の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."によるもので、フィードバックによって表示される内容を変化させることができるようになるみたいです。
リリース内容にもありますが、この機能は1.81.0時点では公式のDiscoverフィードに対してのみ動作しますていました。ですが今後は他のカスタムフィードにも開放されるようなので、 その後1年の時を経て1.107.0、1.109.0にてサードパーティーのカスタムフィードに対しても開放されるようになりました。拙作のRepostNextPostにも対応しましたが、その際にGitHubのコードに潜って探索した記録を残しておこうと思います。
スキーマ実装:atproto#2383
app.bsky.feed.defs#feedViewPost
こちらはapp.bsky.feed.getFeedで取得されるPostに付加されるもののようです。(PDS→クライアント)feedContextが追加 ^feedViewPost
JSON"feedContext": { "type": "string", "description": "Context provided by feed generator that may be passed back alongside interactions.", "maxLength": 2000 }reqIdが追加^reqId
JSON"reqId": { "type": "string", "description": "Unique identifier per request that may be passed back alongside interactions.", "maxLength": 100 }
app.bsky.feed.defs#generatorView
acceptsInteractionsが追加 ^generatorView
こちらはapp.bsky.feed.getFeedGeneratorでフィードジェネレーターの情報を返す際にインタラクションを受け取ることができるかを返すようです。JSON"acceptsInteractions": { "type": "boolean" }
app.bsky.feed.defs#skeletonFeedPost
feedContextが追加 ^skeltonFeedPost
こちらはapp.bsky.feed.getFeedSkeletonで返すPostに付加するもののようです。(フィードジェネレーター→AppView→PDS→クライアントのfeedViewPostへ)JSON"feedContext": { "type": "string", "description": "Context that will be passed through to client and may be passed to feed generator back alongside interactions.", "maxLength": 2000 }
app.bsky.feed.defs#interaction が追加^interaction
フィードジェネレーター側へ送られるフィードバック(interaction)と、getFeedSkeletonで渡したfeedContext、reqIdが定義されています。JSON"interaction": { "type": "object", "properties": { "item": { "type": "string", "format": "at-uri" }, "event": { "type": "string", "knownValues": [ "app.bsky.feed.defs#requestLess", "app.bsky.feed.defs#requestMore", "app.bsky.feed.defs#clickthroughItem", "app.bsky.feed.defs#clickthroughAuthor", "app.bsky.feed.defs#clickthroughReposter", "app.bsky.feed.defs#clickthroughEmbed", "app.bsky.feed.defs#interactionSeen", "app.bsky.feed.defs#interactionLike", "app.bsky.feed.defs#interactionRepost", "app.bsky.feed.defs#interactionReply", "app.bsky.feed.defs#interactionQuote", "app.bsky.feed.defs#interactionShare" ] }, "feedContext": { "type": "string", "description": "Context on a feed item that was orginally supplied by the feed generator on getFeedSkeleton.", "maxLength": 2000 } "reqId": { "type": "string", "description": "Unique identifier per request that may be passed back alongside interactions.", "maxLength": 100 } } },以下、interactionのknownValuesたち
app.bsky.feed.defs#requestLess が追加 ^requestLess
Postのメニューから"Show less like this(このような投稿の表示を減らす)☹"を選択された場合に送信されます。JSON"requestLess": { "type": "token", "description": "Request that less content like the given feed item be shown in the feed" },app.bsky.feed.defs#requestMore が追加 ^requestMore
Postのメニューから"Show more like this(このような投稿の表示を増やす)🙂"を選択された場合に送信されます。JSON"requestMore": { "type": "token", "description": "Request that more content like the given feed item be shown in the feed" },app.bsky.feed.defs#clickthroughItem が追加 ^clickthroughItem
Postをクリック(タップ)してPostの画面を開いた場合に送信されます。JSON"clickthroughItem": { "type": "token", "description": "User clicked through to the feed item" },app.bsky.feed.defs#clickthroughAuthor が追加 ^clickthroughAuthor
Postのアバターや名前をクリックしてプロフィール画面を開いた場合に送信されます。JSON"clickthroughAuthor": { "type": "token", "description": "User clicked through to the author of the feed item" },app.bsky.feed.defs#clickthroughReposter が追加 ^clickthroughReposter
Postの「~~がリポスト」をクリックしてリポスト者を開いた場合に送信されます。JSON"clickthroughReposter": { "type": "token", "description": "User clicked through to the reposter of the feed item" },app.bsky.feed.defs#clickthroughEmbed が追加 ^clickthroughEmbed
Postのリンクカードや引用など埋め込みをクリックして開いた場合に送信されます。JSON"clickthroughEmbed": { "type": "token", "description": "User clicked through to the embedded content of the feed item" },app.bsky.feed.defs#interactionSeen が追加 ^interactionSeen
Postを一定時間表示させた場合に送信されます。JSON"interactionSeen": { "type": "token", "description": "Feed item was seen by user" },app.bsky.feed.defs#interactionLike が追加 ^interactionLike
Postにいいねした場合に送信されます。JSON"interactionLike": { "type": "token", "description": "User liked the feed item" },app.bsky.feed.defs#interactionRepost が追加 ^interactionRepost
PostをRepostした場合に送信されます。JSON"interactionRepost": { "type": "token", "description": "User reposted the feed item" },app.bsky.feed.defs#interactionReply が追加 ^interactionReply
Postに返信しようとした場合に送信されます。JSON"interactionReply": { "type": "token", "description": "User replied to the feed item" },app.bsky.feed.defs#interactionQuote が追加 ^interactionQuote
Postを引用しようとした場合に送信されます。JSON"interactionQuote": { "type": "token", "description": "User quoted the feed item" },app.bsky.feed.defs#interactionShare が追加 ^interactionShare
Postを共有しようとした場合に送信されます。JSON"interactionShare": { "type": "token", "description": "User shared the feed item" }
PDS/Appview実装:atproto#2402
アプリから送信されたInteractionやフィードジェネレーターからのfeedContextをPDSを通してAppViewと送受信する実装です。
公式アプリ実装:social-app#3498
スキーマ側で実装されたInteractionがどのように送信されるかを見ていきます。
lodash/throttleが追加されており、後ほど出てきますが一定間隔でInteractionの送信を制御するのに使用されています。
FeedFeedbackの実体です。
fixes(1.82.0で実装):social-app#3968
1.81.0リリース後に行われている修正(改善)です。
interactionSeenの判定する時間を1.5秒に変更
リプライ元のPostについてもFeedContextを返すように修正(ちゃんと動き読めてないかも)
Include feedContext in DOM as data-(1.84.0で実装) :social-app#4206
skeletonFeedPostのfeedContextが各Postのdivタグに
data-feed-contextとして出力されるように変更
Enable show less / more buttons for third party feeds(1.107.0で実装) social-app#8672
サードパーティーのカスタムフィードにもrequestLessとrequestMoreを送信するよう変更
Send inferrable interactions to third-party feeds(1.109.0で実装) social-app#9094
interactionLike、interactionQuote、interactionReply、interactionRepost、interactionSeenも送信するよう変更
以前Kyoto mini meetupでdan氏にQAでサードパーティーへの開放について聞いてもらった際、PRにも記述があるように、interactionSeenは"privacy-sensitive"という回答をもらっていました。ですが、ページネーションで次のページを取得する=それまでの投稿はスクロールで閲覧されているということになるため、既読の情報を送る用にした方がメリットも大きく対応されることとなりました。
結局対応するにはどうすればいいの
自前のカスタムフィードで対応したPRが多少参考にはなると思いますが主に2点変更が必要です。
app.bsky.feed.generatorレコードの変更
カスタムフィード登録時のapp.bsky.feed.generatorレコードにacceptsInteractionsを追加します。
{
...
"$type": "app.bsky.feed.generator",
...
"acceptsInteractions": true
}
app.bsky.feed.sendInteractionsのXRPC対応
example.com/xrpc/app.bsky.feed.sendInteractionsに上記のInteractionが送信されてきますので、それに対して処理を行います。
{
"interactions": [
{
"$type": "app.bsky.feed.defs#interaction",
"item": "at://did:plc:xxxxxxxxxxxxxxxxxxxxxxxx/app.bsky.feed.post/xxxxxxxxxxxxx",
"event": "app.bsky.feed.defs#xxxxxxxxxxx",
"feedContext": "context",
"reqId": ""
},
...
]
feedContextの対応
sendInteractionsの中身にコンテキストを転送したい場合はapp.bsky.feed.getFeedSkeletonにfeedContextを追加します。(RepostNextPostでは対応していません)
{
"feed": [
"post": "at://did:plc:xxxxxxxxxxxxxxxxxxxxxxxx/app.bsky.feed.post/xxxxxxxxxxxxx",
"feedContext": "context"
],
"cursor": "xxxxxxxxxxx"
}
さいごに
RepostNextPostではrequestLessで投稿を非表示、requestMoreで最後に非表示にした投稿を再表示という処理を入れましたが、 初のDiscoverフィードのように表示内容をいろいろカスタムに活用できるかと思いますので参考になれば幸いです。 それではみなさまよいBlueskyライフを!
(再掲) ⏩5日目は桃色豆腐(@momoiro.me)さんの「公式pdsから引っ越して、公式pdsに戻ってみるまで試す」です
地方のしがないエンジニアもどき 中身はただのアイマスP From:Nara🦌, Japan🇯🇵 Since:2023/03/16
No comments yet