メインコンテンツへスキップ
← 記事一覧に戻る
·運営·13 min read

YouTube Data API の quota 枯渇で申請書を書いた日 — 個人開発で最初に詰まる壁

recipe-aiYouTube API個人開発Build in Public

recipe-ai の料理名検索機能が朝から死んでいた。Vercel のログを見ると、YouTube Data API v3 が 403 を返している。body には quotaExceeded

1 日 100 検索で使い切った。

この記事は、無料枠の YouTube API に依存したサービスが、どの瞬間にスケールしなくなるか、そしてその壁をどう乗り越えるか(または乗り越えないか)の記録だ。

この記事でわかること:

  • YouTube Data API v3 の quota(unit)の仕組み
  • なぜ search.list だけが圧倒的に高い(100 units/request)
  • 10,000 units/日 が個人開発のどの瞬間に壁になるか
  • quota 枯渇時の 429 + 専用メッセージ実装
  • Google Cloud に quota 増額申請する具体的な書き方
  • 申請の審査期間(7〜14 日)をどう乗り越えるか

YouTube Data API v3 の quota の仕組み

Google の YouTube Data API v3 は完全無料で使える。ただし 1 日の使用量に制限があり、これを unit というポイントで管理している。

デフォルト無料枠: 10,000 units/日。日付が変わる(太平洋時刻 00:00 = JST 16:00〜17:00)とリセットされる。

API メソッドごとに消費 unit が違う:

メソッド1 リクエスト用途
search.list100 unitsキーワード検索(最重)
videos.list1 unit動画詳細取得
channels.list1 unitチャンネル情報
commentThreads.list1 unitコメント取得

search.list だけが桁違いに重い。 10,000 units/日 ÷ 100 units = 1 日 100 検索までという構造になる。


なぜ search.list がこんなに高いか

Google 側の事情として、search.list はインデックス全体を横断する重い処理だからだ。他の list 系 API は、videoId や channelId が特定されている前提での直接参照なので、インデックス引き 1 回で済む。

検索は全動画から関連性計算が必要で、Google 側のコストが高い。unit 100 倍の設計は、その重さを正直に反映している。


100 ユーザーで破綻する構造

recipe-ai の料理名検索は、ユーザーが検索するたびに search.list を叩く。キャッシュは 6 時間 ISR で効かせているので、同じクエリの 2 回目以降は 0 unit。ただし:

  • ユーザー A が「カレー」で検索 → 100 units
  • ユーザー A が 6 時間以内に再び「カレー」→ キャッシュヒット、0 units
  • ユーザー B が同じ日に「肉じゃが」で検索 → 100 units
  • ユーザー B が翌日「親子丼」で検索 → 100 units(前日のキャッシュは消えている)

実際には 100 人のユニークユーザーが同時に検索する瞬間に、100 × 100 = 10,000 units に達する。つまり 100 ユーザーの同時アクセスで数分以内に quota 枯渇する。

プロモーションで X に投稿したら、数時間以内にこの閾値を超える。recipe-ai を広める予定の直前で、この壁に気づいた。


キャッシュで何とかできる部分はしている

