Push API

김동현·2026년 3월 21일

Push API

Baseline: 널리 사용 가능

✅ Chrome ✅ Edge ✅ Firefox ✅ Safari

이 기능은 잘 정립되어 있고 많은 디바이스와 브라우저 버전에서 동작해요. 2023년 3월부터 여러 브라우저에서 사용 가능했어요.


📝 참고: 이 기능은 Web Workers에서도 사용할 수 있어요.

Push API는 웹 애플리케이션이 서버로부터 푸시된 메시지를 받을 수 있는 능력을 제공해요. 웹 앱이 포그라운드에 있지 않거나, 심지어 현재 사용자 에이전트에 로드되어 있지 않을 때도 말이죠. 이를 통해 개발자들은 동의한 사용자들에게 비동기 알림과 업데이트를 전달할 수 있어서, 시의적절한 새로운 콘텐츠로 더 나은 참여를 이끌어낼 수 있어요.


💡 강사 팁

여러분, Push API는 현대 웹 애플리케이션의 필수 기능 중 하나예요! 🔔

Push API가 뭔가요?

쉽게 말해서, 여러분이 자주 보는 "새 메시지가 도착했습니다", "할인 이벤트 시작!" 같은 브라우저 알림이 바로 이 Push API를 사용한 거예요.

핵심은 이거예요:

  • 브라우저를 닫아도 알림을 받을 수 있어요
  • 다른 탭을 보고 있어도 알림이 와요
  • 심지어 해당 사이트를 안 보고 있어도 서버가 메시지를 푸시할 수 있어요

실무에서 어떻게 쓰이나요?

제가 실제로 구현해본 사례들을 공유할게요:

1. 메신저/채팅 앱

// Service Worker에서 푸시 메시지 받기
self.addEventListener('push', event => {
  const data = event.data.json();
  
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.message,
      icon: '/icon.png',
      badge: '/badge.png'
    })
  );
});

2. 전자상거래 사이트

  • 장바구니에 담은 상품 할인 시작 알림
  • 품절됐던 상품 재입고 알림
  • 주문 배송 상태 업데이트

3. 뉴스/미디어 사이트

  • 속보 알림
  • 좋아하는 작가의 새 글 발행 알림

중요한 개념들

Service Worker가 필수예요!
Push API는 Service Worker와 함께 동작해요. 왜냐하면 브라우저가 꺼져있어도 백그라운드에서 알림을 받아야 하니까요.

사용자 동의가 필수!

// 푸시 알림 권한 요청
Notification.requestPermission().then(permission => {
  if (permission === 'granted') {
    console.log('알림 권한 획득!');
    // 푸시 구독 시작
  }
});

⚠️ 절대 무단으로 알림 권한 요청하지 마세요! 사용자가 사이트 들어오자마자 알림 권한 팝업 뜨면 진짜 짜증나거든요. 저도 그런 사이트는 바로 닫아버려요. 😤

실전 팁

1. 적절한 타이밍에 권한 요청하기

// ❌ 나쁜 예: 페이지 로드되자마자
window.addEventListener('load', () => {
  Notification.requestPermission(); // 너무 이르다!
});

// ✅ 좋은 예: 사용자가 "알림 받기" 버튼 클릭했을 때
subscribeButton.addEventListener('click', async () => {
  const permission = await Notification.requestPermission();
  if (permission === 'granted') {
    subscribeToPush();
  }
});

2. 서버 설정도 중요해요
Push API는 클라이언트만으로는 안 돼요. 서버에서 푸시 메시지를 보내는 로직도 필요해요. 저는 주로 Firebase Cloud Messaging(FCM)이나 웹푸시 라이브러리를 사용해요.

3. HTTPS는 필수!
Push API는 보안 컨텍스트에서만 동작해요. HTTP에서는 절대 안 돼요! (localhost는 예외)

4. 배터리 소모 고려하기
푸시 알림을 너무 자주 보내면 사용자 기기의 배터리가 빨리 닳아요. 중요한 알림만 보내세요!

흔한 실수들

알림 폭탄 던지기
하루에 수십 개 알림 보내면 사용자가 알림 차단하거나 사이트 안 와요.

