새 SaaS용 대기자 명단6분 분량
App Store 출시 전 모바일 앱 대기자 명단 페이지 만드는 방법
iOS나 Android 앱의 출시 전 대기자 명단으로, 사용하는 휴대폰을 묻고 iPhone 테스터는 TestFlight로 보내고 Play 비공개 테스트를 채웁니다.
앱 랜딩 페이지에 사용하는 휴대폰과 미리 테스트하고 싶은지를 묻는 대기자 명단 폼을 두세요. iPhone 테스터는 웹훅과 App Store Connect API로 TestFlight 그룹에 넣고, Android 테스터는 내보낸 파일로 Google Play 비공개 테스트에 넣으세요. 출시일에는 그룹마다 각자의 스토어 링크를 이메일로 보내세요.
앱이 스토어에 올라가기 전에는 사람들을 보낼 설치 버튼이 없습니다. 내 랜딩 페이지의 대기자 명단은 그때까지 관심을 붙잡아 두고, 스토어가 해 주지 않는 두 번째 일도 합니다. 출시 전에 필요한 테스터를 찾아 줍니다.
모바일 앱에서 다른 점
- 스토어 둘, 목록 둘. 출시 이메일은 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로 작동합니다. 스크립트는 두 가지 작은 일을 합니다. 방문자의 브라우저를 보고 플랫폼을 미리 선택하고, 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 사용자가 서명된 웹훅을 발생시킵니다.
- 릴레이가 이를 검증하고 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 웹훅을 받는 릴레이를 추가하세요. 이 릴레이는 Next.js 라우트 핸들러이며 jose로 Apple 토큰에 서명합니다. 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에 복사하세요. 워크스페이스에는 엔드포인트를 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으로 나누세요. 각 절반에 스토어 링크 하나가 담긴 이메일을 한 통씩 보내세요. iPhone을 고른 사람에게 Play 링크는 필요 없고, 배지 두 개가 있는 이메일 한 통은 작은 화면에서 탭을 놓칩니다. device를 모았다면 보내기 전에 사람들이 적은 모델과 크래시 보고서를 대조해 보세요.
작동 확인하기
- 폼의 Allowed domains에 사이트 도메인을 추가하고, 개발 중에는
localhost도 추가하세요. 비워 두면 어디서 온 POST든 받습니다. - 휴대폰에서 페이지를 여세요. 맞는 플랫폼이 미리 선택되어 있고, Android에서는 Google 계정 안내가 표시됩니다.
- iPhone 테스터로 제출하세요. 제출에
platform은iphone,beta는true로 표시됩니다. - Webhooks에서 릴레이 엔드포인트를 여세요. 전달이
succeeded로 표시되고, 주소가 TestFlight 그룹에 있습니다. - Android 테스터로 제출하고 CSV를 내보낸 뒤,
platform을android로 필터링하면 그 행이 걸러지는지 확인하세요. - 허니팟을 채워서
_gotcha=bot으로 POST해 보세요. 여전히 성공 응답을 받지만, 제출은 스팸으로 저장되고 이메일이나 웹훅을 보내지 않습니다.
주의할 점
| 문제 | 해결 방법 |
|---|---|
릴레이 전달이 502로 실패하고 Apple이 401로 응답함 | 토큰이 잘못되었습니다. 키 ID와 발급자 ID를 확인하고, 개인 키가 환경 변수 안에서 줄바꿈을 유지하는지 확인하세요. |
| 테스터를 추가했는데 TestFlight 이메일이 오지 않음 | 그룹에 아직 빌드가 없거나 첫 빌드가 아직 Beta App Review 중입니다. 그룹에서 빌드를 쓸 수 있게 되면 초대가 나갑니다. |
| Android 테스터가 참여 링크를 열 수 없음 | 목록에 있는 주소가 휴대폰에 로그인된 Google 계정이 아닙니다. 그 계정으로 다시 가입해 달라고 하세요. |
422 validation_failed | POST가 폼의 필드 정의와 맞지 않습니다. error.fields에 각 필드와 이유가 나옵니다. 입력의 name을 필드 ID와 맞추세요. |
| 제출은 대시보드에 있는데 이메일이나 웹훅이 오지 않음 | 스팸으로 저장된 것입니다. 스팸은 아무것도 보내지 않습니다. Spam 필터에서 열어 이유를 확인하고, 스팸 아님으로 표시하면 이메일과 웹훅이 전송됩니다. |
질문
둘은 하는 일이 다릅니다. 사전 주문과 Play 사전 등록은 승인된 스토어 등록 정보가 필요하고, 연락처가 아니라 숫자만 줍니다. 대기자 명단은 첫날부터 작동하고, 사람마다 이메일과 플랫폼을 알려 주며, 테스터를 초대할 수 있게 해 줍니다.
대기자 명단에서 모집하세요. 베타 체크박스와 플랫폼 질문이 있으면 누가 Android 휴대폰을 갖고 있고 테스트하고 싶은지 알 수 있습니다. 그들의 Google 계정을 비공개 테스트 이메일 목록에 넣고 참여 링크를 보내세요.
직접은 안 됩니다. Ikiform은 가입마다 서명된 웹훅을 보내고, 위에서 보여 준 것처럼 직접 배포한 짧은 릴레이가 App Store Connect API로 주소를 TestFlight 그룹에 추가합니다.
아니요. Ikiform은 제출자가 아니라 여러분과 팀에게 이메일을 보내므로 자동 응답이나 확인 이메일이 없습니다. 웹훅을 이메일 도구로 보내고 그곳에서 확인 이메일을 보내세요.
아니요, 무료 플랜은 없습니다. 테스트는 무료입니다. 결제 전에 localhost에서 매달 테스트 제출 50건을 보낼 수 있습니다. 실제 운영하려면 제출 500건에 월 $6부터인 Pro를 쓰거나, 한 번 결제로 제출 10,000건에 $49 또는 50,000건에 $149를 낼 수 있으며, 크레딧은 만료되지 않습니다.
막히는 단계가 있거나 내 상황에 맞는 가이드가 필요하다면 이메일을 보내세요: hello@ikiform.com.