マガジン

localStorageはどこにあるか:端末の中の小さな引き出し

遊びを見つける

執筆にClaudeを使用しています。

スマートフォンとノートパソコンの枠を、赤いゲームの駒と雲のアーチがつなぐ切り絵
記事のテーマをもとに制作したAI生成イラスト。

ブラウザゲームで記録を伸ばした翌日に、同じゲームを開いたら記録が消えていた。逆に、何週間も開いていないのに、前回のセーブがそのまま残っていた。こうした差は、ゲームの出来ではなく「データがどこに置かれ、どんな条件で消えるか」で決まることがよくあります。その置き場所としてよく使われるのが localStorage(ローカルストレージ)です。 先に答えを言えば、localStorage の実体は、ブラウザが利用者の端末の中で管理している保存領域です。ゲームを配信しているサーバーの中でも、ゲームのファイルの中でもありません。ただし、ファイルの形式や置き場所はブラウザやOSごとに違い、利用者が直接開く前提のものでもありません。この記事では、その引き出しの仕組み、消える条件、自分の端末で確かめる手順を順に見ていきます。 そのうえで、アソバースの作品ではこの仕組みがどう扱われているかを、確認できている範囲で整理します。「保存される」と「残り続ける」は同じ意味ではない、という点が全体の軸です。

この記事の目次
  1. 引き出しは「ブラウザ」と「サイトの住所」で決まる
  2. 消える条件を整理する
  3. 自分の端末で確かめる実験の設計書
  4. アソバースの中ではどうなっているか
  5. 立場別の判断基準
  6. 次の行動
  7. 参考資料

引き出しは「ブラウザ」と「サイトの住所」で決まる

localStorage は、Webページの JavaScript から使える「キーと値の組」を保存する仕組みです。キーは名前、値は文字列です。数値や配列を入れたいときは、文字列に変換して入れます。

localStorage.setItem("best", "42");
localStorage.getItem("best"); // "42"

この引き出しには、次の三つの性質があります。

  • ブラウザごとに別です。 ChromeとSafariで同じサイトを開いても、互いの引き出しは見えません。同じブラウザでも、プロファイルを分けていれば別になります。
  • サイトの「オリジン」ごとに別です。 オリジンとは、プロトコル(httpかhttps)、ホスト名、ポート番号の組です。たとえば https://example.com と http://example.com は別のオリジンなので、引き出しも別になります。
  • 端末の外には出ません。 ブラウザが自動でクラウドに同期するとは限らず、サーバーに送られる仕組みでもありません。別の端末で同じサイトを開いても、中身は空です。

物理的な保存先については、Web Storage の仕様がファイルの場所や形式を決めていません。ブラウザの利用者データの置き場所(プロファイル)の中に、ブラウザ独自の形式で置かれるのが一般的です。具体的なパスを覚えるより、各ブラウザの開発者ツールにあるストレージの表示で中身を見るほうが確実で安全です。

消える条件を整理する

「ブラウザが管理している」ということは、消す権限もブラウザと利用者が持っているということです。ゲームの作者が「保存した」と思っていても、次のような条件で引き出しは空になります。

  • 利用者がサイトデータや閲覧データを消去した、何が起きるか:対象のサイトの引き出しが空になります、見分け方:消去の範囲(期間・サイト指定)を設定画面で確かめます
  • プライベートブラウズ(シークレットモード)を閉じた、何が起きるか:そのウィンドウ中だけの引き出しが破棄されます、見分け方:通常ウィンドウで同じサイトを開いて比べます
  • ブラウザが容量不足などで自動整理した、何が起きるか:古い、または使われていないサイトのデータが削除されることがあります、見分け方:扱いはブラウザごとに違うため、各ブラウザの公式の説明を確認します
  • 一定期間そのサイトを使わなかった、何が起きるか:ブラウザによっては、長く使われないサイトのデータを消す設計があります、見分け方:利用中のブラウザの仕様を確認します
  • オリジンが変わった、何が起きるか:住所が変わると、別の引き出しになります。消えたのではなく、見えなくなっただけです、見分け方:アドレスバーのプロトコルとホスト名を比べます
  • 端末やブラウザを変えた、何が起きるか:引き出しは持ち越されません、見分け方:同じ端末・同じブラウザで開いているかを確かめます
  • 保存時に容量の上限を超えた、何が起きるか:書き込みがエラーになり、保存されません、見分け方:開発者ツールのコンソールに例外が出ていないか見ます