알림 내용이 불명확
"업데이트가 있습니다" 같은 모호한 메시지는 클릭률이 낮아요. 구체적으로 작성하세요!

좋은 예시

self.registration.showNotification('신상품 20% 할인!', {
  body: '장바구니에 담은 나이키 운동화가 지금 할인 중이에요',
  icon: '/product-image.jpg',
  data: { url: '/cart' }, // 클릭 시 이동할 URL
  actions: [
    { action: 'view', title: '보러가기' },
    { action: 'dismiss', title: '닫기' }
  ]
});

브라우저 호환성

2023년 3월부터 주요 브라우저에서 다 지원해요! Safari도 이제 지원합니다. 🎉

하지만 iOS Safari는 PWA로 설치한 경우에만 Push API가 동작해요. 이 부분 꼭 테스트해보세요!

Push concepts and usage

⚠️ 경고:
PushManager 구독을 구현할 때, 앱에서 CSRF/XSRF 문제로부터 보호하는 것이 매우 중요해요. 더 많은 정보는 다음 문서들을 참고하세요:

앱이 푸시 메시지를 받으려면, 활성화된 service worker가 있어야 해요. 서비스 워커가 활성화되면, PushManager.subscribe()를 사용하여 푸시 알림을 구독할 수 있어요.

결과로 나오는 PushSubscription에는 애플리케이션이 푸시 메시지를 보내는 데 필요한 모든 정보가 포함되어 있어요: 엔드포인트와 데이터를 보내는 데 필요한 암호화 키요.

서비스 워커는 들어오는 푸시 메시지를 처리하기 위해 필요에 따라 시작될 거예요. 푸시 메시지는 onpush 이벤트 핸들러로 전달돼요. 이를 통해 앱은 푸시 메시지가 수신되는 것에 반응할 수 있어요. 예를 들어, 알림을 표시하는 것(ServiceWorkerRegistration.showNotification()을 사용해서요)처럼요.

각 구독은 서비스 워커에 고유해요. 구독의 엔드포인트는 고유한 capability URL이에요: 엔드포인트에 대한 지식만으로도 여러분의 애플리케이션에 메시지를 보내기에 충분해요. 따라서 엔드포인트 URL은 비밀로 유지해야 해요. 그렇지 않으면 다른 애플리케이션들이 여러분의 애플리케이션에 푸시 메시지를 보낼 수 있을 거예요.

푸시 메시지를 전달하기 위해 서비스 워커를 활성화하면 리소스 사용량이 증가할 수 있어요, 특히 배터리 사용량이요. 브라우저마다 이를 처리하는 방식이 다르고, 현재 표준화된 메커니즘은 없어요. Firefox는 애플리케이션에 보낼 수 있는 푸시 메시지의 제한된 수(쿼터)를 허용하지만, 알림을 생성하는 푸시 메시지는 이 제한에서 제외돼요. 이 제한은 사이트를 방문할 때마다 갱신돼요. Chrome에서는 제한이 없어요.


Interfaces

PushEvent
: 푸시 액션을 나타내며, ServiceWorkerglobal scope로 전송돼요. 애플리케이션에서 PushSubscription으로 보낸 정보를 포함하고 있어요.

PushManager
: 서드파티 서버로부터 알림을 받는 방법과, 푸시 알림을 위한 URL을 요청하는 방법을 제공해요.

PushMessageData
: 서버가 보낸 푸시 데이터에 대한 접근을 제공하고, 수신된 데이터를 조작하는 메서드들을 포함해요.

PushSubscription
: 구독의 URL 엔드포인트를 제공하고, 푸시 서비스로부터 구독 해지를 허용해요.

PushSubscriptionOptions
: 푸시 구독과 관련된 옵션들을 나타내요.


Service worker additions

다음은 Push 메시지 사용을 위한 진입점을 제공하기 위해 Push API 스펙에서 명시된 Service Worker API에 대한 추가 사항들이에요. 이것들은 또한 푸시 및 구독 변경 이벤트를 모니터링하고 응답해요.

ServiceWorkerRegistration.pushManager Read only
: 구독하기, 활성 구독 가져오기, 푸시 권한 상태 접근을 포함한 푸시 구독 관리를 위한 PushManager 인터페이스에 대한 참조를 반환해요. 이것이 Push 메시징을 사용하기 위한 진입점이에요.

