サーバーにログを残さないプライバシー配慮型AIチャットの作り方|localStorageによる会話履歴管理と安全設計

AI プライバシー Web開発 JavaScript セキュリティ
結論

会話ログをサーバー DB に保存せず、ブラウザの localStorage で保存・管理することで、個人のプライバシーを守りながら運用コストゼロの AI チャットが実現できます。

Web サービスで AI チャット機能を提供する場合、ユーザーの入力テキストや対話履歴の扱い方はプライバシー面で重要なテーマです。

会話ログをすべてサーバー側のデータベースに永続化すると、万が一の漏洩リスクや個人情報保護(GDPR等)への配慮、さらに DB ストレージコストが増大します。これをクライアントサイド(localStorage)完結にする設計を解説します。

サーバー保存 vs クライアント(localStorage)保存

データ保存方針の違いによる特徴の比較表です。

保存場所プライバシー安全性サーバー運用コスト複数デバイス同期主な用途
サーバー DB 保存漏洩対策・暗号化対応が必要ストレージ・DB 費用が発生可能(ログイン必須)企業向け SaaS・有料 AI ツール
localStorage(クライアント)極めて高い(ログがサーバーに残らない)ゼロ(DB 不要)不可(端末固有)個人開発・プライバシー重視ツール

会話ログをサーバー側に残さない構成にすることで、開発者側もユーザーの個人的な相談ややり取りを物理的に閲覧・保持することがなくなり、技術的な免責と安心感を提供できます。

クライアントサイド保存の実装 3 手順

React / Astro / プレーン JavaScript で安全に会話履歴を管理する手順です。

  1. マウント時の安全性チェックと読込 SSR(サーバーサイドレンダリング)環境での Hydration エラーを防ぐため、useEffect やクライアントマウント後に window.localStorage から読み込みます。

  2. 最新メッセージの追加と配列スライス ユーザー発言および AI 応答が届くたびに配列へ追加し、最新 N 件(例: 50 件)を超えた古いメッセージは slice で除外して書き込みます。

  3. 明示的な履歴消去 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 の相違が発生しエラーや画面フラッシュが起こる。
  • 解決策: 初期レンダリングは空配列で描画し、ブラウザマウント完了(useEffectDOMContentLoaded)後に localStorage から復元・描画します。

2. 容量超過エラー(QuotaExceededError)

  • 発生現象: 長文の会話を長期間保存し続けた結果、ブラウザの localStorage 容量制限(5MB 前後)を超えて DOMException: QuotaExceededError が発生する。
  • 解決策: 保存時に常に .slice(-30) などの件数上限を適用し、例外が発生した場合は catch ブロックで古いメッセージを削除して再保存を試みる自動リカバリを実装します。

当サイトで公開している /chat/(加賀チャット)でも、会話履歴はすべてユーザーのブラウザ内 localStorage のみに保存され、サーバー側にデータベースや会話ログを保管しない安全設計を採用しています。