1. 為什麼需要 Privacy Policy、Terms 和 Support
先說殘酷的事實:對 ChatGPT Store 而言,公開的隱私權政策與支援聯絡資訊並不是「禮貌」,而是硬性要求。OpenAI 的指引明確寫道,每個 App 都必須有已發佈的 Privacy Policy,清楚說明收集哪些資料、如何使用,並提供支援聯絡方式。
但這件事不只是「讓審核員別來煩」。這些文件同時解決多個問題。
其一,這是給使用者的基本信任門檻。他會看到這個應用背後有真人或公司、遊戲規則是什麼,遇到問題有地方可去。在「又一個 AI 服務」天天冒出的世界裡,這已經是競爭優勢。
其二,這是把你在架構上已經做的事正式文字化。你在安全、記錄、保留期、資料刪除與金流處理等模組做過的決定,都需要被文字清楚表述。若你承諾「不保存對話」,卻把所有 tool‑input 永久寫進日誌,這不只是不好看——還可能引發嚴重投訴。
其三,這是你與 OpenAI 之間的另一層契約。Store 等於是在說:「我們願意把你的 App 展示給數百萬人,但你必須誠實說明你會怎麼處理他們,且在出問題時保持聯絡暢通。」
總結一下:法律頁面不是「被法務逼的」。它用來對齊預期:App 做什麼、會觸碰哪些資料、你願意承擔何種責任,以及使用者如何與你聯繫。
2. 這些法律 URL 在 ChatGPT App 裡應該放哪?
技術上,對 ChatGPT App 而言,法律頁面就是你在應用中繼資料與 Store 列表中填入的公開 URL。指引裡通常把它們叫作 privacy_policy_url、terms_of_service_url 與支援聯絡方式(support contact)。
這些 URL 應符合幾個簡單但重要的條件:
- 它們放在你產品或公司的穩定網域上。 不要用臨時的 ngrok 連結,否則一週後 Store 會把使用者帶到無處可去。
- 它們在未登入的情況下可存取。 使用者(與審核者)應能直接以瀏覽器開啟,無需登入或繁瑣步驟。
- 內容要即時且與實際一致。 如果你更動了資料處理的架構,之後也要更新文件文字。
在我們的教學專案 GiftGenius 裡,已有使用 Next.js 的前端,部署在 Vercel。那麼法律頁面最合適的位置就是這些路由:
- /legal/privacy
- /legal/terms
- /support
本質上它們只是應用中的另外三個頁面,但你會在 App 送審表單裡引用這些頁面。
3. Privacy Policy:如何誠實描述你對資料做了什麼
Privacy Policy 的角色
Privacy Policy(隱私權政策,下文簡稱「Policy」)回答的核心問題是: 「這個 App 對我的(使用者)資料做了什麼?」它應描述你處理哪些資料類別、來源是什麼、用途為何、在哪裡保存、保存多久、會提供給誰,以及使用者如何要求刪除。
ChatGPT Apps 的特殊性在於,使用者需要知道你究竟從對話中拿到了什麼。OpenAI 另外強調:你的 App 不應嘗試還原整段對話,而只能處理模型或使用者明確送進工具的片段。這點也應在 Policy 中說明。
別從寫文案開始,先盤點架構
在寫任何法律文字之前,先用 SRE/架構師的視角看你的 App:實際有哪些資料流過系統。
以我們的例子 GiftGenius,大致可長這樣:
| 資料類別 | 來源 | 儲存位置 | 保留期 / 行為 |
|---|---|---|---|
| 請求文字(聊天片段 snippet) | 來自 ChatGPT 的工具呼叫 | 後端請求日誌 | 保留 N 天或立刻刪除 |
| 使用者選擇的禮物 | 小工具中的操作 | GiftGenius 資料庫 | 保留至帳號刪除 |
| 使用者 Email(若啟用 OAuth) | 身分驗證提供者 | 使用者資料庫 | 只要帳號仍啟用 |
| 技術量測(IP、時間戳、錯誤) | HTTP 請求 | 日誌 / 監控系統 | 依日誌政策保留 N 天 |
建議把這樣的表格直接放進專案文件(例如 /docs):對開發、安全模組與 Policy 本身都很有用。
接著把這個結構「翻譯」成一般人看得懂的語句。
GiftGenius 的 Privacy Policy 結構
在教學專案裡不必寫 20 頁長文;內容精簡但誠實即可。通常會包含這些章節:
- 前言:你是誰、這個 App 是做什麼的。
- 你收集哪些資料。
- 你如何使用這些資料。
- 你會把資料提供給誰。
- 在哪裡儲存、保存多久。
- 使用者的權利(包含刪除請求)。
- 隱私問題聯絡方式。
要理解的是,即使是教學專案也不是「樣板文」。你在安全模組裡已經思考過日誌保留期、刪除政策、備份等——現在需要精準地寫出來。
在 Next.js 中的最簡實作
讓我們在應用裡建立 /legal/privacy 頁面。在 App Router 中這基本上一個檔案就搞定:
// 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 天;
- 可在使用者要求時完全刪除其個人檔案;
- 不會用這些資料訓練你自己的模型,
那麼你應該具備:
- 日誌的保留期設定;
- 刪除使用者的 endpoint 或管理流程;
- 沒有把日誌外洩到第三方儲存「拿去做 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 應用而言,尤其重要的是兩件事:準確性的免責與責任限制。
AI 的特性:「模型可能會出錯」
我們的 GiftGenius 提供送禮建議。這很可愛而且相對安全,但仍可能踩雷:使用者要求「對堅果過敏者的禮物」,模型給了不恰當的建議,結果對方受害,大家都不好受。
當然,Terms 不是萬靈丹,但它能清楚界定:
- 結果由 AI 產生,可能不準確、過時或離奇;
- 使用者有義務自行核實重要資訊,尤其與健康、財務或其他敏感領域相關者;
- 你不保證建議「完美無瑕」,也不對不當使用結果負責。
具體措辭之後應與法務合作打磨,但對技術開發者來說,理解這個精神最重要。
金流/商務細節
若你的 App 涉及任何付款動作(關於 ACP 與 commerce 的模組之後會更深入,但課程已涵蓋),在 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>
);
}
同樣地,最好把正文放在獨立檔案或 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 必須提供清楚的方式讓使用者能與開發者聯絡以取得支援。可以只是個簡單的 email,但它必須存在、能收信,且至少偶爾有人回覆。
教學專案的極簡做法:
- 獨立的 /support 頁面,內含簡短說明與 mailto:support@yourdomain.com。
更成熟的做法:
- 回報表單;
- 指向文件或 Help Center 的連結;
- 如果你在打造社群,或許還有 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 頁面會成為使用者的「入口」:他們透過它回報 bug、提出問題、發起資料刪除請求。此刻至少要先確保這扇門存在,且不會連到「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 的設定(中繼資料);
- 產品的登陸頁;
- 若實作 email 通知,則在郵件內。
在小工具中,你可以透過 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 hook;此處為了簡潔,示範了透過 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 的實作練習
別停留在理論上;現在就為你的應用草擬文件。
做法可以這樣:
先在架構層面描述:
- 你處理哪些資料類別(請求文字、訂單、email、量測);
- 是否保存文字請求,若是,保存多久;
- 接了哪些外部服務(託管、資料庫、金流、分析)。
之後:
- 擬一份 Privacy Policy 的結構,含「收集什麼」、「用途為何」、「提供給誰」、「保存多久」、「如何刪除資料」。
- 擬一份 Terms 的結構:服務描述、使用規則、限制(禁止內容與濫用)、AI 免責、責任限制、連結至 Policy。
- 建立 /support 頁面,放上簡短文字與 email。
- 在專案內新增 lib/appConfig.ts,集中管理法律頁面的 URL,並在小工具與所有外部連結中使用它們。
即便文字暫時只是草稿、你打算「之後給法務看」,你已經完成一件重要的事:把技術實作與法律描述銜接起來。
8. 準備法律頁面時的常見錯誤
錯誤 №1:複製網路上的隨機隱私權政策,不做任何修改。
有時會想直接拿一份現成的政策,改掉產品名稱就算完成。問題在於,那份文字幾乎不會與你的架構一致。它可能包含你沒有的東西(行動 App、推播、特定分析服務),反之卻沒提到你有的內容(MCP 伺服器、工具日誌、透過 ChatGPT 的工作方式)。審核者會注意到不一致,使用者也會覺得「這文本不是在講你」。
錯誤 №2:在 Policy 承諾了程式碼沒有實作的事。
經典案例是「我們應要求會刪除你的所有資料」,但程式碼裡既沒有刪除的 endpoint,也沒有搜尋特定使用者資料的機制。對日誌保留期與「我們不保存你的訊息文字」亦然——若你其實把 tool‑input 丟進沒有保留期的日誌系統。這種落差對審核與真實使用者都很危險。
錯誤 №3:在 Terms 中忽略 AI 的特性。
如果 Terms 完全沒提到答案由模型生成、可能不準確,使用者就可能期待你的 App 「永遠正確」。對推薦類服務(禮物、旅遊、商品選擇)或許還能接受,但在醫療、金融、法律建議等領域,這個缺口會有很嚴重的後果。請明確、誠實地說清楚限制與責任。
錯誤 №4:Support 頁面沒有真實聯絡方式,或使用死信信箱。
一個指向 /support 的頁面,但只放了 mailto:hello@example.com 且無人查看,形式上存在,實際上無用。使用者得不到回覆、bug 回報消失,App 的信任度下降。平台也期待你會回應投訴與問題。即使團隊很小,至少每隔幾天檢視收件匣並回應。
錯誤 №5:忘了文件的日期與版本。
有時法律頁面完全沒有標示最後更新時間。對審核者而言,這是警訊:文件是否反映產品現況不得而知。簡單的「Last updated: …」區塊就能同時幫助你與使用者,也有助於後續在架構演進時記錄 Policy/Terms 的更新歷史。
GO TO FULL VERSION