onpush
: push 이벤트가 발생할 때마다 실행되는 이벤트 핸들러예요. 즉, 서버 푸시 메시지가 수신될 때마다요.

onpushsubscriptionchange
: pushsubscriptionchange 이벤트가 발생할 때마다 실행되는 이벤트 핸들러예요. 예를 들어, 푸시 구독이 무효화되었거나 무효화되려고 할 때요 (예: 푸시 서비스가 만료 시간을 설정했을 때).


Examples

Mozilla의 ServiceWorker Cookbook에 유용한 푸시 예제들이 많이 있어요.


Specifications

Specification
Push API # pushevent-interface
Push API # pushmessagedata-interface

Browser compatibility

브라우저 호환성 표 보기


💡 강사 팁

CSRF/XSRF 보안, 정말 중요해요!

문서에서 경고하는 CSRF(Cross-Site Request Forgery) 공격, 간과하시면 안 돼요! 😱

제가 실제로 본 사례를 들려드릴게요. 어떤 서비스에서 푸시 구독 엔드포인트를 제대로 보호하지 않았더니, 악의적인 사이트에서 해당 엔드포인트로 요청을 보내 사용자 몰래 구독을 해지시키거나 스팸 알림을 보낸 케이스가 있었어요.

// ✅ CSRF 토큰을 함께 보내세요
async function subscribeUser() {
  const registration = await navigator.serviceWorker.ready;
  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
  });
  
  // 서버에 구독 정보 전송할 때 CSRF 토큰 포함!
  await fetch('/api/push/subscribe', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-CSRF-Token': getCsrfToken() // 여기!
    },
    body: JSON.stringify(subscription)
  });
}

엔드포인트 URL은 비밀번호처럼!

문서에서 강조한 것처럼, 엔드포인트 URL을 알면 누구나 여러분 앱에 메시지를 보낼 수 있어요. 절대 프론트엔드 코드에 노출하거나 로그에 찍지 마세요!

// ❌ 절대 이러지 마세요
console.log('Subscription endpoint:', subscription.endpoint);

// ✅ 서버에만 안전하게 전송
await sendToServer(subscription); // HTTPS 필수!

실전 구현 흐름

Push API 구현의 전체 흐름을 정리해드릴게요:

1. 사용자 동의 획득 (Notification.requestPermission)
         ↓
2. Service Worker 등록 (navigator.serviceWorker.register)
         ↓
3. Push 구독 생성 (pushManager.subscribe)
         ↓
4. 구독 정보를 서버에 저장 (endpoint, keys 포함)
         ↓
5. 서버에서 푸시 메시지 발송 (web-push 라이브러리 등)
         ↓
6. Service Worker에서 push 이벤트 수신 (self.addEventListener('push'))
         ↓
7. 알림 표시 (registration.showNotification)

pushsubscriptionchange 이벤트, 놓치면 안 돼요!

구독이 만료되거나 무효화될 수 있다는 거 아셨나요? 이 이벤트를 처리 안 하면 사용자가 갑자기 알림을 못 받게 될 수 있어요.

// Service Worker에서
self.addEventListener('pushsubscriptionchange', event => {
  event.waitUntil(
    // 새 구독 생성하고 서버에 업데이트
    self.registration.pushManager.subscribe(event.oldSubscription.options)
      .then(newSubscription => {
        return updateSubscriptionOnServer(newSubscription);
      })
  );
});

Firefox vs Chrome 차이점

특성FirefoxChrome
메시지 쿼터있음 (제한적)없음
알림 필수 여부쿼터 초과 시 필수권장
쿼터 갱신사이트 방문 시-

Firefox에서 쿼터 제한에 걸리지 않으려면, 푸시 메시지를 받을 때 반드시 알림을 표시하세요! 그러면 쿼터에서 제외돼요.

ServiceWorker Cookbook 적극 활용하세요!

문서에서 링크된 ServiceWorker Cookbook은 Mozilla에서 만든 공식 예제 모음이에요. 복붙해서 쓸 수 있는 실전 코드들이 가득해요! 저도 처음 배울 때 여기서 정말 많이 참고했어요. 👍