recipe-ai で既に実装済みの節約策:

  1. 6 時間 ISR キャッシュ: 同じクエリは 6 時間 0 units(Next.js の next.revalidate = 21600
  2. おすすめ動画は自前 DB 由来: トップに並ぶ人気動画は extract_jobs テーブル(抽出済み 348 本)から取る。YouTube API は一切叩かない
  3. 動画クリック → プレビュー → 抽出ボタン: 動画を選んだ瞬間に自動抽出しない。ユーザーが「レシピを抽出」を押したときだけ Gemini を呼ぶ。「quota を使うか」の判断をユーザー側に委ねる

これでも 10,000 units/日 の上限は、1 日 100 検索 = 100 ユニークユーザー相当で破綻する。節約策には限界があって、根本解決には quota 増額が必要。


429 + 専用メッセージで丁寧に失敗する

quota 枯渇時に 502 を返しているままだと、ユーザーから見て「壊れた」としか見えない。これを 429 + 専用メッセージに変えた。

// lib/youtube-search.ts
if (res.status === 403 && /quotaExceeded|dailyLimitExceeded/.test(body)) {
  return {
    ok: false,
    error: "QUOTA_EXCEEDED",
    message: "本日の検索リクエスト上限に達しました。明朝に復旧します(しばらくは保存済みレシピやおすすめ動画をご利用ください)",
  };
}
// app/api/youtube-search/route.ts
const status =
  result.error === "NOT_CONFIGURED" ? 503
  : result.error === "QUOTA_EXCEEDED" ? 429
  : 502;

429 は「Too Many Requests」の標準的な意味なので、ブラウザ / CDN / プロキシの挙動も素直。ユーザーには「明朝に復旧します、それまでは保存済みレシピを使ってください」と案内できる。

ユーザーが完全に詰まない動線を残すのが重要で、recipe-ai の場合は extract_jobs のおすすめ動画が生きているから、検索が死んでもトップページで既存動画を発見できる。


Google Cloud に増額申請した

quota 増額は 完全に無料 だ。Google Cloud Console → YouTube Data API v3 → Quotas → Apply for higher quota から申請フォームにアクセスできる。

フォームで聞かれる主な項目:

  1. アプリケーション名 / URL / 連絡先
  2. アプリの説明
  3. 使っている API メソッド
  4. 現在の使用状況
  5. 申請する新しい quota 量
  6. 申請理由(Justification)
  7. 不正利用防止策
  8. 収益モデル
  9. コンプライアンス
  10. スクリーンショット(10MB 未満 1 ファイル)

申請書の書き方のコツ

通りやすくする書き方として、以下を意識した:

具体的な数字で書く:

現在の 10,000 units/日 では search.list が 100 units/req のため 1 日最大 100 検索しか処理できず、100 人の同時ユーザーで数分以内に quota を使い切る構造です。申請する 1,000,000 units/日(約 10,000 検索/日)は 6 ヶ月後の成長目標に相当します。

曖昧な「たくさんのユーザー」ではなく、「100 ユーザー × 1 検索 = 100 リクエスト = 上限」と具体的に書く。

既に節約していることをアピール:

  1. 全検索結果に 6 時間の ISR キャッシュ
  2. 348 本の抽出済み料理動画を自前 DB で保持、動画発見 → レシピ表示まで YouTube API を使わずに処理可能
  3. quota 枯渇時の 429 レスポンス + 専用メッセージ

「増やせば解決するから増やしてくれ」ではなく「ここまで節約してもこれ以上は無理」というトーンに持っていく。

収益モデルが怪しくないことを示す:

フリーミアム型で運営。無料枠は月 3 回の AI レシピ抽出。プレミアム(¥500/月)で無制限抽出。現在はプレミアム会員 0 人の初期段階の個人開発プロダクト。

怪しい抽出業者・スクレイピング業者と区別するために、収益の取り方を明示する。特商法ページの URL も添えた。

スクリーンショットを同封:

5 枚の PNG を 1 つの PDF に結合して提出した:

  1. トップページ(検索バー + おすすめ動画)
  2. 動画プレビュー + 抽出ボタン画面
  3. 使い方ページ(3 ステップフロー + 料金比較)
  4. 特商法表記
  5. プレミアムプラン

これで審査担当が実際に何のアプリかを視覚的に理解できる。


審査期間 7〜14 日をどう乗り越えるか

申請の審査は通常 7〜14 日。日本語で申請した場合は翻訳工程で +2〜3 日。

その間、quota は 10,000 units/日 のまま。広めるタイミングを審査結果後にずらすか、節約モードで広めるかの判断になる。

recipe-ai では後者を選んだ:

  • masatoman.net のブログ記事(流入は少なく、quota 消費しにくい層)から広め始める
  • Zenn / Qiita の技術記事も同様(技術者は URL 直貼りが多く、料理名検索を大量に叩かない)
  • X の一般向け拡散は quota 増額承認後に解禁

技術記事から流入する層は、しばしば「このアプリどうやって作ったんだろう」という興味で来るので、URL 直貼りで試すパターンが多い。料理名検索を大量に叩かない。結果、quota 消費が抑えられる。


落ちて初めて気づいた設計の穴

今回、検索を広める直前に quota 枯渇したのは不幸中の幸いだった。もし X で拡散した直後に落ちていたら、最初の訪問者が全員「検索できません」画面で離脱していた。

個人開発で 最初に詰まる壁は、ほぼ確実に外部 API の無料枠だ。Gemini の TPM 制限、Supabase Edge Function のタイムアウト、Vercel Hobby の 60 秒、そして今回の YouTube Data API の 10,000 units/日。

無料枠を組み合わせて月¥0で運用する設計は可能だが、「ユーザーが一定数を超えた瞬間に詰む」ポイントが必ずある。どこで詰むかを先に把握して、そのときの退避経路(429 + 専用メッセージ、DB キャッシュ)を準備しておくのが、実運用では効いてくる。


まとめ

  • YouTube Data API v3 の無料枠は 10,000 units/日、search.list は 100 units/req → 1 日 100 検索が上限
  • 100 ユーザーの同時アクセスで数分以内に枯渇する構造
  • 節約策(ISR キャッシュ + 自前 DB)には限界があり、根本解決は quota 増額
  • quota 枯渇時は 502 ではなく 429 + 専用メッセージで丁寧に失敗する
  • 増額申請は無料。具体的な数字、既存の節約策、収益モデルを書いて申請
  • 審査 7〜14 日の間は、流入層を選んで広める(技術記事から始める)

個人開発で「最初に詰まる壁」の多くは外部 API の無料枠だ。設計段階で退避経路を準備しておくと、実運用で焦らずに済む。

recipe-ai を試す(無料)

この記事で作っている YouTube 料理レシピ抽出アプリ本体。動画 URL を貼るだけで AI がレシピに変換。月 5 本まで無料。

この記事が役に立ったらシェア