CodeGym /コース /ChatGPT Apps /Privacy Policy、Terms、Support: 必須の法的ページ

Privacy Policy、Terms、Support: 必須の法的ページ

ChatGPT Apps
レベル 18 , レッスン 1
使用可能

1. なぜ Privacy Policy、Terms、Support が必要なのか

不都合な真実から始めましょう。ChatGPT Store では、公開されたプライバシーポリシーとサポート連絡先の有無は「マナー」ではなく、厳格な要件です。OpenAI のガイドラインには、すべての App が公開された Privacy Policy を持つべきであり、どのデータを収集し、どのように使用するかを明確に説明し、かつサポート連絡先を示すよう明記されています。

しかし話は「モデレーターをやり過ごすため」だけではありません。これらの文書は同時に複数の課題を解決します。

第一に、ユーザーに対する信頼の最低ラインです。アプリの背後に実在の人や会社がいて、ルールがあり、問題があれば連絡できる場所があることが分かります。「また別の AI サービス」が毎日のように現れる世界では、これはすでに競争優位です。

第二に、あなたがアーキテクチャで実装したことの形式化です。セキュリティ、ログ、保持期間(retention)、データ削除、決済の扱いで決めたことは、文章にも反映されるべきです。「チャット内容は保存しません」と約束しながら、実際にはすべての tool-input を無期限にログしているなら、それは単に好ましくないだけでなく、重大なクレームの原因になります。

第三に、あなたと OpenAI の間のもう一つの契約レイヤーです。Store は実質こう言っています。「あなたの App を何百万人にも見せる用意はある。だが、ユーザーに対して何をするのか正直に説明し、何かあったときは連絡の取れる状態でいてほしい」。

まとめると、法的ページは「法務に言われたから」ではありません。App が何をするのか、どのデータに触れるのか、どの範囲の責任を負うのか、ユーザーがどうやってあなたと話せるのか、という期待値を同期させる手段なのです。

2. ChatGPT App における法的 URL の所在

技術的には、ChatGPT App の法的ページは、アプリのメタデータとストアのリスティングに記載する公開 URL にすぎません。ガイドラインでは、たとえば privacy_policy_urlterms_of_service_url、そしてサポート連絡先のように呼ばれています。

これらの URL は、単純ですが重要な条件を満たす必要があります。

  1. 製品または会社の安定したドメイン上にあること。 一時的な ngrok のリンクは不可。1 週間後に Store からユーザーが空振りしてしまいます。
  2. 認証なしでアクセスできること。 ユーザー(とレビュアー)は、ログインや面倒な手順なしにブラウザで開けなければなりません。
  3. 内容が最新で、実態と一致していること。 データ処理のアーキテクチャを変更したなら、いずれテキストも更新する必要があります。

この講座のサンプルプロジェクト GiftGenius には、すでに Next.js のフロントエンドがあり、たとえば Vercel にデプロイしています。法的ページを置く妥当な場所は、次のようなルートです。

  • /legal/privacy
  • /legal/terms
  • /support

要するに、これらはアプリ内の 3 つの通常ページですが、App をレビュー提出する際に参照するのはまさにこの URL です。

3. Privacy Policy: データ取り扱いを誠実に記述する

Privacy Policy の役割

Privacy Policy(プライバシーポリシー。以下、簡単のため「Policy」)は、次の主な問いに答えます。 「この App は(ユーザーの)データをどう扱うのか?」 どのカテゴリのデータを処理し、どこから取得し、何のために必要で、どこでどのくらい保存し、誰に提供し、ユーザーがどうすれば削除を依頼できるのかを記載する必要があります。

ChatGPT Apps の特性として、チャットから何を受け取っているかをユーザーが理解することが重要です。OpenAI は明確に強調しています。あなたの App は全会話を再現しようとせず、モデルまたはユーザーが明示的にツールに送った断片だけを扱うべきだと。これも Policy に明示しておく価値があります。

