3일 만에 경쟁사 가격 모니터를 만들었습니다, 실제 작동 방식은 이렇습니다
Source: Dev.to
문제점
지난 달에 잠재 고객이 경쟁사의 가격이 내려갔다고 알려줘서 계약을 놓쳤습니다. 가격을 자동으로 모니터링할 수 있는 도구를 찾다가 직접 만들게 되었습니다.
기술 스택
- Framework: Next.js 16 (App Router)
- Scraping: Playwright
- Storage: Supabase
- Email: Resend
- Hosting & Cron: Vercel
분류 엔진
가장 어려운 부분은 신호와 잡음을 구분하는 것이었습니다. 일반적인 페이지 모니터링은 쉽지만, 가격 페이지는 배너 회전, 동적 콘텐츠 등으로 계속 변합니다. 저는 변화를 네 가지 유형으로 분류하는 엔진을 만들었습니다:
| Type | Description |
|---|---|
PRICE_CHANGE | 달러 금액이 변동되는 경우 |
PLAN_CHANGE | 플랜이 새로 나타나거나 사라지는 경우 |
FEATURE_CHANGE | 기능이 티어 간에 이동되는 경우 |
COSMETIC | 그 외 모든 것 (무시) |
PRICE_CHANGE, PLAN_CHANGE, FEATURE_CHANGE만 이메일 알림을 트리거합니다.
핵심 인사이트: 정규화된 Diff
- 날짜, 시간, 네비게이션 텍스트, 쿠키 알림, 소셜 핸들을 제거합니다.
- 남은 텍스트에 대해 라인‑별 diff를 수행합니다.
이 정규화 과정 덕분에 오탐이 크게 감소합니다.
왜 Playwright를 선택했는가 (Puppeteer 대비)
가격 페이지는 대부분 JavaScript‑무거운 싱글 페이지 애플리케이션입니다. Puppeteer는 초기 HTML 응답 이후에 콘텐츠가 로드되는 최신 React 앱에서 종종 어려움을 겪습니다.
Playwright는 waitUntil: 'networkidle'와 추가 2초 대기를 결합해, 약간 더 큰 의존성 규모를 감수하더라도 공격적인 레이지 로딩을 안정적으로 처리합니다.
Cron 워커
- 매일 오전 9시에 실행됩니다.
- 각 모니터를 순차적으로 처리하며, 사이에 3초 지연을 둡니다(병렬 처리 아님).
- 병렬 스크래핑은 금지율 및 차단을 빠르게 초래합니다.
워크플로우:
- 첫 실행: 기준 스냅샷을 저장합니다.
- 이후 실행: 이전 스냅샷과 diff를 수행하고, 변화를 분류한 뒤, 의미 있는 경우 알림을 보냅니다.
다르게 할 점
현재 diff 알고리즘이 가장 약한 고리입니다. 라인‑별 텍스트 diff는 대부분의 변화를 잡아내지만, 텍스트는 그대로인데 경쟁사가 기능을 다른 플랜 섹션으로 옮기는 등 미묘한 구조 변화를 놓칩니다.
다음 단계: 구조화된 데이터(플랜 이름 → 가격 → 기능[])를 추출하고, 원시 텍스트가 아니라 이 구조를 diff합니다.
라이브 데모
모니터는 실시간으로 무료 제공됩니다:
- 계정이나 신용카드가 필요 없습니다.
- URL을 입력하면 가격이 변할 때마다 이메일 알림을 받습니다.
질문
스크래핑, diff 엔진, 이메일 전송 등 구현에 관한 어떤 부분이든 자유롭게 물어보세요.
여러분이라면 무엇을 다르게 구축하시겠습니까?