> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 인앱 메시지용 HTML 템플릿

> OneSignal 인앱 메시지에서 사용할 수 있는 복사/붙여넣기 HTML 템플릿, 필요한 설정 및 일반적인 문제.

이러한 복사/붙여넣기 HTML 템플릿을 사용하여 OneSignal의 맞춤형 인앱 메시지를 더 빠르게 구축하세요.

저희의 인앱 메시지 HTML 에디터를 사용하면 HTML, CSS, JavaScript를 사용하여 인앱 메시지 레이아웃과 동작을 완전히 제어할 수 있습니다. 에디터에는 **내장 템플릿이 포함되지 않지만**, 이 페이지에서는 에디터에 붙여넣고 사용자 지정할 수 있는 **바로 사용 가능한 예제**를 제공합니다.

<Note>
  이러한 템플릿은 인앱 메시지 웹뷰 내에서 실행됩니다. 메시지를 닫고, URL을 열고, 사용자를 태그하고, 클릭을 캐표하려면 [인앱 메시지 JS API](./in-app-message-api)를 사용하세요.
</Note>

## 전제 조건

시작하기 전에 다음을 검토하는 것이 좋습니다:

* [인앱 메시지 개요](./in-app-messages-setup) 페이지.
* [HTML 에디터로 인앱 메시지 디자인하기](./design-your-in-app-message-with-html) 페이지.

<Warning>
  템플릿 코드에 비밀 정보(API 키, 토큰)를 넣지 마세요. 모든 인앱 메시지 입력을 신뢰할 수 없는 것으로 취급하고 앱 또는 백엔드에서 유효성을 검사하세요.
</Warning>

## 템플릿 사용 방법

1. OneSignal에서 **메시지 > 인앱 > 새 인앱**으로 이동합니다.
2. **HTML 에디터**를 선택합니다.
3. 아래에서 템플릿을 찾습니다.
4. 코드 블록에서 전체 HTML을 복사하여 에디터에 붙여넣습니다.
5. 자리 표시자(URL, 엔드포인트, 날짜, 콘텐츠)를 업데이트합니다.
6. 실제 기기에서 테스트한 후 게시합니다.

## 사용 가능한 템플릿

<Card title="이메일 수집 양식" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/email-form.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=d74293c6b7c0c2ed0694078d41a8c1c8" href="#email-form" width="1258" height="708" data-path="images/html-iam/email-form.png">
  사용자의 이메일을 요청하고 클릭 이름을 통해 앱에 전송합니다.
</Card>

<Card title="전화번호 수집 양식" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/sms-form.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=d5444750f75c638f9aacc4cadc8ce8e3" href="#sms-form" width="1251" height="704" data-path="images/html-iam/sms-form.png">
  SMS 전송에 대한 동의를 요청하고 얻습니다. E.164 형식의 전화번호를 포함하고 클릭 이름을 통해 앱에 전송합니다.
</Card>

<Card title="체크리스트 설문조사" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/checklist-survey.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=e35945ecfefabdb013053aa814c3618d" href="#checklist-survey" width="574" height="322" data-path="images/html-iam/checklist-survey.png">
  백엔드에 보내거나 태그로 변환할 수 있는 다중 선택 설문조사.
</Card>

<Card title="카운트다운" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/count_down.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=bcc786162ca0f4837c244f0d7f03097d" href="#countdown" width="1820" height="1024" data-path="images/html-iam/count_down.png">
  시간 제한 프로모션용 카운트다운 타이머.
</Card>

<Card title="프로모 휠" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/promo-wheel.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=dfd0aa50f5981774267644acb17da817" href="#promo-wheel" width="574" height="322" data-path="images/html-iam/promo-wheel.png">
  돌리기-투-윈 프로모 경험(프로모 처리 사용자 지정).
</Card>

<Card title="퀴즈 모달" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/quiz_modal.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=66399edf105d0799bdfab78412a60744" href="#quiz-modal" width="1820" height="1024" data-path="images/html-iam/quiz_modal.png">
  사용자에게 점수로 태그를 지정할 수 있는 퀴즈 경험.
</Card>