テキストではなくアーキテクチャから始める

法的な文言を書く前に、SRE/アーキテクトの目線で自分の App を眺めると有益です。実際にどのデータがシステムを通過しているのか。

たとえば今回の GiftGenius では、概ね次のように整理できます。

データカテゴリ 流入元 保存先 期間 / 取り扱い
リクエスト本文(チャットのスニペット) ChatGPT からの Tool 呼び出し バックエンドのリクエストログ N 日間、または即時削除
ユーザーが選んだギフト ウィジェットでの操作 GiftGenius のデータベース アカウント削除まで保存
ユーザーのメール(OAuth がある場合) 認証プロバイダ ユーザーデータベース アカウントが有効な間
技術メトリクス(IP、タイムスタンプ、エラー) HTTP リクエスト ログ / 監視システム ログポリシーに基づく N 日

このような表はプロジェクトのドキュメント(たとえば /docs)に用意するとよいでしょう。開発にも、Security モジュールにも、Policy 本文にも役立ちます。

次に、この構造を「人間の言葉」に落とし込みます。

GiftGenius 向け Privacy Policy の構成

学習用プロジェクトでは 20 ページの大作は不要です。簡潔でも誠実な構成で十分です。一般的には次のセクションに分けます。

  1. 導入:運営主体と App の概要。
  2. 収集するデータ。
  3. データの利用方法。
  4. 第三者提供。
  5. 保存場所と保存期間。
  6. ユーザーの権利(削除リクエスト等)。
  7. プライバシー問い合わせ窓口。

重要なのは、学習用とはいえ単なる「雛形」ではない点です。セキュリティのモジュールでログの保持期間、削除ポリシー、バックアップを検討しましたが、今度はそれを丁寧に言語化する番です。

Next.js での最も簡単なページ実装

アプリに /legal/privacy ページを作りましょう。App Router ならファイル 1 つで済みます。

// app/legal/privacy/page.tsx
export default function PrivacyPage() {
  return (
    <main className="mx-auto max-w-3xl p-8 prose">
      <h1>Privacy Policy – GiftGenius</h1>
      <p>Last updated: {new Date().toLocaleDateString()}</p>
      {/* 以下にポリシーの各セクションを記載 */}
    </main>
  );
}

この例は意図的にシンプルです。目的は静的な URL を確定すること。実際のプロジェクトでは、ポリシー本文は別(たとえば .md ファイル)に置き、読み込むのが一般的です。JSX に長文を散在させないためです。

たとえば、典型的なローダーは次のとおりです。

// app/legal/privacy/page.tsx
import policyHtml from "./policy.html"; // 事前にビルドされた HTML

export default function PrivacyPage() {
  return (
    <main
      className="mx-auto max-w-3xl p-8 prose"
      dangerouslySetInnerHTML={{ __html: policyHtml }}
    />
  );
}

「理解せずに真似しないで」系の注意書きもここでは適切です。 dangerouslySetInnerHTML は、HTML のソースをあなたがコントロールできる場合(たとえば CI で markdown から自動ビルド)にのみ安全です。

実運用プロセスとの結び付き

最重要ポイントは、実装のないことを Policy に書かないことです。もし次のように宣言するなら:

  • リクエスト本文は 7 日を超えて保存しない;
  • ユーザーの要請に基づき、プロフィールを完全に削除する;
  • そのデータを自前モデルの学習に使わない、

ならば、以下を整備しておく必要があります。

  • ログの保持期間(retention)の設定;
  • ユーザー削除のエンドポイントまたは管理プロセス;
  • 「Data Science 用」などの名目でログを外部ストレージに流出させるコードが存在しないこと。

逆に、利用状況メトリクス、A/B テスト、国別分析などを有効化している場合は、Policy に正直に記載してください。そして少なくとも基本的な権利、すなわち保存情報の開示と削除リクエストの手段を提供しましょう。