Web Push API Notifications best practices

이 문서는 사용자 참여를 위해 푸시 알림을 사용하는 웹사이트와 애플리케이션을 개발할 때 염두에 두어야 할 모범 사례들에 대한 유용한 요약을 제공해요.

"잘 만들어지면 있으면 좋지만, 잘 만들어지지 않으면 정말 짜증나요." — 푸시 알림의 윤리에 대해 논의하는 두 브라우저 개발자 사이의 우연히 들은 대화


📑 이 문서의 내용


Overview of web push notifications

웹 푸시 알림(Notifications, Push, 그리고 Service Worker API의 조합으로 만들어진)은 제품 개발자들과 마케터들이 그들의 사이트에 주목을 끌기 위해 사용하고 있는 증가하는 소음의 일부예요. "웹 푸시 알림"을 웹에서 검색하면, 푸시를 사용하여 사이트를 떠난 사람들을 다시 참여시켜서 구매를 완료하도록 하거나, 최신 뉴스를 받거나, 추천 제품 링크를 받도록 해야 한다고 믿는 마케팅 전문가들의 글을 찾을 수 있어요.

The dark side

그들의 새로움은 잠재 고객에게 도달하려는 진취적인 사이트들에게 새롭고 착취되지 않은 기회를 제공해요. 고객이 이메일에 답하려고 탭을 전환했나요? 무시할 수 없는 무료 배송의 만료 제안으로 그들을 다시 끌어들이세요!

하지만 정말로, 이게 푸시 알림의 최선의 사용일까요? 아니면 오래되고 지친 팝업 광고의 새로운 반복일까요?

"웹 푸시는 스팸 폴더에 갇힐 위험이 없어요. 광고 차단기에 의해 차단될 수도 없어요. 웹사이트가 닫혀 있어도 바로 데스크톱에 나타나요. 모바일에서는 브라우저가 실행되고 있지 않아도 앱 푸시 알림처럼 알림 트레이에 나타나요." — 이름 없는 마케팅 사이트

Positive uses of push

하지만 푸시 알림의 밝고 유용한 면도 있어요. 여러분과 팀이 일반적으로 채팅 프로그램을 사용하여 소통하는데, 오늘 여러분이 어딘가에서 행복하게 일하고 있고 문제가 발생했다고 가정해봐요. 프로그램 관리자가 승인에서 차질을 발견하고 진행하기 전에 여러분의 피드백을 받고 싶어 해요.

여러분의 주의를 끌려는 몇 번의 실패한 시도 후에, 그들은 여러분에게 이메일을 보내고, 이메일 앱이 푸시 알림을 생성하여 성공적으로 여러분에게 알려요. 비록 메일 웹 앱이 열려 있지 않더라도요.

이 문서에서는 웹 푸시 알림의 윤리적 사용에 대해 이야기할 거예요. 때로는 그것들이 좌절과 짜증을 제거할 수 있고, 때로는 그것들을 야기할 수 있어요. 그리고 푸시 알림의 사용에 대해 현명한 권장 사항(그리고 결정)을 내리는 것은 개발자인 여러분에게 달려 있어요.


What are you hoping to achieve with this push notification?

모든 것이 그렇듯이, 큰 힘에는 큰 책임이 따라요. 모든 푸시 알림은 유용하고 시의적절해야 하며, 사용자는 항상 첫 번째 알림을 보내기 전에 권한을 요청받아야 하고, 앞으로 더 받지 않을 수 있는 쉬운 방법을 제공받아야 해요.

푸시 알림이 필요한지 판단하기 위해 답할 수 있는 몇 가지 기본 질문들이 있어요:

  • 실시간으로 응답을 기다리는 사람이 있나요? 위의 예시에서, 프로그램 관리자는 여러분의 응답을 기다리고 있으므로 푸시 알림이 적절해요.
  • 최신 업데이트가 필요한가요? 저는 다양한 소셜 미디어 뉴스 소스를 집계하는 서비스를 사용해요. 제가 관심 있는 스토리가 트렌딩될 때 알림을 받고 싶어요!
  • 시의적절한 속보가 있나요? 여기서 조금 까다로워져요. 때때로 뉴스 사이트들은 본질적으로 "나를 봐! 나를 봐!"라고 말할 수 있도록 푸시 알림을 요청해요. 모든 것은 사용자가 원하는 것에 달려 있고, 행동을 사용하여 의도를 판단할 수 있어요. 예를 들어, 사용자가 하나 이상의 기사를 보거나 페이지에 몇 분간 머무른다면, 업데이트 받는 것에 관심이 있을 수 있어요.