<Card title="평점 설문조사" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/ranking-survey.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=42cfa0b554dbfe1f59f61c47306f8460" href="#ranking-survey" width="574" height="322" data-path="images/html-iam/ranking-survey.png">
  1–5점 평점 설문조사(엔드포인트로 전송 또는 사용자 태그).
</Card>

<Card title="오디오/비디오 플레이어" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/ui-ui.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=cf9bdf607dda82687faa1c874fddebb4" href="#audio/video-player" width="574" height="322" data-path="images/html-iam/ui-ui.png">
  직접 MP3 파일용 간단한 오디오 미리보기 UI.
</Card>

<Card title="세로 스와이프" img="https://mintcdn.com/onesignal/gVwen8HnVQfsFC-e/images/html-iam/vertical-swiping.png?fit=max&auto=format&n=gVwen8HnVQfsFC-e&q=85&s=3cb4a092cf2e4bb14bee214a0c22c58b" href="#vertical-swiping" width="574" height="322" data-path="images/html-iam/vertical-swiping.png">
  다중 슬라이드 세로 스와이프 온보딩 또는 기능 투어.
</Card>

***

### 이메일 양식

인얁 메시지를 통해 이메일 [구독](./subscriptions)을 수집합니다.

이 양식의 작동 방식:

1. 사용자가 이메일 주소를 입력하고 동의 체크박스를 체크합니다.
2. 제출 시 OneSignal의 Create User API가 호출되어 앱에서 이메일 구독이 생성됩니다.
3. 또한 템플릿이 `OneSignalIamApi.addClickName(e, email)`을 호출하여 이메일 주소를 SDK의 인앱 메시지 클릭 리스너에 전달합니다.
4. 앱 내에서 인얁 메시지 클릭 리스너를 추가하여 클릭 이름을 읽고 이메일을 SDK의 `addEmail` 메서드에 전달할 수 있습니다.

2단계와 4단계 모두 이메일 구독 생성을 포함한다는 것을 알 수 있습니다.

* 2단계는 앱에 직접 코드를 추가할 필요가 없지만 `login` 메서드를 호출한 경우 사용자에게 이메일 구독을 추가하지도 않습니다.
* 4단계는 추가 코드(인얁 메시지 클릭 리스너)가 필요하지만 `login` 메서드를 호출한 경우에도 사용자에게 이메일 구독을 추가합니다.