データと Privacy Policy を固めたら、次はデータ処理だけでなく「利用のルール」自体を明確化します。これは Terms の役割です。

4. Terms of Use / Service: ルールと AI ディスクレーマー

Policy があるのに、なぜ Terms が要るのか

Privacy Policy は「データをどう扱うか」に答えます。Terms Of Use/Service(以下、Terms)は「そもそもどの条件で App を利用できるのか」に答えます。これはあなたとユーザーとの法的な契約です。

そこには次のようなことを記載します。

  • GiftGenius とは何か、どんな機能を提供するか;
  • ユーザーのどの行為が許容され、どの行為が禁止か;
  • AI の「魔法の境界線」(AI ディスクレーマー);
  • あなた側の責任制限;
  • 紛争解決の方法と準拠法/裁判管轄。

AI アプリでは、とりわけ精度に関するディスクレーマーと責任制限の 2 点が重要です。

AI 特有の注意:「モデルは誤ることがある」

GiftGenius はギフトのレコメンドを行います。可愛らしく比較的安全ですが、ここでも落とし穴はあります。たとえば「ナッツアレルギーの人向けのギフト」と依頼されたのに、モデルが不適切な提案をし、ユーザーに不利益が生じる、といったケースです。

Terms は万能の防弾チョッキではありませんが、次の点を明確に定めます。

  • 結果は AI により生成され、正確でない・古い・奇妙な場合がある;
  • とくに健康、金融、その他センシティブな領域については、重要情報をユーザー自身で検証する責務がある;
  • 推奨の完全性を保証せず、結果の不適切な利用について責任を負わない。

文言は最終的に法務と詰める必要がありますが、開発者としてはこの考え方を理解しておくことが大切です。

コマース上の注意点

App が何らかの決済を扱う場合(ACP とコマースは後のモジュールで詳述しますが、このコースには含まれます)、Terms では次を丁寧に説明しましょう。

  • 決済が誰を介して行われるか(Stripe、ACP、その他);
  • あなたが見える決済データの範囲;
  • 返金やキャンセルの条件;
  • 何をもってトランザクション成功とみなすか。

一般的なプラットフォーム推奨としては、カードデータは決済プロバイダが処理し、あなたのサーバーでは取り扱わないこと、そして最低限(たとえばトランザクション ID)のみ保存することを明記するのが望ましいです。

Next.js での /legal/terms 実装

技術的には Privacy Policy とほぼ同様です。ページを用意します。

// app/legal/terms/page.tsx
export default function TermsPage() {
  return (
    <main className="mx-auto max-w-3xl p-8 prose">
      <h1>Terms of Use – GiftGenius</h1>
      <p>Last updated: {new Date().toLocaleDateString()}</p>
      {/* セクション: サービス説明、制限、AI ディスクレーマー、責任 */}
    </main>
  );
}

Policy と同様、本文は別ファイルや CMS に置き、コード側のマークアップは最小限にするのが良いでしょう。

法的ページ用の共通レイアウトを用意するのも一案です。

// app/legal/LegalLayout.tsx
export function LegalLayout(props: { title: string; children: React.ReactNode }) {
  return (
    <main className="mx-auto max-w-3xl p-8 prose">
      <h1>{props.title}</h1>
      <p>Last updated: {new Date().toLocaleDateString()}</p>
      {props.children}
    </main>
  );
}

その上で、Policy と Terms の両方に使います。これは「コードの美しさ」のためというより、更新日を入れ忘れないこと、スタイルを統一することに意味があります。

5. Support / Contact: ユーザーの駆け込み寺

最低限と「望ましい姿」

OpenAI のガイドラインでは、App にサポート連絡手段が分かりやすく用意されている必要があるとされています。単純なメールでもかまいませんが、実在し、受信でき、少なくとも時折は返信があるものにしましょう。

