AI・開発、電子工作、クルマ。実際にやってみたことを残すブログ

ふるさと納税の返礼品を実売価格で比べるサイトを Claude Code と3週間で作った

楽天ふるさと納税の返礼品を、楽天市場の同じ型番の製品の実売価格と突き合わせて「実質還元率」を毎日計算するサイトを、Claude Code と一緒に作りました。3 週間の流れ、Claude Code との進め方、費用が青天井にならないための工夫、データの正しさで苦労したことをまとめます。

アイキャッチ。「ふるさと納税の返礼品を 実売価格で比べるサイトを Claude Code と3週間で作った」という題名が大きく書かれ、右下に Seedflower とある。背景は明るいクリーム色で、左下に贈り物の箱、右上に右肩上がりの棒グラフの小さな絵
アイキャッチ(Hermes Agent 経由で GPT Image が生成)
目次
  1. 作った理由
  2. 全体の仕組み
  3. 3 週間の流れ
  4. Claude Code との進め方
  5. 仕様書を先に書かせ、実装の前に読ませる
  6. やってはいけないことを CLAUDE.md に書く
  7. 守りたいものはテストで固める
  8. 苦労したこと
  9. ページを送っても全件が集まらない
  10. 最安値が中古、ありえない還元率
  11. 小さなつまずき
  12. 料金が青天井にならないように
  13. 公開してみて
  14. まとめ

ふるさと納税の返礼品を、楽天市場で普通に買ったときの値段と比べるサイト「ふるさと納税還元率ナビ」を作りました。

https://furusato-kangen.com/

楽天ふるさと納税の返礼品を型番で楽天市場の同じ製品と突き合わせ、実売価格 ÷ 寄付金額 を「実質還元率」として毎日計算しています。2026 年 10 月 11 日の時点で、22 のカテゴリの返礼品 4,411 件を載せています。

最初のコミットが 9 月 21 日の夜で、この記事を書いている 10 月 11 日までに 287 コミット。設計から実装、毎日の運用まで、ほぼすべてを Claude Code と一緒に進めました。この記事では、その 3 週間の流れと、進め方、苦労したところを書きます。

ふるさと納税還元率ナビのトップページ。左に 22 のカテゴリの絞り込み、右上の説明文に返礼品 4,411 件とあり、その下にカテゴリ 22・自治体 222・メーカー 306・還元率の中央値 24.4%・最高 88.8% の数字、さらに診断への入口と特集の記事が並ぶ
トップページ(2026 年 10 月 11 日)

作った理由

ふるさと納税の返礼品には「〇万円相当」と書かれていますが、普通に買ったらいくらなのかは分かりません。家電のように型番がある返礼品なら、同じ製品が楽天市場で売られているので、その値段と比べられるはずです。「〇万円相当」ではなく「普通に買ったらいくらか」で返礼品を比べたい、というのが動機です。

還元率を比べるサイトはすでにありますが、人の手で調べているので、載っているのは数百〜3,000 品ほどです。照合を自動にすれば、もっと多くの返礼品を比べられると考えました。

返礼品の詳細ページ。日立の炊飯器(RZ-V100KM-K)の返礼品で、寄付金額 112,000 円、楽天市場の最安値 44,080 円、実質還元率 39.4% と表示され、下に楽天ふるさと納税・楽天市場・Amazon へのボタンがある
返礼品の詳細。寄付金額と、同じ型番の楽天市場の最安値を並べる

全体の仕組み