<Accordion title="이메일 양식 HTML 코드">
  \*\*[설정 > 키 및 ID](./keys-and-ids)에서 찾은 OneSignal 앱 ID로 `YOUR_APP_ID`를 교체하세요.

  ```html theme={null}
  <!DOCTYPE html>
  <html lang="ko">
  <head>
      <meta charset="UTF-8">
      <!-- iOS 입력 포커스 시 확대 방지 -->
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
      <style>
          /* ===== 리셋 ===== */
          * {
              box-sizing: border-box;
              margin: 0;
              padding: 0;
          }
          
          /* ===== 기본 ===== */
          body {
              font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
              background: transparent;
              display: flex;
              justify-content: center;
              align-items: center;
              min-height: 100vh;
              padding: 20px;
          }
          
          /* ===== 카드 ===== */
          .container {
              position: relative;
              background: #ffffff;
              border-radius: 16px;
              padding: 32px 24px;
              max-width: 340px;
              width: 100%;
              box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
              text-align: center;
          }
          
          /* ===== 닫기 버튼 ===== */
          .close-btn {
              position: absolute;
              top: 12px;
              right: 12px;
              background: none;
              border: none;
              font-size: 24px;
              color: #999;
              cursor: pointer;
              padding: 4px 8px;
              line-height: 1;
          }
          
          .close-btn:hover {
              color: #333;
          }
          
          /* ===== 타이포그래피 ===== */
          h1 {
              font-size: 22px;
              font-weight: 600;
              color: #333;
              margin-bottom: 8px;
          }
          
          p {
              font-size: 14px;
              color: #666;
              margin-bottom: 24px;
              line-height: 1.5;
          }
          
          /* ===== 이메일 입력 ===== */
          .email-input {
              width: 100%;
              padding: 14px 16px;
              font-size: 16px; /* iOS 자동 확대 방지를 위한 16px */
              border: 2px solid #e0e0e0;
              border-radius: 10px;
              margin-bottom: 16px;
              outline: none;
              transition: border-color 0.2s;
              touch-action: manipulation;
          }
          
          .email-input:focus {
              border-color: #007AFF;
          }
          
          .email-input::placeholder {
              color: #aaa;
          }
          
          /* ===== 동의 체크박스 ===== */
          .consent-wrapper {
              display: flex;
              align-items: flex-start;
              gap: 10px;
              text-align: left;
              margin-bottom: 16px;
          }
          
          .consent-wrapper input[type="checkbox"] {
              width: 18px;
              height: 18px;
              margin-top: 2px;
              cursor: pointer;
              flex-shrink: 0;
          }
          
          .consent-wrapper label {
              font-size: 13px;
              color: #666;
              line-height: 1.4;
              cursor: pointer;
          }
          
          /* ===== 제출 버튼 ===== */
          .submit-btn {
              width: 100%;
              padding: 14px 24px;
              font-size: 16px;
              font-weight: 600;
              color: #fff;
              background: #007AFF;
              border: none;
              border-radius: 10px;
              cursor: pointer;
              transition: background 0.2s, opacity 0.2s;
          }
          
          .submit-btn:hover {
              background: #0056b3;
          }
          
          .submit-btn:disabled {
              background: #ccc;
              cursor: not-allowed;
              opacity: 0.7;
          }
          
          /* ===== 상태 메시지 ===== */
          .error-msg,
          .success-msg {
              font-size: 12px;
              margin-top: -12px;
              margin-bottom: 12px;
              display: none;
          }
          
          .error-msg {
              color: #e53935;
          }

          .success-msg {
              color: #4CAF50;
              font-size: 14px;
          }
          
          /* ===== 로딩 상태 ===== */
          .loading {
              pointer-events: none;
              opacity: 0.7;
          }
      </style>
  </head>
  <body>
      <div class="container">
          <!-- 닫기 버튼 -->
          <button id="close-btn" class="close-btn" data-onesignal-unique-label="close-button">×</button>
          
          <!-- 헤더 -->
          <h1>연결을 유지하세요!</h1>
          <p>이메일을 입력하여 업데이트와 독점 오퍼를 받아보세요. 언제든 구독을 취소할 수 있습니다!</p>
          
          <!-- 이메일 입력 -->
          <input 
              type="email" 
              id="email-input" 
              class="email-input" 
              placeholder="이메일을 입력하세요" 
              data-onesignal-unique-label="email-input" 
              autocomplete="email" 
              autocapitalize="off"
          >
          
          <!-- 상태 메시지 -->
          <p id="error-msg" class="error-msg">유효한 이메일 주소를 입력하세요</p>
          <p id="success-msg" class="success-msg">구독해 주셔서 감사합니다!</p>
          
          <!-- 동의 체크박스 -->
          <div class="consent-wrapper">
              <input type="checkbox" id="consent-checkbox" name="consent">
              <label for="consent-checkbox">마케팅 이메일 수신에 동의합니다</label>
          </div>
          
          <!-- 제출 버튼 -->
          <button id="submit-btn" class="submit-btn" data-onesignal-unique-label="submit-email" disabled>
              구독하기
          </button>
      </div>

      <script>
          document.addEventListener("DOMContentLoaded", function() {
              
              // ===== DOM 참조 =====
              var emailInput = document.getElementById("email-input");
              var submitBtn = document.getElementById("submit-btn");
              var closeBtn = document.getElementById("close-btn");
              var errorMsg = document.getElementById("error-msg");
              var successMsg = document.getElementById("success-msg");
              var consentCheckbox = document.getElementById("consent-checkbox");
              
              // ===== 도움 함수 =====
              
              // 이메일 형식 유효성 검사
              function isValidEmail(email) {
                  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
              }
              
              // 이메일이 유효하고 동의가 체크된 경우에만 제출 버튼 활성화
              function updateSubmitState() {
                  var email = emailInput.value.trim();
                  submitBtn.disabled = !(isValidEmail(email) && consentCheckbox.checked);
              }
              
              // OneSignal API를 통해 이메일 구독 생성
              async function createOneSignalUser(email) {
                  // ⚠️ OneSignal 앱 ID로 교체
                  var appId = "YOUR_APP_ID";
                  var url = "https://api.onesignal.com/apps/" + appId + "/users";
                  
                  var payload = {
                      properties: {
                          tags: { email_created_from: "iam" },
                          language: "ko"
                      },
                      subscriptions: [{
                          type: "Email",
                          token: email,
                          enabled: true
                      }]
                  };
                  
                  var response = await fetch(url, {
                      method: "POST",
                      headers: { "Content-Type": "application/json" },
                      body: JSON.stringify(payload)
                  });
                  
                  if (!response.ok) throw new Error("API 요청이 실패했습니다");
                  return response.json();
              }
              
              // ===== 이벤트 리스너 =====
              
              // 닫기 버튼 - IAM 닫기
              closeBtn.addEventListener("click", function(e) {
                  OneSignalIamApi.close(e);
              });
              
              // 체크박스 - 버튼 상태 업데이트
              consentCheckbox.addEventListener("change", updateSubmitState);
              
              // 이메일 입력 - 버튼 상태 업데이트 및 오류 숨기기
              emailInput.addEventListener("input", function() {
                  errorMsg.style.display = "none";
                  updateSubmitState();
              });
              
              // 이메일 입력 - Enter 키로 제출
              emailInput.addEventListener("keypress", function(e) {
                  if (e.key === "Enter" && !submitBtn.disabled) {
                      submitBtn.click();
                  }
              });
              
              // 제출 버튼 - 구독 처리
              submitBtn.addEventListener("click", async function(e) {
                  var email = emailInput.value.trim();
                  
                  if (!isValidEmail(email) || !consentCheckbox.checked) {
                      errorMsg.textContent = "유효한 이메일 주소를 입력하세요";
                      errorMsg.style.display = "block";
                      return;
                  }
                  
                  // OneSignal 클릭 핸들러에 이메일 전달(동기적으로 호출해야 함)
                  OneSignalIamApi.addClickName(e, email);
                  
                  // 로딩 상태 표시
                  errorMsg.style.display = "none";
                  submitBtn.textContent = "구독 중...";
                  submitBtn.classList.add("loading");
                  
                  try {
                      await createOneSignalUser(email);
                      
                      // 성공 - 메시지 표시 및 자동 닫기
                      successMsg.style.display = "block";
                      submitBtn.textContent = "구독 완료!";
                      
                      setTimeout(function() {
                          closeBtn.click();
                      }, 1500);
                      
                  } catch (error) {
                      // 오류 - 재설정 및 메시지 표시
                      submitBtn.textContent = "구독하기";
                      submitBtn.classList.remove("loading");
                      errorMsg.textContent = "문제가 발생했습니다. 다시 시도해 주세요.";
                      errorMsg.style.display = "block";
                  }
              });
          });
      </script>
  </body>
  </html>
  ```
