Show original
Try the app

5本だけ
Enjoyed this article?
Support Serious playful
AI translation
サブスク時代の「選べない」パラドックス
Try the app

5本だけ
Enjoyed this article?
Support Serious playful
Have you ever opened Netflix, scrolled for 15 minutes, and then just ended up playing the same show you always watch?
You might think that more options would increase satisfaction, but psychology actually shows the opposite—it's called the "paradox of choice." When there are too many options, people tend to postpone decisions or end up less satisfied with their choice afterward.
I noticed the exact same thing happening with FANZA's video streaming service. Despite having a massive catalog, users just endlessly scroll through thumbnails in search results and ultimately settle for "the usual." So I wondered: what if I created a site that deliberately reduces choices instead? That's what led me to personally develop an app called "5 Books Only."
No matter what filters you select or how you search on FANZA, you always get back a maximum of 5 results. Nothing more.
At first, I only built simple filter search (category, fetish tags, release year, price range, review rating), but I realized that wouldn't resonate with people who still couldn't decide what to watch. So I added a 30-second AI diagnosis bot.
Answer a few questions about mood, situation, appearance preferences, and deal-breakers, and the system scores your responses, outputs a type diagnosis like "You're the ○○ type," and recommends exactly 5 matching titles.
The diagnosis results are shareable. The results page includes a bar graph of your fetish type and an X (formerly Twitter) share button. When someone clicks a shared link, they're prompted to take the same diagnosis. However, since this is an adult service, there's a risk of violating terms of service if explicit keywords or images spread directly on SNS. So I implemented:
It's a subtle but important point: never expose explicit terminology directly on public-facing pages.
When using the DMM Affiliate API, the <affiliate_id` requires an API-specific <-990` suffix for authentication, but this is invalid as an actual affiliate click link. API authentication would succeed, but when users actually clicked, they'd see "invalid link"—a bug I discovered during user testing after launch and had to scramble to fix. Since then, I always manage authentication IDs and registered click IDs in separate environment variables.
The <`article_id` parameter in DMM ItemList API only accepts one genre ID per request. Even if users select multiple tags, internally I only use the first one for API-side filtering, and post-filter the remaining tags on the app side after fetching the response.
I wanted to recalculate rankings hourly and write them to cache, but Cloudflare Pages doesn't natively support Cron Triggers (that's a Workers-only feature). So I set up a lightweight separate Worker that shares the main D1/KV, and configured Cron only on that Worker.
In the AI diagnosis scoring, all questions initially had equal weight, causing frequent ties. This meant priority was accidentally determined by answer input order (JavaScript Map insertion order), so the "appearance type" answer—which should have been most specific—would lose to vague questions like "today's mood." I fixed it by establishing <`見た目 > プレイの好み > 年代 > 雰囲気` as a clear hierarchy.
The contrarian UX of "narrowing down to just 5 results" instead of "expanding options" feels promising to me. I've set up three entry points—filter search, AI diagnosis, and "feeling lucky" (gacha-style random pick)—all converging on "curated 5 results."
The tech stack is Cloudflare Pages + Pages Functions + D1 + KV + separate Cron Worker. Even as a solo project, it's fully serverless and keeps infrastructure costs very low.
If you're interested, please give it a try (18+ only).
#IndieHacking #CloudflarePages #DMMAPI #FANZA Affiliate
##
Netflixを開いて15分スクロールした挙句、結局いつも見てる作品を再生する——って経験、ありませんか?
選択肢が増えるほど満足度が上がるかというと、実はそうでもなくて、心理学では「選択のパラドックス」と呼ばれています。選択肢が多すぎると人は逆に決断を先延ばしにしたり、選んだあとの満足度がむしろ下がったりする現象です。
これ、FANZAの動画配信でも全く同じことが起きているなと思っていました。作品数は膨大なのに、検索してもズラッと並ぶサムネイルを延々スクロールするだけで、結局「いつもの」に落ち着く。だったら逆に、選択肢を思い切って減らしてしまうサイトを作ったらどうなるかを試したくなり、個人開発で「5本だけ」というアプリを作りました。
条件を選んでもFANZAで検索しても、返ってくるのは常に最大5本だけ。それ以上は出しません。
最初はシンプルなフィルタ検索(カテゴリ・性癖タグ・年代・価格帯・レビュー評価)だけを作ったのですが、それだけだと「結局何を選べばいいか分からない」人には刺さらないと気づきました。
そこで追加したのが30秒のAI診断ボットです。雰囲気・シチュエーション・見た目の好み・NG要素などいくつかの質問に答えるだけで、スコアリングして「あなたは○○型です」というタイプ診断結果を出し、そこから合う作品を5本だけ提案する仕組みにしました。
さらに、診断結果はシェアできるようにしています。診断結果ページに性癖タイプの棒グラフとX(旧Twitter)共有ボタンを付けて、シェアされたリンクを踏んだ人にも同じ診断を促す導線を作りました。ただしこれはアダルトサービスなので、SNS上でそのままセンシティブな単語や画像が流れると規約に触れるリスクがあります。なので:
という工夫を入れています。露骨な単語をそのまま公開面に出さない、というのは地味に重要なポイントでした。
DMMアフィリエイトAPIを使う際、`affiliate_id`にはAPI専用の`-990`系サフィックスが必要で、これは実際にAFFする(クリックされる)リンクとしては無効でした。API認証は通るのに、実際にユーザーがクリックすると「無効なリンクです」と表示される——というバグを本番リリース後にユーザーの実機テストで発見し、慌てて修正しました。以来、API認証用IDとクリック用登録済みIDは必ず別の環境変数で管理するようにしています。
DMM ItemList APIの`article_id`パラメータは、1回のリクエストで指定できるジャンルIDが1つだけ。複数タグを選んでも、内部的には先頭の1件だけをAPI側の絞り込みに使い、残りはレスポンスを取得したあとにアプリ側でポストフィルタする設計にしています。
「毎時ランキングを再集計してキャッシュに書き込む」ような定期実行がしたかったのですが、Cloudflare PagesはCron Triggerをネイティブでサポートしていません(Workers専用機能)。そこで、本体のD1/KVを共有する軽量な別Workerを立てて、そちらにだけCronを設定する構成にしました。
AI診断のスコアリングで、最初は全質問が同じ重みだったため同点が頻発し、たまたま回答の入力順(JSのMap挿入順)で優先度が決まってしまうというバグがありました。結果、本来一番具体的なはずの「見た目のタイプ」の回答が、曖昧な「今日の気分」的な質問に負けてしまう——という事故です。重みを`見た目 > プレイの好み > 年代 > 雰囲気`という明確な階層に直して解決しました。
「選択肢を増やす」のではなく「絞り込んで、5本だけ提示する」という逆張りのUXは、個人的には手応えを感じています。フィルタ検索・AI診断・フィーリングラッキー(ガチャ的に1本おまかせ)の3つの入り口を用意して、どれも最終的には「厳選5本」に収束する設計です。
技術スタックはCloudflare Pages + Pages Functions + D1 + KV + 別Cron Worker。個人開発でもサーバーレスで完結できて、インフラコストもかなり抑えられています。
気になった方はぜひ触ってみてください(18歳未満の方はご遠慮ください)。
#個人開発 #CloudflarePages #DMMAPI #FANZA アフィリエイト