壁紙アプリを 6 本並行で運用していると、同じ「最初の 3 画面」を 6 回つくり直していたことにある日気づきます。配色もコピーも微妙に違い、どのアプリで何を直したのか自分でも追えなくなっていました。2026 年 5 月、これを一度ぜんぶ畳んで 1 つの共通オンボーディングに寄せ、1 ヶ月運用してみたので、その前後で数字がどう動いたかを正直に書き残しておきます。
なぜ 6 本まとめて作り直したのか
きっかけは収益でも流入でもなく、保守の苦しさでした。あるアプリでオンボーディング 2 枚目の文言を直したつもりが、別のアプリでは古いままになっている。プッシュ通知の許諾を求めるタイミングも、アプリごとに「起動直後」だったり「1 枚目の後」だったりとバラバラで、許諾率を比較しても何が効いたのか切り分けられませんでした。
両家の祖父がともに宮大工で、丁寧に組み上げた仕口は何十年も持つことを近くで見て育ちました。コードも同じで、6 本に散らばった似て非なる実装は、便利そうに見えて実は一番もろい状態です。まず構造を一本に通すところから手をつけることにしました。
共通化のためにやったこと
方針はシンプルで、画面そのものを共通化するのではなく「オンボーディングの中身を設定として渡す」形にしました。各アプリは配色とコピーとステップ数だけを宣言し、描画ロジックとプッシュ許諾の呼び出しタイミングは 1 つの共通コンポーネントに集約します。
// onboarding.config.ts —— アプリごとに変えるのはここだけ
export type OnboardingStep = {
key: string;
title: string;
body: string;
image: number; // require() の戻り値
askPushAfter?: boolean; // この画面を読み終えた直後に許諾を求めるか
};
export const onboardingConfig: OnboardingStep[] = [
{
key: "welcome",
title: "毎日の一枚を、静かに",
body: "気分に合う壁紙を、数タップで着せ替えできます。",
image: require("./assets/onb-welcome.webp"),
},
{
key: "value",
title: "お気に入りはすぐ呼び出せます",
body: "保存した壁紙はホームの上部にまとまります。",
image: require("./assets/onb-value.webp"),
askPushAfter: true, // 価値が伝わった直後に通知許諾を求める
},
];// SharedOnboarding.tsx —— 6 本で完全に共通
import { useState, useCallback } from "react";
import * as Notifications from "expo-notifications";
import { onboardingConfig } from "./onboarding.config";
export function SharedOnboarding({ onDone }: { onDone: () => void }) {
const [index, setIndex] = useState(0);
const step = onboardingConfig[index];
const next = useCallback(async () => {
if (step.askPushAfter) {
// ユーザーが価値を理解した後に初めて OS ダイアログを出す
await Notifications.requestPermissionsAsync();
}
if (index < onboardingConfig.length - 1) {
setIndex((i) => i + 1);
} else {
onDone();
}
}, [index, step, onDone]);
return <OnboardingView step={step} progress={(index + 1) / onboardingConfig.length} onNext={next} />;
}ポイントは askPushAfter です。以前は起動直後に許諾ダイアログを出していましたが、まだ価値が伝わっていない段階で求めても拒否されるだけでした。共通化のついでに「価値が伝わった 2 枚目の直後」に統一しています。アプリ側のコードは設定ファイルを書き換えるだけになり、文言の直し忘れがそもそも起こらない構造になりました。
思っていたより手こずった 3 つの壁
一本化は気持ちよく進むと思っていましたが、現実にはいくつか引っかかりました。どれも派手な不具合ではなく、長く運用してきたアプリほど過去の自分の判断が残っていて、それを丁寧にほどく作業でした。
1 つ目は、画像アセットの命名がアプリごとにバラバラだったことです。共通コンポーネントは require() の戻り値を受け取る前提なので、各アプリの assets/ を onb-welcome.webp のように規約で揃え直す必要がありました。地味ですが、ここを曖昧にすると共通化の意味が薄れます。
2 つ目は、初回起動の判定です。6 本のうち数本は古い実装で「初回フラグ」をそれぞれ別のキー名で保存しており、共通化後に「既存ユーザーにもオンボーディングが再表示される」事故を一度起こしました。マイグレーションで旧キーを読んで新キーへ移すコードを挟んで解消しています。
3 つ目は、プッシュ許諾のタイミングを変えたことで、iOS の事前許諾(プリパーミッション)画面との二重表示が起きたアプリがあったことです。これは設定で許諾の呼び出しを 1 箇所に寄せたからこそ気づけた重複で、結果的にコードを読みやすくしてくれました。
1 ヶ月の数字から見えたこと
手元の 6 本平均で、共通化前後の 4 週間を比べた変化はおおむね次の通りでした。あくまで私のアプリでの観測値で、ジャンルや国別構成によって変わる点は差し引いて読んでください。
オンボーディング完了率は約 71% から約 84% に上がりました。3 画面構成を 2 画面に削ったことが効いていそうです。初日継続率(D1)は 6 本平均で 32% 前後から 38% 前後へ。プッシュ通知の許諾率は、起動直後に求めていた頃の 19% から、価値提示の直後に変えてから 27% まで伸びました。2014年から個人でアプリを出し、累計で 5,000万ダウンロードほどを重ねてきましたが、数字の規模が大きくても、結局は最初の数分の体験設計が効くのだと改めて感じます。許諾タイミングをこれだけ動かしただけで二桁パーセント変わるのを数字で見たのは、正直に言って収穫でした。
数字の取り方も補足しておきます。オンボーディング完了率は最終画面の onDone 到達イベント、初日継続率は新規ユーザーの翌日再起動で計測しており、共通化の前後で計測コードは一切変えていません。ここを揃えておかないと、改善したのか計測がぶれたのかを後から切り分けられなくなります。
逆に、課金や 7 日継続率には今回はっきりした差は出ませんでした。オンボーディングが効くのは「最初の数分」までで、その先は別の要因が支配する、という当たり前の事実を改めて確認した形です。
これから手を入れたいところ
次は、設定ファイルに「言語ごとのコピー差し替え」を組み込むつもりです。今は日本語と英語を別ファイルで持っていますが、ステップ定義の中に多言語を畳み込めば、6 本 × 言語の管理がもう一段楽になります。あわせて、2 枚目のコピーを数パターン用意して、許諾率がどこまで動くかを 1 本ずつ試していきたいと考えています。
似たように複数アプリのオンボーディングがばらけて困っている方の、整理のきっかけになれば幸いです。お読みいただきありがとうございました。