サーバーにログを残さないプライバシー配慮型AIチャットの作り方|localStorageによる会話履歴管理と安全設計
会話ログをサーバー DB に保存せず、ブラウザの localStorage で保存・管理することで、個人のプライバシーを守りながら運用コストゼロの AI チャットが実現できます。
Web サービスで AI チャット機能を提供する場合、ユーザーの入力テキストや対話履歴の扱い方はプライバシー面で重要なテーマです。
会話ログをすべてサーバー側のデータベースに永続化すると、万が一の漏洩リスクや個人情報保護(GDPR等)への配慮、さらに DB ストレージコストが増大します。これをクライアントサイド(localStorage)完結にする設計を解説します。
サーバー保存 vs クライアント(localStorage)保存
データ保存方針の違いによる特徴の比較表です。
| 保存場所 | プライバシー安全性 | サーバー運用コスト | 複数デバイス同期 | 主な用途 |
|---|---|---|---|---|
| サーバー DB 保存 | 漏洩対策・暗号化対応が必要 | ストレージ・DB 費用が発生 | 可能(ログイン必須) | 企業向け SaaS・有料 AI ツール |
| localStorage(クライアント) | 極めて高い(ログがサーバーに残らない) | ゼロ(DB 不要) | 不可(端末固有) | 個人開発・プライバシー重視ツール |
会話ログをサーバー側に残さない構成にすることで、開発者側もユーザーの個人的な相談ややり取りを物理的に閲覧・保持することがなくなり、技術的な免責と安心感を提供できます。
クライアントサイド保存の実装 3 手順
React / Astro / プレーン JavaScript で安全に会話履歴を管理する手順です。
-
マウント時の安全性チェックと読込 SSR(サーバーサイドレンダリング)環境での Hydration エラーを防ぐため、
useEffectやクライアントマウント後にwindow.localStorageから読み込みます。 -
最新メッセージの追加と配列スライス ユーザー発言および AI 応答が届くたびに配列へ追加し、最新 N 件(例: 50 件)を超えた古いメッセージは
sliceで除外して書き込みます。 -
明示的な履歴消去 UI の提供 ユーザーが自発的に会話をやり直したい場合に備え、ワンタップで
localStorage.removeItem()を実行するクリアボタンを設置します。
最小コード例(履歴管理フック・処理)
const STORAGE_KEY = 'ai_chat_history_v1';
const MAX_HISTORY_COUNT = 30; // 容量オーバーを防ぐ制限数
// 履歴の読み込み
export function loadChatHistory() {
if (typeof window === 'undefined') return [];
try {
const raw = localStorage.getItem(STORAGE_KEY);
return raw ? JSON.parse(raw) : [];
} catch (e) {
console.error('履歴読み込み失敗:', e);
return [];
}
}
// 履歴の保存
export function saveChatHistory(messages: Array<{ role: string; content: string }>) {
if (typeof window === 'undefined') return;
try {
// 最新 30 件のみに制限して QuotaExceededError を防止
const trimmed = messages.slice(-MAX_HISTORY_COUNT);
localStorage.setItem(STORAGE_KEY, JSON.stringify(trimmed));
} catch (e) {
console.error('localStorage 保存エラー:', e);
}
}
// 履歴の一括削除
export function clearChatHistory() {
if (typeof window === 'undefined') return;
localStorage.removeItem(STORAGE_KEY);
}
現場で起こる障害と対策(Failure Boundary)
localStorage 運用で発生しやすいトラブルと対策です。
1. SSR との表示不一致(Hydration Mismatch)
- 発生現象: Astro や Next.js などの SSR 枠組みにおいて、サーバー描画段階とブラウザ初期表示段階で
localStorageの有無による HTML の相違が発生しエラーや画面フラッシュが起こる。 - 解決策: 初期レンダリングは空配列で描画し、ブラウザマウント完了(
useEffectやDOMContentLoaded)後にlocalStorageから復元・描画します。
2. 容量超過エラー(QuotaExceededError)
- 発生現象: 長文の会話を長期間保存し続けた結果、ブラウザの
localStorage容量制限(5MB 前後)を超えてDOMException: QuotaExceededErrorが発生する。 - 解決策: 保存時に常に
.slice(-30)などの件数上限を適用し、例外が発生した場合はcatchブロックで古いメッセージを削除して再保存を試みる自動リカバリを実装します。
当サイトで公開している /chat/(加賀チャット)でも、会話履歴はすべてユーザーのブラウザ内 localStorage のみに保存され、サーバー側にデータベースや会話ログを保管しない安全設計を採用しています。