表の下の三行は、データが消えたのではなく「最初から入っていない」「見えない」状態です。サポートへの問い合わせでは、この区別がつかないまま「消えた」と報告されることがよくあります。原因が違えば対処も違うので、切り分けの観点として覚えておくと便利です。

また、容量の上限はブラウザによって異なり、数値は変わりうるものです。この記事では具体的な数字は挙げません。大きなデータを入れる設計にするときは、各ブラウザの公式ドキュメントを確認してください。

自分の端末で確かめる実験の設計書

説明を読むだけでは実感しにくいので、自分のブラウザで引き出しの動きを確認する手順を示します。結果はブラウザや設定によって変わるため、ここでは書きません。表の予測と照らして、ご自身で読み取ってください。

準備するもの

次のHTMLを drawer.html という名前で保存します。読み込むたびに回数を1増やして表示するだけの、外部通信なしのファイルです。

html
<!doctype html>
<meta charset="utf-8">
<title>引き出しの確認</title>
<p>オリジン:<code id="o"></code></p>
<p>読み込み回数:<span id="n"></span></p>
<button id="r">リセット</button>
<script>
const KEY = "drawer-test";
document.getElementById("o").textContent = location.origin;
try {
  const n = Number(localStorage.getItem(KEY) || 0) + 1;
  localStorage.setItem(KEY, String(n));
  document.getElementById("n").textContent = n;
} catch (e) {
  document.getElementById("n").textContent = "使えません:" + e.name;
}
document.getElementById("r").onclick = () => localStorage.removeItem(KEY);
</script>