푸시 알림이 전혀 필요한지에 대한 질문 외에도, 캐주얼하고 사라지는 것부터 지속적이고 상호작용이 필요한 것까지 다양한 많은 유형의 푸시 알림이 있어요.

상호작용이 필요한 것들은 매우 아껴서 사용하라고 주의를 드려요. 왜냐하면 그것들이 가장 짜증날 수 있기 때문이에요. 여러분의 알림은 방해가 아닌 도움이 되어야 해요.


Building trust

일부 연구에 따르면 푸시 알림의 60%나 차단된다고 해요. 사이트가 실시간으로 알림을 푸시할 수 있도록 허용하는 것은 신뢰를 필요로 해요. 잘 설계된 웹사이트를 가지고, 사용자에 대한 존중을 보여주는 좋은 콘텐츠를 제공하고, 푸시 알림을 수락하는 것에 대한 명확한 가치를 제공함으로써 신뢰를 쌓을 수 있어요.


Browser mitigations

과거 푸시 알림의 남용 때문에, 웹 브라우저 개발자들은 이 문제를 완화하기 위한 전략을 구현하기 시작했어요. 예를 들어, Safari 12.1은 이제 요구하고 있어요 — 그리고 다른 브라우저들도 이미 그렇게 하고 있거나 그렇게 할 계획이에요 — 페이지가 푸시 알림을 수행하기 위한 권한을 요청하기 전에 사용자가 페이지와 어떤 방식으로든 상호작용해야 한다는 것을요. 이것은 적어도 사용자가 한 번만 스쳐 본 웹 페이지에서 자발적으로 이 질문을 받는 것을 방지하고, 다시는 보지 않을 수도 있는 페이지에서 말이에요.

Firefox의 경우, Firefox bug 1524619를 보면, Firefox 68이 이것을 구현했으며, 기본적으로 비활성화되어 있고, dom.webnotifications.requireuserinteraction 환경 설정 뒤에 있다는 것을 알 수 있어요.


See also


Help improve MDN

이 페이지가 도움이 되셨나요?

👍 Yes | 👎 No

기여하는 방법 알아보기

이 페이지는 2023년 5월 10일에 MDN contributors에 의해 마지막으로 수정되었어요.

GitHub에서 이 페이지 보기문제 보고하기


💡 강사 팁

여러분, 이 문서는 정말정말 중요해요! 기술적인 내용이 아니라 윤리와 사용자 경험에 대한 내용이거든요. 😊

마케터 vs 개발자의 시각 차이

제가 실무에서 정말 많이 겪은 상황이에요. 마케팅 팀은 이렇게 말해요:

  • "푸시 알림으로 재방문율 30% 증가했어요!"
  • "광고 차단 안 돼서 완전 좋아요!"
  • "사용자 참여도 엄청 올라가요!"

하지만 개발자로서 우리가 봐야 할 건 숫자 뒤의 사용자 경험이에요.

제가 겪은 실제 사례

나쁜 사례 🚫
한 쇼핑몰 사이트에서 일했을 때, 마케팅 팀이 요구한 푸시 알림:

// 사용자가 사이트 들어온 지 5초 후
setTimeout(() => {
  Notification.requestPermission(); // ❌ 최악!
}, 5000);

결과:

  • 권한 수락률 5% 미만 😱
  • 사용자 피드백 최악
  • 브랜드 이미지 타격

좋은 사례 ✅
채팅 앱 프로젝트에서:

// 사용자가 실제로 채팅을 시작한 후
function startChat() {
  // 채팅이 시작되면 알림의 가치를 설명
  showInfoModal({
    title: '메시지 놓치지 마세요!',
    message: '새 메시지가 도착하면 알림을 받으시겠어요?',
    onConfirm: async () => {
      const permission = await Notification.requestPermission();
      if (permission === 'granted') {
        subscribeToNotifications();
      }
    }
  });
}

