# App Store 公開前のモバイルアプリ用ウェイトリストページの作り方

> 使っているスマホを尋ね、iPhone のテスターを TestFlight に送り、Play のクローズドテストを埋める、iOS・Android アプリ向けの公開前ウェイトリストです。

公開日 2026-10-25 · https://ikiform.com/ja/guides/waitlist/mobile-app

アプリのランディングページに、使っているスマホと早期テストを希望するかを尋ねるウェイトリストフォームを置きます。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 人を集める場所がウェイトリストです。
- **ストアには独自の公開前ツールがあります。** ウェイトリストの代わりではなく、併用する価値があります。下の比較を見てください。

|   | App Store の予約注文、Play の事前登録 | 自分のウェイトリスト |
| --- | --- | --- |
| ストアの掲載情報が必要 | はい、承認済みで準備完了のもの | いいえ。ランディングページの初日から使えます |
| 得られるもの | 件数と、リリース時のストアからの通知または自動ダウンロード | 各人のメールアドレス、プラットフォーム、回答 |
| テスターを招待できるか | いいえ | はい、メールで TestFlight や Play のクローズドテストに |
| 制限 | 新しい個人アカウントでは、テストの要件を満たすまで Play の事前登録は使えません | 公開のメールは自分で送ります |

## アプリのウェイトリストのフィールド

メールアドレス欄の意味が変わるので、まずプラットフォームを尋ねます。機種は任意で、どの端末でテストすべきかがわかります。ベータのチェックボックスで、テストしたい人と公開のメールだけほしい人を分けます。

フォーム: App waitlist

- **メールアドレス** (`email`, email, 必須)
- **名** (`first_name`, text)
- **お使いのスマホは？** (`platform`, radio, 必須)
- **機種** (`device`, text)
- **公開前のテストに招待してほしい** (`beta`, checkbox)

`platform` のラジオボタンは必須なので、どの登録も対応可能なリストに入ります。定義をフォームの **Fields** タブに貼り付けてください。

## フォーム

このフォームは、どのランディングページでもプレーンな HTML として動きます。スクリプトが行うのは 2 つの小さなことだけです。訪問者のブラウザーからプラットフォームを事前に選択し、Google アカウントの注意書きを Android のユーザーにだけ表示します。

`index.html`:

```html
<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**（送信後のリダイレクト）に、プラットフォームごとに次に何が起きるかを説明するサンクスページを設定します。フレームワーク版のフォームは[メインのガイド](https://ikiform.com/ja/guides/waitlist.md#form)を参照し、これらのフィールドを追加してください。

## テスターをそれぞれのストアに振り分ける

図: iPhone と Android のテスターが各ストアのベータに届くまで

1. iPhone のユーザーがベータのチェックボックスにチェックを入れると、署名付き Webhook が送られます。
2. 中継サーバーがそれを検証し、App Store Connect API を呼び出してアドレスを TestFlight のグループに追加します。
3. グループで利用できるビルドができると、Apple が TestFlight の招待メールを送ります。
4. Android のテスターも同じ方法で集め、CSV でエクスポートしてプラットフォームで絞り込みます。
5. Google アカウントを Play Console のクローズドテストのメールリストに貼り付けます。
6. メールツールから、テストのオプトインリンクをメールで送ります。

Apple にはテスター用の API がありますが、Google Play のクローズドテストは Play Console か Google グループで管理するので、Android 側は毎週のエクスポートになります。

### iPhone: TestFlight にテスターを追加する

App Store Connect で外部テストグループを作成し、**Users and Access** › **Integrations** で App Manager か Admin のロールを持つ API キーを作成します。次に、Ikiform の `submission.created` Webhook を受け取る中継サーバーを追加します。ここでは Next.js のルートハンドラーで、Apple のトークンの署名に `jose` を使っています。`fetch` があるサーバーならどこでも動きます。

`app/api/testflight/route.ts`:

```ts
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 人がオプトインしている必要があります。