</Accordion>

**4단계에 필요한 사항:**

1. HTML 제출 핸들러에서 [addClickName](./in-app-message-api#click-name) 호출을 유지하세요.
2. SDK의 [인앱 메시지 클릭 리스너](./mobile-sdk-reference#addclicklistener-in-app)로 입력을 읽어오세요
3. 클릭 이름이 이메일처럼 보일 때 인앱 메시지 클릭 리스너 내에서 [addEmail](./mobile-sdk-reference#addemail-,-removeemail) 메서드를 호출하세요.

**인앱 메시지 클릭 리스너와 addEmail 메서드를 사용한 예제:**

```swift theme={null}
// HTML 인앱 메시지에서 이메일과 전화를 캡처하는 인앱 메시지 클릭 핸들러 예제
class InAppMessageClickHandler: NSObject, OSInAppMessageClickListener {
    func onClick(event: OSInAppMessageClickEvent) {
        // 이벤트에서 클릭 이름(actionId) 가져오기
        let clickName = event.result.actionId
        print("인앱 메시지 클릭, actionId: \(clickName ?? "nil")")
        
        guard let value = clickName else { return }
        
        // 클릭 이름이 이메일 주소처럼 보이는지 확인
        if value.contains("@") && value.contains(".") {
            OneSignal.User.addEmail(value)
            print("OneSignal에 이메일 추가: \(value)")
        }
        // 클릭 이름이 E.164 형식의 전화번호처럼 보이는지 확인(+1XXXXXXXXXX)
        else if value.hasPrefix("+") && value.count >= 11 {
            OneSignal.User.addSms(value)
            print("OneSignal에 SMS 추가: \(value)")
        }
    }
}
```

***

### SMS 양식

인앱 메시지를 통해 SMS [구독](./subscriptions)을 수집합니다.

이 양식의 작동 방식:

1. 사용자가 국가 코드를 선택하고 10자리 번호를 입력한 후 동의 체크박스를 체크합니다.
2. 제출 시 OneSignal의 Create User API가 호출되어 앱에서 SMS 구독이 생성됩니다.
3. 또한 템플릿이 `OneSignalIamApi.addClickName(e, e164Phone)`을 호출하여 전화번호를 SDK의 인앱 메시지 클릭 리스너에 전달합니다.
4. 앱 내에서 인앱 메시지 클릭 리스너를 추가하여 클릭 이름을 읽고 전화번호를 SDK의 `addSms` 메서드에 전달할 수 있습니다.

2단계와 4단계 모두 SMS 구독 생성을 포함한다는 것을 알 수 있습니다.

* 2단계는 앱에 직접 코드를 추가할 필요가 없지만 `login` 메서드를 호출한 경우 사용자에게 SMS 구독을 추가하지도 않습니다.
* 4단계는 추가 코드(인앱 메시지 클릭 리스너)가 필요하지만 `login` 메서드를 호출한 경우에도 사용자에게 SMS 구독을 추가합니다.

<Accordion title="SMS 양식 HTML 코드">
  \*\*[설정 > 키 및 ID](./keys-and-ids)에서 찾은 OneSignal 앱 ID로 `YOUR_APP_ID`를 교체하세요.

  ```html theme={null}
  <!DOCTYPE html>
  <html lang="ko">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
      <style>
          /* 스타일은 이메일 양식과 동일하나 전화 입력용으로 조정 */
          * { box-sizing: border-box; margin: 0; padding: 0; }
          body {
              font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
              background: transparent;
              display: flex;
              justify-content: center;
              align-items: center;
              min-height: 100vh;
              padding: 20px;
          }
          .container {
              position: relative;
              background: #ffffff;
              border-radius: 16px;
              padding: 32px 24px;
              max-width: 340px;
              width: 100%;
              box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
              text-align: center;
          }
          /* 기타 스타일... */
      </style>
  </head>
  <body>
      <div class="container">
          <button id="close-btn" class="close-btn">×</button>
          <h1>SMS로 최신 소식을 받아보세요!</h1>
          <p>전화번호를 입력하여 중요한 업데이트를 SMS로 받아보세요.</p>
          
          <div class="phone-input-wrapper">
              <select id="country-select" class="country-select">
                  <option value="+1">🇺🇸 +1</option>
                  <option value="+82">🇰🇷 +82</option>
                  <!-- 기타 국가 코드... -->
              </select>
              <input type="tel" id="phone-input" class="phone-input" placeholder="1234567890" maxlength="10">
          </div>
          
          <div class="consent-wrapper">
              <input type="checkbox" id="consent-checkbox">
              <label for="consent-checkbox">SMS 마케팅 메시지 수신에 동의합니다</label>
          </div>
          
          <button id="submit-btn" class="submit-btn" disabled>구독하기</button>
      </div>
      
      <script>
          // JavaScript 로직(이메일 양식과 동일하나 전화번호 처리용으로 조정)
          // 자세한 구현은 이메일 양식과 동일한 패턴
      </script>
  </body>
  </html>
  ```
</Accordion>

### 기타 템플릿

위의 이메일 및 SMS 양식 외에도 다음 템플릿들도 사용할 수 있습니다:

* **체크리스트 설문조사**: 다중 선택 설문조사
* **카운트다운**: 시간 제한 프로모션
* **프로모 휠**: 돌리기-투-윈 경험
* **퀴즈 모달**: 점수 기반 퀴즈
* **평점 설문조사**: 1–5점 평가
* **오디오/비디오 플레이어**: 미디어 미리보기
* **세로 스와이프**: 다중 슬라이드 투어

각 템플릿의 상세한 HTML 코드와 구현 단계는 위의 카드 링크에서 각 섹션을 참조하세요.

***

***
