社名変更にあわせて新しいドメインへサイトを移した翌朝、サポート窓口に同じ問い合わせが立て続けに入った。「ホーム画面に置いていたアプリのアイコンを開くと、見慣れない『このページは移動しました』の白い画面が出る」「いつも届いていたお知らせの通知が、昨日からぱったり止まった」。リダイレクトは全URLぶん丁寧に張ったはずなのに、なぜか旧ドメインで使ってもらっていた“アプリ”だけが置き去りになっている。
これは作り話ではなく、PWA(ホーム画面に追加して使えるWebアプリ)を運用しているサイトがドメインを変えるときに、ほぼ確実に踏む地雷だ。検索順位やブックマークの引き継ぎは301リダイレクトで何とかなる。ところが、ホーム画面に追加されたPWAそのもの、その裏で動くService Worker、プッシュ通知の購読、端末に保存されたデータは、リダイレクトとは別の層に属している。ここを設計に入れずに移行すると、いちばん熱量の高い「アプリとして使い続けてくれていた既存ユーザー」だけを、移行の瞬間に丸ごと失う。
検索評価とリダイレクトの観点はドメイン移行とサイトリニューアルSEOの記事で扱った。本記事はそこと意図的に切り分け、PWA・インストール状態・通知購読というクライアント側の引き継ぎだけに踏み込む。
なぜリダイレクトでは「アプリ」が死ぬのか
PWAの正体を分解すると、ドメイン移行で何が切れるのかが見えてくる。ユーザーがホーム画面に追加したPWAは、サーバー上のページそのものではなく、ブラウザが「このオリジン(https://ドメイン名の単位)にひもづくインストール済みアプリ」として端末に記録した一個の登録だ。そしてその裏では、次の3つがすべて「オリジン単位」で結びついている。
- Service Worker:オフライン動作やキャッシュ、通知の受け取りを担う常駐スクリプト。登録できるのは自分と同じオリジンのページに対してだけ
- プッシュ通知の購読(Push Subscription):「この端末のこのブラウザに通知を送ってよい」という許可と宛先。Service Workerの登録にぶら下がっている
- 保存データ(IndexedDB / Cache Storage など):ログイン状態、下書き、オフライン用データなど、オリジンごとに隔離されたストレージ
ここで効いてくるのが、Webのセキュリティの大原則である「同一オリジンポリシー」だ。old.example.com のService Workerは new.example.jp のページを制御できないし、old.example.com で取った通知購読を new.example.jp がそのまま読むこともできない。オリジンが変わった時点で、ブラウザから見れば両者は「赤の他人のサイト」なのだ。
だからドメイン移行で起きることはこうなる。旧ドメインへアクセスしたユーザーは301で新ドメインへ飛ぶ。新ドメインは新しいオリジンなので、ブラウザは「初めて来たサイト」として扱う。旧ドメインにあったインストール済みPWAは宙に浮いたまま残り、ホーム画面のアイコンをタップしても、もう中身のない旧オリジンを開こうとする。通知を送っていたサーバーは旧オリジンの購読宛先に投げ続けるが、ユーザーはもう旧ドメインを開かないので、購読は更新されないまま静かに失効していく。これが「アイコンが死に、通知がゼロになる」の正体だ。
旧: https://old-corp.example.com ← ホーム画面のPWA / SW / 通知購読 / 保存データ
│ 301リダイレクト(ページは飛ぶ)
▼
新: https://newbrand.example.jp ← 別オリジン。上の4つは何も引き継がれない
ページは飛ぶのに、アプリの実体は飛ばない。リダイレクトを「全URL完璧に」張ったチームほど、この層の存在に気づかず本番で初めて事故る。
Chrome の「Web App Origin Migration」で引き継げるもの・引き継げないもの
この問題に対して、Chrome は「Web App Origin Migration(PWAのオリジン移行)」という仕組みを用意し始めている。Chrome Developers のブログ記事「Seamless PWA origin migration: Change domains without losing users」で解説されているもので、Webアプリマニフェストに移行先・移行元を宣言することで、インストール済みPWAの“身元”を新オリジンへ付け替えられる。
仕組みはマニフェストの2つのフィールドと、所有を証明するハンドシェイクで構成される。新オリジンのマニフェストに移行元を指す migrate_from を、旧オリジンのマニフェストに移行先を指す migrate_to を書く。
// 新オリジン newbrand.example.jp の manifest.webmanifest
{
"name": "NewBrand",
"id": "/",
"start_url": "/",
// 旧オリジンのインストール済みPWAを引き継ぐ宣言
"migrate_from": [
{ "origin": "https://old-corp.example.com", "behavior": "suggest" }
]
}
そのうえで、旧オリジン側に所有確認用の .well-known ファイルを置き、移行を許可していることを示す。これは第三者が勝手に他社のPWAを乗っ取る(フィッシング目的で「うちに移行しろ」と宣言する)のを防ぐための双方向の合意だ。
// 旧オリジン側 https://old-corp.example.com/.well-known/web-app-origin-association
{
"https://newbrand.example.jp/": { "allow_migration": true }
}
ユーザー体験としては、旧サイトから新サイトへ誘導された際にブラウザがこの宣言を検出し、通常のアプリ更新と同じような確認ダイアログを出す。ワンタップで旧PWAがアンインストールされ、新PWAがインストール・起動される。behavior に force を指定すれば更新を強制でき、suggest なら提案にとどめられる(名前やアイコンの変更は移行と同時にはできず、移行完了後に通常のアプリ更新として反映される、という制約もある)。
ここで受託の発注判断として絶対に外せない前提が2つある。
1つめ。この仕組みは「同一サイト(same-site)」のオリジン移行に限定されている。 つまり app.example.com から example.com/app/ のようにサブドメインやパスを変える移行は救えるが、old-corp.com から newbrand.jp のように登録ドメインそのものが変わる移行(社名変更でまったく別ドメインに引っ越す、いちばんありがちなケース)は対象外だ。仕様上、別サイト間の移行はフィッシングなどのリスクが大きいとして意図的に除外されている。リブランドで完全に別ドメインへ移る案件では、このChromeの機能では救えない、という前提から設計を始める必要がある。
2つめ。移行で引き継がれるのはPWAの“インストール識別”だけで、中身は引き継がれない。 通知の許可をはじめとする各種パーミッション、IndexedDB や Cache Storage に貯めた保存データは移行スコープの外で、新オリジンは原則「まっさらな新規インストール」として扱われる。通知購読を生き残らせ、保存データを運ぶのは、ブラウザではなくこちら側(サーバーと実装)の責任になる。
なお、この機能は仕様としてはまだ標準化の途上(W3C/WICGで議論中)で、対応ブラウザもChrome系が先行している段階だ。Safari/iOSなど他環境では現時点で同等の挙動は期待できない。本番採用時は対象ユーザーのブラウザ構成と最新の対応状況を必ず確認してほしい、という点は明記しておく。
通知購読と保存データを「自前で」生き残らせる設計
Chromeの機能が同一サイトに限られる以上、別ドメインへ移るリブランド案件で頼りになるのは、ブラウザ任せではなく自分たちで引き継ぐ設計だ。受託で組み込む勘所は次の3つに集約される。
まず通知購読のサーバー側保持。プッシュ通知は「端末ごとの購読情報(エンドポイントと鍵)」をサーバーが持っていて初めて送れる。これを旧オリジンのクライアント任せにせず、ユーザーアカウントにひもづけてサーバーDBに保存しておけば、ドメインが変わってもサーバー側の宛先は残る。とはいえ前述のとおり購読自体はオリジンに縛られるため、移行後は新オリジンで購読を取り直す(再購読させる)導線が必須になる。ログインしたユーザーに対し、新オリジンで再度通知許可を求め、新しい購読を旧アカウントに上書き保存する、という流れだ。
次に**pushsubscriptionchange イベントの実装**。Service Workerには、ブラウザの都合で購読が更新・失効したときに発火する pushsubscriptionchange というイベントがある。ここで新しい購読を取り直し、サーバーへ送り直す処理を入れておくと、移行に限らず日常の購読切れにも強くなる。
// service-worker.js(新オリジン側)
self.addEventListener('pushsubscriptionchange', (event) => {
event.waitUntil(
self.registration.pushManager
.subscribe(event.oldSubscription.options) // 同じ条件で取り直し
.then((newSubscription) =>
// 新しい購読をサーバーへ。古い購読と差し替える
fetch('/api/push/resubscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
old: event.oldSubscription,
new: newSubscription,
}),
})
)
);
});
最後に保存データの移送方針。IndexedDB などオリジン隔離されたストレージは自動では運べない。ログイン状態やユーザー設定など「失うとユーザーが離れる」データは、移行前にサーバーへ同期しておき、新オリジンで初回ログイン時にサーバーから再構築するのが堅い。逆に、再計算できるキャッシュ類は無理に運ばず捨てる判断をする。ここは「何を失うとユーザーが怒るか」を起点に、運ぶデータと捨てるデータを線引きする設計判断であって、技術より優先順位の話だ。
弊社の受託案件で起きたこと
会員向けに配送状況のプッシュ通知を出していた、ある小売事業者(社名は伏せる)のリブランド案件で、まさにこの落とし穴を踏みかけた。当初の移行計画は「全URLを301で転送し、Search ConsoleとGA4で順位を観測する」という、検索評価中心の設計だった。リダイレクト設計としては妥当だったが、PWAと通知の層がすっぽり抜けていた。
ステージングでの検証中に、こちらから「旧ドメインでホーム画面に追加している会員は何人いるか」「通知購読は何件アクティブか」を確認したところ、アクティブ購読のうち相当数が、アプリ的な使い方をするリピーター——つまり客単価の高い常連層に集中していた。このまま素直に移行すれば、検索流入は守れても、いちばん売上に効く常連の通知だけが一夜で消える、という構図だった。
別ドメインへの移行だったためChromeのオリジン移行機能は使えず、対応は自前の再購読フローに切り替えた。具体的には、(1) 移行前に購読情報を会員アカウントにひもづけてサーバー保存、(2) 新ドメインの初回ログイン時に通知許可を取り直し、(3) 旧購読は失効としてサーバー側で差し替える、という三段構えだ。あわせて、移行後しばらくは旧ドメインを即時には捨てず、旧ドメインにアクセスした会員へ「新ドメインのアプリに入れ直してください」という再追加導線を出す期間を設けた。結果として、移行後の通知到達は緩やかに回復し、常連層の離脱は最小に抑えられた。
この案件で学んだのは、PWAと通知の引き継ぎは「移行作業の中の一工程」ではなく、移行計画を立てる前に『誰が・どの機能を・どれだけ使っているか』を棚卸しする段階の話だということだ。インストール済みユーザーの数と、その層の事業上の重みを知らないまま移行設計には入れない。PWAをこれから導入する/されている前提の整理は中小企業向けPWA導入ガイドも合わせて読むと、自社の現在地がつかみやすい。
発注前に確認しておきたいこと
ドメイン移行を伴うリニューアルを発注する側として、見積もりや提案を受け取る前に、自社の状況をいくつか押さえておくと話が早い。ホーム画面への追加(PWAのインストール)を促す施策をやってきたか。プッシュ通知を送っているか、その購読は何件あって、どんな層が使っているか。新ドメインは旧ドメインと同一サイト(サブドメイン違い)なのか、それとも完全に別ドメインなのか。この3点で、移行に必要な作り込みの重さが大きく変わる。
提案を受ける側として、リダイレクトとSEOの話しか出てこない移行計画には、「PWAのインストール状態と通知購読はどう引き継ぐのか」を一度ぶつけてみてほしい。そこで具体的な答えが返ってくるかどうかが、移行設計の解像度を測る試金石になる。リニューアル自体を切り出すタイミングの判断はサイトリニューアルのタイミングの記事も参考になるはずだ。
グリームハブでは、ドメイン移行・サイト統合に伴うPWAと通知購読の引き継ぎ設計を、現状の棚卸しから本番後の再購読導線まで一貫してご支援しています。「リブランドで別ドメインに移したいが、アプリ追加してくれた常連と通知を失いたくない」というご相談は、お問い合わせフォームからお気軽にどうぞ。現行の購読状況とブラウザ構成を拝見したうえで、何を引き継ぎ何を捨てるかの線引きからご一緒します。
Sources
- Seamless PWA origin migration: Change domains without losing users(Chrome for Developers)
- PWA Origin Migration Explainer(WICG/manifest-incubations)
- Ready for Developer Testing: Web App Origin Migration(blink-dev)
- ServiceWorkerGlobalScope: pushsubscriptionchange event(MDN)
- Progressive Web Apps in multi-origin sites(web.dev)