> Ikiform はフォームに入力した人にはメールを送りません。通知メールが届くのはあなたとチームだけなので、自動返信、確認メール、ダブルオプトインはありません。それらは [Webhook](https://ikiform.com/ja/docs/webhooks.md) をきっかけにメールツールから送ってください。TestFlight は独自の招待を送るので、iPhone のテスターには Apple から連絡が届きます。Android のテスターに連絡するのはあなただけです。

## ローンチ日

リスト全体をエクスポートし、`platform` で分けます。それぞれのグループに、ストアのリンクを 1 つだけ載せたメールを 1 通送ります。iPhone を選んだ人に Play のリンクは不要ですし、バッジを 2 つ並べたメールは小さな画面ではタップされにくくなります。`device` を集めていたなら、送る前に、登録者が挙げた機種とクラッシュレポートを照らし合わせておきましょう。

## 動作を確認する

1. フォームの **Allowed domains** に、自分のサイトのドメインと、開発中は `localhost` を追加します。空にしておくと、どこからの送信も受け付けます。
2. スマホでページを開きます。正しいプラットフォームが事前に選択され、Android では Google アカウントの注意書きが表示されます。
3. iPhone のテスターとして送信します。送信データの `platform` は `iphone`、`beta` は `true` になります。
4. **Webhooks** で中継サーバーのエンドポイントを開きます。配信は `succeeded` と表示され、アドレスが TestFlight のグループに載っています。
5. Android のテスターとして送信し、CSV をエクスポートして、`platform` を `android` にするとその行が絞り込まれることを確認します。
6. ハニーポットに値を入れて `_gotcha=bot` で送信します。成功の応答は返りますが、送信データはスパムとして保存され、メールも Webhook も送られません。

## ハマりどころ

| 問題 | 対処法 |
| --- | --- |
| 中継サーバーへの配信が `502` で失敗し、Apple が `401` を返した | トークンが間違っています。キー ID、発行者 ID を確認し、環境変数の秘密鍵の改行が保たれているか確かめてください。 |
| テスターは追加されたが TestFlight のメールが届かない | グループにまだビルドがないか、最初のビルドが Beta App Review 中です。グループでビルドが利用可能になると招待が送られます。 |
| Android のテスターがオプトインリンクを開けない | リストにあるアドレスが、スマホでログインしている Google アカウントと違います。そのアカウントでもう一度登録してもらってください。 |
| `422 validation_failed` | 送信がフォームのフィールド定義に合っていません。`error.fields` に各フィールドと理由が示されます。入力欄の `name` をフィールド ID に合わせてください。 |
| 送信データはダッシュボードにあるのに、メールも Webhook も届かない | スパムとして保存されています。スパムは何も送りません。**Spam** フィルターで開いて理由を確認し、スパムではないとマークすると、メールと Webhook が送られます。 |

## よくある質問

### App Store に予約注文があるなら、ウェイトリストは必要ですか？

役割が違います。予約注文や Play の事前登録には承認済みのストア掲載情報が必要で、得られるのは連絡先ではなく件数です。ウェイトリストは初日から使え、各人のメールアドレスとプラットフォームがわかり、テスターも招待できます。

### Google Play のクローズドテスト要件を満たす 12 人のテスターはどう集めればいいですか？

ウェイトリストで募りましょう。ベータのチェックボックスとプラットフォームの質問で、Android のスマホを持っていてテストしたい人がわかります。その人たちの Google アカウントをクローズドテストのメールリストに追加し、オプトインリンクを送ります。

### Ikiform は TestFlight にテスターを自動で追加できますか？

直接はできません。Ikiform は登録ごとに署名付き Webhook を送り、上のように、自分でデプロイした短い中継サーバーが App Store Connect API でアドレスを TestFlight のグループに追加します。

### Ikiform はフォームを送信した人にメールを送れますか？

いいえ。Ikiform がメールを送るのはあなたとチームで、送信者には送らないので、自動返信や確認メールはありません。Webhook をメールツールに送り、確認メールはそこから送ってください。

### Ikiform は無料ですか？

いいえ、無料プランはありません。テストは無料で、支払う前に localhost からテスト送信を月 50 件まで送れます。本番運用には、500 件で月 $6 からの Pro か、買い切りで 10,000 件 $49、または 50,000 件 $149 を選べます。クレジットに有効期限はありません。

## その他のガイド

- [新しい SaaS のウェイトリスト](https://ikiform.com/ja/guides/waitlist.md): 自分のランディングページにローンチ前のウェイトリストを作ります。フォーム、スパム対策、重複、確認メール、ローンチ日のきれいなエクスポートまで扱います。
- [選考付きのベータ登録](https://ikiform.com/ja/guides/waitlist/beta-signup.md): サーバーが必須を強制する選考質問付きのベータ応募フォームと、応募者を採点してリストから各コホートを選ぶスクリプトを紹介します。
- [Product Hunt ローンチリスト](https://ikiform.com/ja/guides/waitlist/product-hunt.md): Product Hunt の数週間前からローンチリストを集め、登録をチャネルごとにタグ付けし、太平洋時間のリセットに合わせてローンチ日のメールを 2 回に分けて送ります。
- [プレーンな HTML のウェイトリスト](https://ikiform.com/ja/guides/waitlist/html.md): ビルド不要でプレーンな HTML だけのウェイトリストページ。JavaScript がオフでも動き、読み込めばその場でお礼を表示し、必要なときはフォールバックします。
- [Next.js のウェイトリスト](https://ikiform.com/ja/guides/waitlist/nextjs.md): Next.js App Router のウェイトリスト。シークレットキーで登録を転送するサーバーアクション、useActionState、楽観的なサンクス表示、訪問者ごとの制限を扱います。
- [Framer のウェイトリスト](https://ikiform.com/ja/guides/waitlist/framer.md): Framer でウェイトリストの登録を集める 2 つの方法。Ikiform への Webhook を使う Framer のフォームか、訪問者ごとの制限とスパムチェックが残るコードコンポーネントです。