결과:

  • 권한 수락률 60% 이상 🎉
  • 사용자 만족도 상승
  • 실제로 유용한 알림만 전송

문서에서 강조한 "3가지 질문" 체크리스트

푸시 알림 보내기 전에 항상 이걸 체크하세요:

// 제가 실제로 쓰는 의사결정 헬퍼 함수
function shouldSendPushNotification(context) {
  const checks = {
    // 1. 실시간 응답이 필요한가?
    isRealTimeResponse: context.waitingForResponse === true,
    
    // 2. 최신 정보가 중요한가?
    isTimelyUpdate: context.isBreakingNews || context.isTrending,
    
    // 3. 사용자가 실제로 관심 있어 하나?
    userEngaged: context.pageViews > 1 || context.timeOnSite > 180 // 3분
  };
  
  // 하나라도 true면 고려할 만함
  return Object.values(checks).some(check => check === true);
}

신뢰 구축이 가장 중요해요

문서에서 "60%가 차단된다"고 했죠? 제 경험상 이건 보수적인 추정이에요. 잘못 구현하면 80% 넘게 차단당해요.

신뢰를 쌓는 방법:

  1. 타이밍이 전부
// ❌ 나쁜 타이밍
window.addEventListener('load', requestNotificationPermission);

// ✅ 좋은 타이밍
// 사용자가 "업데이트 구독" 버튼을 클릭했을 때
subscribeButton.addEventListener('click', requestNotificationPermission);
  1. 가치를 먼저 보여주기
    사용자가 서비스의 가치를 경험한 후에 권한을 요청하세요. 예를 들어:
  • 뉴스 사이트: 사용자가 3개 이상 기사를 읽은 후
  • 쇼핑몰: 위시리스트에 아이템을 추가한 후
  • 채팅 앱: 첫 대화를 시작한 후
  1. 명확한 혜택 설명
const message = `
  🔔 알림을 받으시면:
  ✅ 찜한 상품 할인 시 즉시 알림
  ✅ 한정 수량 재입고 알림
  ✅ 배송 상태 실시간 업데이트
`;

브라우저 정책 변화 대응하기

문서에서 언급한 Safari 12.1의 "사용자 상호작용 필수" 정책, 이제 거의 모든 브라우저의 표준이 되었어요.

// 모던 브라우저에서의 안전한 패턴
button.addEventListener('click', async () => {
  // 사용자 제스처 내에서만 권한 요청 가능
  const permission = await Notification.requestPermission();
  
  if (permission === 'granted') {
    console.log('알림 권한 획득!');
  } else if (permission === 'denied') {
    // 대안 제시 (예: 이메일 구독)
    showEmailSubscriptionOption();
  }
});

알림 타입별 사용 가이드

타입언제 쓸까예시
일시적 (자동 사라짐)정보성 알림"저장되었습니다"
지속적 (클릭 필요)응답 필요"회의 5분 전입니다"
인터렉티브 (버튼)즉시 행동 필요"친구 요청 승인/거절"

절대 규칙: 인터렉티브 알림은 정말정말 중요할 때만! 사용자가 하던 일을 멈추게 만드는 거니까요.

제 개인적 원칙

15년 개발하면서 정립한 푸시 알림 원칙:

  1. "내가 받고 싶은 알림인가?" 항상 스스로에게 물어보세요
  2. 오후 10시~아침 8시는 웬만하면 금지 (긴급 상황 제외)
  3. 하루 3개 이상 보내지 않기 (채팅 앱 제외)
  4. 거절해도 서비스 이용에 지장 없게 만들기
  5. 알림 설정을 찾기 쉽게 (보통 숨겨놓는데, 이러면 안 돼요!)

마지막으로, 이 문서의 첫 인용문 기억하시나요?

"잘 만들어지면 있으면 좋지만, 잘 만들어지지 않으면 정말 짜증나요."

이게 전부예요. 사용자를 짜증나게 하지 마세요. 도와주세요! 💙

profile
프론트에_가까운_풀스택_개발자

0개의 댓글