新しい SaaS のウェイトリスト2 分で読めます
App Store 公開前のモバイルアプリ用ウェイトリストページの作り方
使っているスマホを尋ね、iPhone のテスターを TestFlight に送り、Play のクローズドテストを埋める、iOS・Android アプリ向けの公開前ウェイトリストです。
アプリのランディングページに、使っているスマホと早期テストを希望するかを尋ねるウェイトリストフォームを置きます。iPhone のテスターは Webhook と App Store Connect API で TestFlight のグループに送り、Android のテスターはエクスポートから Google Play のクローズドテストに登録します。公開日には、各グループにそれぞれのストアへのリンクをメールで送ります。
アプリがストアに並ぶまでは、案内できるインストールボタンがありません。自分のランディングページにウェイトリストを置けば、それまで関心をつなぎ止められるうえ、ストアにはできないもう 1 つの役割も果たせます。公開前に必要なテスターを見つけることです。
モバイルアプリならではの違い
- ストアが 2 つ、リストも 2 つ。 公開のメールは App Store か Google Play にリンクし、テストの招待は TestFlight か Play のクローズドテストで送ります。適切なほうを送るには、各人のプラットフォームを知る必要があります。
- テスターはストアのアカウントと一致している必要があります。 TestFlight はどのアドレスにも招待メールを送ります。Play のクローズドテストはリストにある Google アカウントしか受け入れないので、仕事用のアドレスで登録した Android のテスターはビルドをインストールできません。
- Google Play では公開前にテスターが必要な場合があります。 2023 年 11 月 13 日以降に作成された個人のデベロッパーアカウントは、本番に公開する前に、14 日間連続でオプトインし続けるテスターが 12 人以上いるクローズドテストを実施する必要があります。その 12 人を集める場所がウェイトリストです。
- ストアには独自の公開前ツールがあります。 ウェイトリストの代わりではなく、併用する価値があります。下の比較を見てください。
| Item | App Store の予約注文、Play の事前登録 | 自分のウェイトリスト |
|---|---|---|
| ストアの掲載情報が必要 | はい、承認済みで準備完了のもの | いいえ。ランディングページの初日から使えます |
| 得られるもの | 件数と、リリース時のストアからの通知または自動ダウンロード | 各人のメールアドレス、プラットフォーム、回答 |
| テスターを招待できるか | いいえ | はい、メールで TestFlight や Play のクローズドテストに |
| 制限 | 新しい個人アカウントでは、テストの要件を満たすまで Play の事前登録は使えません | 公開のメールは自分で送ります |
アプリのウェイトリストのフィールド
メールアドレス欄の意味が変わるので、まずプラットフォームを尋ねます。機種は任意で、どの端末でテストすべきかがわかります。ベータのチェックボックスで、テストしたい人と公開のメールだけほしい人を分けます。
プレビュー
Ikiform のバリデーターをブラウザーで実行します。何も送信されません。
platform のラジオボタンは必須なので、どの登録も対応可能なリストに入ります。定義をフォームの Fields タブに貼り付けてください。フォーム
このフォームは、どのランディングページでもプレーンな HTML として動きます。スクリプトが行うのは 2 つの小さなことだけです。訪問者のブラウザーからプラットフォームを事前に選択し、Google アカウントの注意書きを Android のユーザーにだけ表示します。
<form id="app-waitlist" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<fieldset>
<legend>Which phone do you use?</legend>
<label><input type="radio" name="platform" value="iphone" required> iPhone</label>
<label><input type="radio" name="platform" value="android"> Android</label>
</fieldset>
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" inputmode="email" required>
<p id="email-hint" hidden>Use the Google account you sign in to Google Play with.</p>
<label for="first_name">First name</label>
<input id="first_name" name="first_name" autocomplete="given-name" maxlength="60">
<label for="device">Phone model</label>
<input id="device" name="device" maxlength="80" placeholder="iPhone 15, Pixel 8">
<label><input type="checkbox" name="beta" value="true"> Invite me to test the app before launch</label>
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
<button>Join the waitlist</button>
</form>
<script>
const form = document.getElementById("app-waitlist");
const agent = navigator.userAgent;
const guess = /iPhone|iPad/.test(agent) ? "iphone" : /Android/.test(agent) ? "android" : null;
if (guess) form.querySelector(`[name="platform"][value="${guess}"]`).checked = true;
const hint = () => {
document.getElementById("email-hint").hidden = form.platform.value !== "android";
};
form.addEventListener("change", hint);
hint();
</script>- 推測はラジオボタンを事前に選択するだけです。変更もでき、スクリプトがなければ何も選択されないので、
requiredによって必ず選んでもらえます。 inputmode="email"とautocomplete="email"は、ここでは他のどこよりも重要です。アプリのランディングページの訪問者はほとんどがスマホからだからです。- Redirect after submit(送信後のリダイレクト)に、プラットフォームごとに次に何が起きるかを説明するサンクスページを設定します。フレームワーク版のフォームはメインのガイドを参照し、これらのフィールドを追加してください。
テスターをそれぞれのストアに振り分ける
- iPhone のユーザーがベータのチェックボックスにチェックを入れると、署名付き Webhook が送られます。
- 中継サーバーがそれを検証し、App Store Connect API を呼び出してアドレスを TestFlight のグループに追加します。
- グループで利用できるビルドができると、Apple が TestFlight の招待メールを送ります。
- Android のテスターも同じ方法で集め、CSV でエクスポートしてプラットフォームで絞り込みます。
- Google アカウントを Play Console のクローズドテストのメールリストに貼り付けます。
- メールツールから、テストのオプトインリンクをメールで送ります。
iPhone: TestFlight にテスターを追加する
App Store Connect で外部テストグループを作成し、Users and Access › Integrations で App Manager か Admin のロールを持つ API キーを作成します。次に、Ikiform の submission.created Webhook を受け取る中継サーバーを追加します。ここでは Next.js のルートハンドラーで、Apple のトークンの署名に jose を使っています。fetch があるサーバーならどこでも動きます。
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { importPKCS8, SignJWT } from "jose";
async function appStoreToken() {
const key = await importPKCS8(process.env.ASC_PRIVATE_KEY!, "ES256");
return new SignJWT({})
.setProtectedHeader({ alg: "ES256", kid: process.env.ASC_KEY_ID!, typ: "JWT" })
.setIssuer(process.env.ASC_ISSUER_ID!)
.setAudience("appstoreconnect-v1")
.setIssuedAt()
.setExpirationTime("15m")
.sign(key);
}
export async function POST(request: Request) {
const payload = await request.text();
try {
const event = await verifyWebhook({ payload, headers: request.headers, secret: process.env.IKIFORM_WEBHOOK_SECRET! });
if (event.type !== "submission.created") return new Response(null, { status: 204 });
const { email, first_name, platform, beta } = event.data.fields;
if (platform !== "iphone" || beta !== true) return new Response(null, { status: 204 });
const response = await fetch("https://api.appstoreconnect.apple.com/v1/betaTesters", {
method: "POST",
headers: { authorization: `Bearer ${await appStoreToken()}`, "content-type": "application/json" },
body: JSON.stringify({
data: {
type: "betaTesters",
attributes: { email: String(email), firstName: first_name ? String(first_name) : undefined },
relationships: { betaGroups: { data: [{ type: "betaGroups", id: process.env.ASC_BETA_GROUP_ID! }] } },
},
}),
});
if (response.ok || response.status === 409) return new Response(null, { status: 204 });
return new Response(`App Store Connect answered ${response.status}`, { status: 502 });
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
}ASC_PRIVATE_KEYは Apple から受け取る.p8ファイルの中身で、改行も含みます。ASC_KEY_IDとASC_ISSUER_IDは同じページにあります。- Apple のトークンの有効期間は最大 20 分なので、中継サーバーは配信ごとに新しいトークンに署名します。
409は Apple が変更を競合として拒否したことを意味し、多くはそのアドレスがすでにテスターである場合です。中継サーバーはこれを完了として扱うので、招待が届かないテスターがいたら App Store Connect でグループを確認してください。それ以外の失敗には502を返すので、Ikiform が配信をリトライします。- TestFlight では、アプリごとに最大 10,000 人の外部テスターを追加できます。外部グループに最初に渡すビルドは Beta App Review を通る必要があり、各ビルドは 90 日で期限切れになります。
Ikiform の Webhooks に中継サーバーの URL を追加し、whsec_ のシークレットを IKIFORM_WEBHOOK_SECRET にコピーします。1 つのワークスペースにエンドポイントは 3 つまで登録できるので、メールツールに送る中継サーバーと並べて動かせます。
Android: クローズドテストを埋める
Google Play の公開 API はクローズドテストのテスターを個々のアドレスではなく Google グループで管理するので、こちらは毎週のエクスポートで対応します。Export CSV でリストをエクスポートし、スプレッドシートで platform = android かつ beta = true に絞り込んで、Play Console の Test and release › Testing › Closed testing › Manage track › Testers にあるクローズドテストのメールリストにメールアドレスを追加します。そのあと、メールツールからその人たちにテストのオプトインリンクを送ります。
12 人のテスター要件を満たすつもりなら、12 人より多く招待してください。オプトアウトした人や一度もオプトインしなかった人は数に入らず、14 日間ずっと 12 人がオプトインしている必要があります。
ローンチ日
リスト全体をエクスポートし、platform で分けます。それぞれのグループに、ストアのリンクを 1 つだけ載せたメールを 1 通送ります。iPhone を選んだ人に Play のリンクは不要ですし、バッジを 2 つ並べたメールは小さな画面ではタップされにくくなります。device を集めていたなら、送る前に、登録者が挙げた機種とクラッシュレポートを照らし合わせておきましょう。
動作を確認する
- フォームの Allowed domains に、自分のサイトのドメインと、開発中は
localhostを追加します。空にしておくと、どこからの送信も受け付けます。 - スマホでページを開きます。正しいプラットフォームが事前に選択され、Android では Google アカウントの注意書きが表示されます。
- iPhone のテスターとして送信します。送信データの
platformはiphone、betaはtrueになります。 - Webhooks で中継サーバーのエンドポイントを開きます。配信は
succeededと表示され、アドレスが TestFlight のグループに載っています。 - Android のテスターとして送信し、CSV をエクスポートして、
platformをandroidにするとその行が絞り込まれることを確認します。 - ハニーポットに値を入れて
_gotcha=botで送信します。成功の応答は返りますが、送信データはスパムとして保存され、メールも Webhook も送られません。
ハマりどころ
| 問題 | 対処法 |
|---|---|
中継サーバーへの配信が 502 で失敗し、Apple が 401 を返した | トークンが間違っています。キー ID、発行者 ID を確認し、環境変数の秘密鍵の改行が保たれているか確かめてください。 |
| テスターは追加されたが TestFlight のメールが届かない | グループにまだビルドがないか、最初のビルドが Beta App Review 中です。グループでビルドが利用可能になると招待が送られます。 |
| Android のテスターがオプトインリンクを開けない | リストにあるアドレスが、スマホでログインしている Google アカウントと違います。そのアカウントでもう一度登録してもらってください。 |
422 validation_failed | 送信がフォームのフィールド定義に合っていません。error.fields に各フィールドと理由が示されます。入力欄の name をフィールド ID に合わせてください。 |
| 送信データはダッシュボードにあるのに、メールも Webhook も届かない | スパムとして保存されています。スパムは何も送りません。Spam フィルターで開いて理由を確認し、スパムではないとマークすると、メールと Webhook が送られます。 |
よくある質問
役割が違います。予約注文や Play の事前登録には承認済みのストア掲載情報が必要で、得られるのは連絡先ではなく件数です。ウェイトリストは初日から使え、各人のメールアドレスとプラットフォームがわかり、テスターも招待できます。
ウェイトリストで募りましょう。ベータのチェックボックスとプラットフォームの質問で、Android のスマホを持っていてテストしたい人がわかります。その人たちの Google アカウントをクローズドテストのメールリストに追加し、オプトインリンクを送ります。
直接はできません。Ikiform は登録ごとに署名付き Webhook を送り、上のように、自分でデプロイした短い中継サーバーが App Store Connect API でアドレスを TestFlight のグループに追加します。
いいえ。Ikiform がメールを送るのはあなたとチームで、送信者には送らないので、自動返信や確認メールはありません。Webhook をメールツールに送り、確認メールはそこから送ってください。
いいえ、無料プランはありません。テストは無料で、支払う前に localhost からテスト送信を月 50 件まで送れます。本番運用には、500 件で月 $6 からの Pro か、買い切りで 10,000 件 $49、または 50,000 件 $149 を選べます。クレジットに有効期限はありません。
手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com