ファイルを直接開く(file://)場合、ブラウザによってオリジンの表示や localStorage の扱いが異なります。これも観察の対象です。

手順と記録

次の条件を一つずつ試し、それぞれ「読み込み回数の表示」と「オリジンの表示」を書き留めます。条件ごとに1回ずつ、合計6回程度で十分です。

  1. 通常のウィンドウで開き、再読み込みを3回します。
  2. ブラウザを完全に閉じて開き直し、同じファイルをもう一度開きます。
  3. 別のブラウザ(入っていれば)で同じファイルを開きます。
  4. プライベートブラウズで開き、再読み込みを2回してからウィンドウを閉じ、新しいプライベートウィンドウでもう一度開きます。
  5. 開発者ツールのストレージ表示(ブラウザにより「Application」「ストレージ」などの名称です)で、drawer-test のキーと値を確認します。
  6. ブラウザの設定でこのファイルのサイトデータだけを消去し、もう一度開きます。

結果の読み方

  • 手順2で回数が続いていれば、引き出しはブラウザを閉じても残る性質を持っています。0や1に戻っていれば、そのブラウザの設定や環境でデータが保持されていないことになります。
  • 手順3で回数が引き継がれなければ、「ブラウザごとに別」を確認できたことになります。
  • 手順4の2回目の起動で回数が戻っていれば、プライベートブラウズの引き出しが閉じた時点で破棄されると読めます。
  • 手順5でキーが見つからないのに画面に回数が出ているなら、別のオリジンを見ている可能性があります。開発者ツールが表示しているオリジンと、画面のオリジン表示を比べてください。
  • 「使えません」と表示された場合は、ブラウザの設定や環境が保存を制限している可能性があります。例外の名前を手がかりに調べます。

起こりやすい誤りもあります。試す対象に、普段遊んでいるサイトを選ばないでください。開発者ツールのコンソールでそのサイトの localStorage を書き換えたり消したりすると、本物の記録を失うことがあります。必ず上の自作ファイルで試します。

アソバースの中ではどうなっているか

ここからは、確認済みの事項だけを根拠に、「設計から読み取れること」として整理します。

アソバースでは、アップロードされたゲームはsandbox付きのiframeで実行され、コードはメインサイトと別のオリジンから配信されます。そのうえで、アップロード作品内の localStorage と sessionStorage は「一時メモリーの互換処理」とされています。ここから読み取れるのは、作品が localStorage.setItem を呼んでもエラーで止まらず動く一方で、その内容は端末に残る保存として当てにできない、ということです。ブラウザが持つ本物の引き出しとは、役割が違うと考えるのが安全です。

公式作品13本の案内にも、同じ設計が表れています。

  • 保存があるのは「余白の庭」「WAVE / WAVE」「かたちのあいだ」の3作品です。
  • 残りの10作品では、記録や録音は画面を開いている間だけ残ります。たとえば「雨音のピアノ」の録音や「こだまの森」の最高記録がこれに当たります。
  • 一方で、言語の切り替えやプレイ画面の拡大では進行が保たれる設計になっています。
  • 古い保存(version1)は、新しい形式(version2)へ移行されます。

3作品の保存が内部でどのような方式を使っているかは、確認済み事項に含まれていません。この部分は、作品を開いて実際に保存や再読み込みを試し、挙動で確かめてください。

では、アソバース上で記録を長く持たせたい作者は何を使えるのでしょうか。確認できているのは次の経路です。

  • アップロードしたゲームにはSDKが自動で追加され、URL投稿のゲームは作者がSDKを読み込むと、作品専用のプレイヤーIDとクラウドセーブが使えます。
  • クラウドセーブは作品ごとにJSONで128KiBまでです。
  • ゲームにFirebaseのUID、認証トークン、メールアドレスは渡されません。
  • クラウドセーブが使えるのは、ログイン中の利用者です。ログインにはGoogleまたはメールアドレスが使えます。

端末とクラウドの関係にも、読み取れる点があります。ゲストの履歴や進行は端末内に保存され、ログイン後のアカウントへ自動では混ざりません。また、未同期の端末セーブは、クラウドの古いデータより優先して再送されます。「端末のほうが新しいのに、古いクラウドで上書きされる」事態を避ける設計と読めます。退会すると、履歴やセーブを含む個人データも削除されます。

立場別の判断基準

最後に、読む人の立場ごとに、引き出しの性質をどう使い分けるかを整理します。

遊ぶ人は、長く残したい記録があるなら、そのゲームが「保存あり」かどうかを先に確かめます。公式13作品では、保存があるのは3作品だけです。それ以外では、ページを閉じると記録が消えるものと考えて遊ぶのが前提になります。

保護者の方は、「端末の引き出し」が子どもの端末のブラウザ設定に左右される点に注意が必要です。サイトデータの消去や、共有端末でのプライベートブラウズが、記録が消える原因になりえます。ゲストの進行はログイン後のアカウントに自動では移らないため、移行したいときは、遊ぶ前にログインしておくのが確実です。

作る人は、localStorage だけに頼る設計のリスクを数えておきます。次の観点でチェックしてみてください。

  1. そのデータが消えたら、利用者は困るのか。困るなら、保存先を二重にするか、消えることを画面で伝えます。
  2. 保存の失敗(容量超過や制限環境)を try/catch で受け、失敗しても遊べる作りになっているか。
  3. 保存形式にバージョンを持たせているか。形式を変える日が来たときに、古い保存を新しい形式へ移せます。
  4. アソバースに投稿するなら、作品内の localStorage は一時メモリーの互換処理であることを前提に、残したい進行はクラウドセーブで設計するか。

学習者は、上の実験を一度行ってみてください。「保存した」という言葉が、どのブラウザで、どのオリジンで、どの条件まで有効かを、自分の画面で言い切れるようになります。

次の行動

まず上の drawer.html を作り、6つの条件で回数とオリジンを書き留めてみてください。次に、気になる公式作品を開き、保存ありの3作品とそれ以外の作品で、画面を開き直したときの違いを確かめます。投稿を考えている方は、残したい進行をクラウドセーブに載せる設計から検討してください。

参考資料

  • MDN Web Docs「Web Storage API」
  • MDN Web Docs「ストレージの割り当てとエビクション」
  • WHATWG HTML Living Standard「Web storage」

出典・参考資料