学習用プロジェクトの最小構成は次のとおりです。

  • 短い説明と mailto:support@yourdomain.com を記載した専用ページ /support

より本格的な構成:

  • 問い合わせフォーム;
  • ドキュメントまたはヘルプセンターへのリンク;
  • コミュニティ運営をするなら Slack/Discord へのリンク。

Next.js の /support ページ

まずは極めてシンプルな例から。

// app/support/page.tsx
export default function SupportPage() {
  return (
    <main className="mx-auto max-w-xl p-8 prose">
      <h1>GiftGenius Support</h1>
      <p>
        If you have issues or questions, email us at{" "}
        <a href="mailto:support@giftgenius.app">support@giftgenius.app</a>.
      </p>
    </main>
  );
}

少し進んだ例として、簡単なフォームを追加します。

// app/support/page.tsx
"use client";

export default function SupportPage() {
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // ここで API を呼び出してメール/チケットを送信します
  };

  return (
    <main className="mx-auto max-w-xl p-8 prose">
      <h1>GiftGenius Support</h1>
      <form onSubmit={handleSubmit}>
        <input name="email" placeholder="Your email" className="border p-2 w-full" />
        <textarea name="message" placeholder="How can we help?" className="border p-2 w-full mt-2" />
        <button type="submit" className="mt-4 px-4 py-2 border rounded">
          Send
        </button>
      </form>
    </main>
  );
}

学習用プロジェクトでこのフォームの本当のバックエンドを実装しないにせよ、分かりやすい URL とページ構成があるだけで、Store の要件に近づきます。

インシデントマネジメントとの関係

Support ページは「落ちたときに連絡する場所」だけではなく、運用全体の一部です。後のモジュールでインシデントや App の運用について扱いますが、Support ページはユーザーの「入口」になります。ここからバグ報告、質問、データ削除リクエストが届きます。今は少なくとも、その入口が存在し、「404 Not Found」に繋がっていないことを確認しましょう。

6. アプリとリスティングへの法的ページ統合

プロジェクト内の URL 統一設定

コードのあちこちに「マジックストリング」の URL を散らさないよう、簡単な設定を用意すると便利です。

// lib/appConfig.ts
export const legalLinks = {
  privacy: "https://giftgenius.app/legal/privacy",
  terms: "https://giftgenius.app/legal/terms",
  support: "https://giftgenius.app/support",
} as const;

これらの URL は、次の場面でも使用します。

  • ChatGPT App の設定(メタデータ);
  • 製品ランディングページ;
  • メール通知を実装するならメール本文。

ウィジェット内からは、openExternal を使ってユーザーにこれらのページへ素早くアクセスさせることができます。

// GiftGenius の React ウィジェット内
import { legalLinks } from "../lib/appConfig";

function FooterLinks() {
  const handleOpen = (url: string) => {
    window.openai?.openExternal({ url }); // Apps SDK helper
  };

  return (
    <footer className="mt-4 text-xs text-gray-500">
      <button onClick={() => handleOpen(legalLinks.privacy)}>Privacy</button>
      <span> · </span>
      <button onClick={() => handleOpen(legalLinks.terms)}>Terms</button>
    </footer>
  );
}

実際のウィジェットコードでは、Apps SDK の useOpenExternal フックを使うのが望ましいです。ここでは簡潔化のために window.openai による直接呼び出しを示しています。

こうすることで透明性が高まり、ユーザーはウィジェットからワンクリックで法的文書へアクセスでき、Store のどこかを探し回る必要がなくなります。

ユーザーとレビュアーのフロー

やり取りの流れを小さな図で見てみましょう。

flowchart TD
  A[ChatGPT Store のリスティングページ] --> B[ユーザーが App の説明を読む]
  B --> C[リンクから Privacy / Terms を開く]
  B --> D[App をインストール / 利用開始]
  D --> E[GiftGenius のウィジェットを起動]
  E --> F["必要に応じて『Support』または『Privacy』を押す"]