ふるさと納税還元率ナビのデータの流れ。自宅の Linux サーバーで cron が動き、楽天 API から製品と返礼品を取得し、型番を照合し、TypeSafe Jev に同じ製品かを判定させ、還元率を計算して静的サイトを生成する。サイトは Cloudflare の Workers の静的アセットとして配信し、D1 には差分を投入する。WAF のレート制限をかけている。Hermes Agent が書いた文面を毎朝 8 時に X に投稿する。自動更新が失敗したときは Discord に通知が届く
データの流れ。重い処理はすべて自宅のサーバーで行い、Cloudflare には出来上がったページを置く
  1. 取得: 楽天 API から、製品(実売価格の最安値)と返礼品を取ります。楽天 API は登録した IP アドレスからしか呼べないので、取得は自宅の Linux サーバーで行っています
  2. 型番の照合: 返礼品の名前から型番を抜き出し、製品の型番と照合します。全角・半角やハイフン、大文字・小文字をそろえた完全一致 → JAN コード → 色違いの型番、の順に探します
  3. 同じ製品かの判定: 型番が一致しても、セット品やふるさと納税限定のモデルは同じ製品ではありません。ここは TypeSafe の判定用 API「Jev」に、セット品か・限定モデルかを 0〜1 の確率で判定させています。型番の無い返礼品は、候補の製品の中から選ばせます
  4. 還元率の計算とサイトの生成: 実売価格 ÷ 寄付金額で還元率を計算し、テストが通ったら約 5,400 ページの静的サイトを書き出して Cloudflare にデプロイします

これを cron で、月〜土の朝 5 時に動かしています(価格の取り直しからデプロイまで十数分)。日曜は楽天 API から全件を取り直すので、約 12 時間かかります。自動更新が失敗したときは、Discord に通知が届きます。

型番のない返礼品を候補から選ばせるとき、選択肢には必ず「該当なし」を入れています。間違った還元率を載せるよりは、載せない方がよいからです。Jev は入力 100 万トークンあたり $0.042 で、データを作るバッチの中だけで呼び、利用者がページを開いたときには呼びません。

炊飯器の返礼品の一覧ページ。156 件の返礼品について、品目・メーカー・容量で絞り込むボタンが並び、その下に代表機種の実質還元率と寄付額の横棒グラフがある
品目ごとのページ。代表機種の実質還元率を横棒グラフで比べる

3 週間の流れ

コミットの日付で振り返ると、こうなります。

  • 9/21 夜: 雛形、データベース(D1)の設計、型番の照合
  • 9/22: 製品と返礼品の取得、照合、Jev での判定、画面、Terraform での本番の準備、費用の上限対策、SEO、自動更新の cron。この日だけで 58 コミット
  • 9/23: 腕時計、フライパン・鍋、ゴルフクラブなど 9 カテゴリを追加。Amazon アソシエイトのリンク。47 コミット
  • 9/25〜26: デザインの刷新(6 段階)
  • 9/27: 暮らしについての 7 つの質問から返礼品を選ぶ「タイプ診断」
  • 9/28〜29: X への自動投稿。毎朝、時事の話題に絡めたおすすめの返礼品の記事を自動で公開
  • 10/7〜10: note と Zenn に記事を公開

287 コミットのうち 240 件は、Claude との共同作業の印(Co-Authored-By)が付いています。

Claude Code との進め方

自分がしたのは、作りたいものと判断の基準を伝えることと、出てきた結果の確認です。進めてみて効いたと感じたのは次の 3 つです。

仕様書を先に書かせ、実装の前に読ませる

還元率の計算の決まりや、どの返礼品を掲載から外すかといった判断は仕様書にまとめ、実装はそれに従わせました。

Claude Code が毎回読むファイル(CLAUDE.md)には、進め方も書いています。

  • コードを書く前に、ディレクトリ構成と作業手順の計画を示して了承を得る
  • 1 段階ずつ進め、終わったら結果を報告して止まる
  • 仕様書と実装で矛盾や不明点があれば、推測で進めずに質問する

やってはいけないことを CLAUDE.md に書く

「.env の中身を表示しない」「本番への反映は明示的に指示したときだけ(例外は cron のスクリプト)」「Worker の CPU 時間の上限を緩めない」などです。これを書いてからは、任せられる範囲が広がりました。

守りたいものはテストで固める

SEO のための title や構造化データ(JSON-LD)、一覧の絞り込みの動きなどはテストにしてあります。テストのファイルは 53 あります。毎日の自動更新でもテストが落ちたら本番には反映しません。変更を任せても、壊してはいけないところが壊れていないことを機械的に確かめられます。

楽天 API の仕様の調査も、Claude Code が API を実際に呼んで挙動を確かめながら進めました。次の「苦労したこと」の 1 つ目は、そうやって見つかったものです。

苦労したこと

ページを送っても全件が集まらない

楽天の製品検索 API で製品の一覧を作ろうとしたところ、同じ条件で同じページを続けて取っても、中身がほぼ入れ替わる ことが分かりました。最初のやり方では 24% が重複し、約 11,000 件が欠けていました。

そこで、価格帯を分割して、1 回で全部返ってくる大きさ(30 件以下)になるまで細かくしてから取る方式に変えました。22 カテゴリで約 35,000 リクエスト、1 秒に 1 リクエストなので約 10 時間かかります。

最安値が中古、ありえない還元率

製品の最安値をそのまま使うと、中古品の出品が最安値になっていることがありました。今は、最安値が中古と分かったら出品を検索して、新品の最安値に置き換えています。

それでも、ありえない還元率になる返礼品は残ります。還元率が 80% 超か 5% 未満の返礼品を全件(20 件)確かめたところ、正しかったのは 1 件だけでした。誤りの内訳は、実売価格の誤りが 13 件、別の製品との照合違いが 3 件、セット品が 2 件、色や容量の違いが 1 件です。10 月 2 日からは、この範囲の返礼品を自動で外しています。

小さなつまずき

  • 返礼品を 50 件ずつ 1 つの SQL 文にまとめて D1 に入れていたところ、説明文の長いもの(最大 12KB)が重なって、1 文の上限(100KB)を超えてエラー(SQLITE_TOOBIG)になりました。今は件数に加えて大きさでも分け、1 文を 90KB 以下にしています
  • 夜間の作業で git worktree を使ったとき、node_modules へのシンボリックリンクを git add -A でコミットしてしまい、依存が壊れました(npm ci で復旧)。.gitignore の node_modules/ は末尾の / のせいで、シンボリックリンクを除外していませんでした

料金が青天井にならないように

Cloudflare Workers の有料プランは、上限を超えると従量課金になり、支出を止める仕組みがありません。そこで、本番に出す前(9 月 22 日)に、費用が青天井にならないための対策を入れました。方針は「料金がかかる処理を、利用者のアクセスから切り離す」です。

  • 画面はすべて、バッチが書き出した静的なファイルです。Workers の静的アセットへのリクエストは Worker を起動せず、無料・無制限です
  • 一覧の絞り込みやキーワード検索は、書き出した JSON をブラウザの JavaScript で処理します
  • 残る API の Worker は CPU 時間の上限を 50ms に絞っています
  • WAF のレート制限で、同じ IP から 10 秒に 100 リクエストを超えたら 10 秒ブロックします(Terraform で定義)

公開してみて

訪問はまだ多くありません。10 月 10 日の時点で、外から来た訪問は 7 日で約 54 件でした。内訳は次のとおりです。

  • ChatGPT(OpenAI): 27
  • Google: 9
  • X: 8
  • note: 4
  • Bing: 3

いちばん多いのは ChatGPT 経由で、半分を占めています。Google の検索では 1 日に 20〜90 回表示され、平均の順位は 32 位でした。10 月 9 日の Search Console の記録では、「検出 - インデックス未登録」のページが 4,532、登録済みは 1,630 でした。

ふるさと納税の検索は 11〜12 月に集中します。いまは毎週 1〜2 個ずつ改善を本番に出していて、需要の山の前の 11 月 15 日までに、比較の図や年末向けの入口をそろえる予定です。

まとめ

3 週間で、取得から照合、判定、毎日の更新、SNS への投稿まで、ひととおり自動で回るサイトになりました。自分は方針と判断の基準を決め、実装は Claude Code に任せる形です。

仕組みと楽天 API のハマりどころ、照合の精度は、Zenn にもう少し詳しく書いています。

年末にふるさと納税で家電などを選ぶときは、よかったら使ってみてください。

https://furusato-kangen.com/