ChatGPT Store のレビュアーも、ほぼ同じ経路をたどりますが、より慎重です。次の点を確認します。

  • リスティングに何が書かれているか;
  • Policy と Terms に何が約束されているか;
  • 実際のシナリオで App がどう振る舞うか;
  • 記載内容と挙動が一致しているか。

すべてが誠実で予測可能なら、レビュー通過の確率は大きく上がります。

7. あなたの App のための実践課題

机上の空論で終わらせないために、今すぐ自分のアプリ用の文書ドラフトを用意しましょう。

アプローチは次のようにできます。

まずアーキテクチャの観点から整理します。

  • 処理するデータカテゴリ(リクエスト本文、注文、メール、メトリクス);
  • テキストリクエストを保存するか、するなら期間はどれくらいか;
  • 接続している外部サービス(ホスティング、DB、決済、分析)。

その後、次を行います。

  1. Privacy Policy の構成案を作成:「何を集める」「なぜ」「どこへ提供」「どれくらい保存」「どうやって削除」。
  2. Terms の構成案を作成:サービス説明、利用ルール、制限(禁止コンテンツや濫用)、AI ディスクレーマー、責任制限、Policy へのリンク。
  3. 短い文面とメールを載せた /support ページを作る。
  4. プロジェクトに lib/appConfig.ts を追加して法的ページの URL を集約し、ウィジェットや外部リンクで使用する。

テキストが荒削りで「後で法務に見せる」予定だとしても、すでに重要な作業を完了しています。技術的実装と法的記述を接続できるからです。

8. 法的ページ準備でありがちなミス

ミス No.1: 適当なプライバシーポリシーをコピペして放置。
つい最初に見つかったプライバシーポリシーを持ってきて、製品名だけ差し替えて終わりにしたくなることがあります。しかしそのようなテキストは、あなたのアーキテクチャとほぼ確実に一致しません。モバイルアプリ、プッシュ通知、特定の分析サービスなど、あなたにない要素が含まれていたり、逆に MCP サーバー、ツールのログ、ChatGPT 経由の動作について何も触れられていなかったりします。レビュアーは不一致に気付きますし、ユーザーも「誰か別のもの向けのテキストだ」と感じます。

ミス No.2: コードで実装していないことを Policy に約束する。
典型例は「要請があればすべてのデータを削除します」という一文。しかしコードには削除エンドポイントもなければ、特定ユーザーのデータを検索する手段すらない。ログの保持期間や「ユーザーのメッセージは保存しません」という文言も同様で、実際には tool-input を保持期間なしにログシステムへ保存している、といった矛盾です。これはレビューにも実ユーザーにも危険です。

ミス No.3: Terms に AI 特有の注意書きがない。
回答がモデルによって生成され、不正確である可能性に一言も触れないと、ユーザーは App に「絶対的な真実」を期待してしまうかもしれません。レコメンド系(ギフト、旅行、商品の選定)ならまだしも、医療、金融、法律助言のような領域では深刻な結果になり得ます。制約と責任を明確かつ誠実に述べるのが望ましいです。

ミス No.4: 実在しない連絡先、または死んでいるアドレスの Support ページ。
/support ページが mailto:hello@example.com にリンクしていても、誰も受信箱を見ないなら、形式上は存在しても実質的には無意味です。ユーザーは返信を得られず、バグ報告は失われ、App の評価は下がります。プラットフォームも苦情や問題への対応を期待しています。小さなチームでも、数日に一度は受信を確認し反応することが重要です。

ミス No.5: 文書の日付やバージョンを忘れる。
法的ページに更新日の記載が一切ないことがあります。レビュー担当にとっては不安要素で、文書が現状と一致するか不明です。シンプルな「Last updated: …」ブロックで、あなたにもユーザーにも安心感が生まれますし、アーキテクチャの進化に合わせて Policy/Terms を更新した履歴管理にも役立ちます。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION