Chrome Web Store 배포 가이드
작성일: 2026-04-06 Last Updated: 2026-04-06 대상: Chrome Web Store (CWS) 심사 통과 및 배포
공통 문서 참조: CI/CD 파이프라인은
../common/ci-cd.md, 라이선스/트라이얼은../common/licensing.md참조
목차
- 개발자 등록
- 심사 가이드라인
- 거부 사유 Top 10과 대응
- Single Purpose Policy
- 프라이버시 정책
- 권한 정당화 작성 가이드
- 스토어 리스팅
- 게시 및 업데이트
- 심사 후 대응
- 배포 자동화 (CI/CD)
- 체크리스트
1. 개발자 등록
등록 절차
| 단계 | 작업 | 비용 |
|---|---|---|
| 1 | Google 계정 준비 (2FA 필수) | 무료 |
| 2 | Chrome Web Store Developer Dashboard 접속 | - |
| 3 | 개발자 등록비 결제 | $5 (1회) |
| 4 | 연락처 이메일, 개발자 이름 입력 | - |
| 5 | 개인/기업 계정 유형 선택 | - |
기업 계정 vs 개인 계정
| 항목 | 개인 | 기업 |
|---|---|---|
| 등록 정보 | 개인 이름 | 회 사명 + 도메인 검증 |
| 스토어 표시 | 개발자 이름 | 회사명 (신뢰도 향상) |
| 팀 관리 | X | O (그룹 퍼블리셔) |
| 추천 | 개인 프로젝트 | 상용 서비스 |
그룹 퍼블리셔 설정 (기업)
Developer Dashboard → Publisher → Create Group Publisher
→ Google Group 이메일 등록
→ 팀원 초대 (역할: Owner, Developer, Viewer)
2. 심사 가이드라인
심사 기준 요약
| 영 역 | 핵심 기준 |
|---|---|
| 기능 | Single Purpose, 설명과 실제 동작 일치 |
| 권한 | 최소 권한 원칙, 정당화 필수 |
| 프라이버시 | 데이터 수집 고지, 프라이버시 정책 URL 필수 |
| 보안 | 원격 코드 실행 금지, CSP 준수 |
| 콘텐츠 | 불법/유해 콘텐츠 금지, 지적재산권 준수 |
| UX | 사용자 기만 금지, 명확한 설치/제거 |
심사 소요 시간
| 유형 | 소요 시간 | 비고 |
|---|---|---|
| 신규 등록 | 1-7 영업일 | 첫 게시는 더 오래 걸림 |
| 업데이트 (마이너) | 수 시간-3 영업일 | 변경 범위에 따라 다름 |
| 권한 변경 포함 업데이트 | 3-7 영업일 | 추가 심사 |
| 거부 후 재심사 | 3-7 영업일 | 거부 사유 완전 해결 필수 |
3. 거부 사유 Top 10과 대응
1. 과도한 권한 (Excessive Permissions)
// ❌ 거부: 정당화 없는 광범위 권한
{
"permissions": ["tabs", "history", "<all_urls>"]
}
// ✅ 승인: 필요한 것만 + 정당화
{
"permissions": ["activeTab", "storage"],
"host_permissions": ["https://api.myservice.com/*"]
}
2. 원격 코드 실행 (Remotely Hosted Code)
// ❌ 거부: 외부 스크립트 로드 후 실행
const script = document.createElement('script');
script.src = 'https://cdn.example.com/code.js';
document.head.appendChild(script);
// ❌ 거부: eval, new Function
eval(responseFromServer);
// ✅ 승인: 모든 코드는 확장 패키지 내에 포함
import { helper } from './utils/helper.js';
3. 설명과 기능 불일치 (Deceptive Functionality)
| ❌ 거부 사례 | ✅ 올바른 대응 |
|---|---|
| "생산성 도구"인데 광고 삽입 | 실제 기능과 설명 정확히 일치시키기 |
| 숨겨진 데이터 수집 | 모든 데이터 수집을 설명에 명시 |
| 미사용 기능의 권한 요청 | 사용하는 기능만 권한 요청 |
4. 프라이버시 정책 미비
// ❌ 거부: 프라이버시 정책 없음 또는 데이터 수집 고지 누락
// ✅ 승인: 프라이버시 정책 URL 제공 + 데이터 사용 목적 명시
5. Single Purpose 위반
6. 사용자 데이터 처리 위반
| 위반 사항 | 올바른 처리 |
|---|---|
| 동의 없이 브라우징 기록 수집 | 명시적 동의 후 수집, 목적 고지 |
| 수집 데이터 제3자 판매 | 판매 금지 (CWS 정책) |
| 불필요한 PII 수집 | 기능에 필요한 최소 데이터만 수집 |
7. 콘텐츠 정책 위반
- 멀웨어, 피싱 페이지 유도 금지
- 저작권 침해 콘텐츠 금지
- 성인 콘 텐츠는 적절한 등급 표시
8. 키워드 스팸 (Keyword Stuffing)
// ❌ 거부: 설명에 관련 없는 키워드 나열
"best extension free download chrome firefox edge safari ad blocker vpn proxy..."
// ✅ 승인: 실제 기능을 정확히 설명
"Translate selected text on any webpage. Supports 100+ languages with one click."
9. 중복 기능 (Duplicate Functionality)
- 동일 기능의 확장을 여러 개 게시 금지
- 다른 확장의 기능을 그 대로 복제 금지
10. 불완전한 기능 (Broken or Incomplete)
| 확인 사항 | 방법 |
|---|---|
| 모든 UI 동작 확인 | 버튼 클릭, 폼 제출, 에러 상태 |
| 빈 페이지/에러 페이지 없음 | Options, Popup 모든 페이지 테스트 |
| 오프라인 상태 처리 | 네트워크 단절 시 안내 메시지 |
4. Single Purpose Policy
핵심 원칙
하나의 확장은 하나의 브라우저 기능 또는 좁고 관련된 기능 묶음을 제공해야 합니다.
판단 기준
| ✅ 허용 | ❌ 위반 |
|---|---|
| 탭 관리 확장 (정리 + 검색 + 그룹) | 탭 관리 + 날씨 + 뉴스 |
| 번역 확장 (텍스트 + 페이지 + 이미지 OCR) | 번역 + 스크린샷 + 메모 |
| 이메일 알림 (Gmail + Outlook + Yahoo) | 이메일 + 일정 + 할일 + 채팅 |
설명 작성 가이드
// manifest.json의 description (132자 이내)
// 단일 목적이 명확히 드러나도록
✅ "Translate selected text on any webpage with one click. Supports 100+ languages."
✅ "Manage browser tabs efficiently - search, group, and organize your tabs."
❌ "All-in-one productivity tool: translate, take notes, manage tabs, and more!"
5. 프라이버시 정책
필수 여부
| 조건 | 프라이버시 정책 필수 |
|---|---|
| 개인 데이터 수집 | O |
| host_permissions 사용 | O |
| 사용자 인증 (OAuth 등) | O |
| 애널리틱스 포함 | O |
| 순수 로컬 기능만 | 권장 |
프라이버시 정책 필수 항목
# Privacy Policy for [Extension Name]
## Data Collection
- What data is collected (be specific)
- How data is collected (automatic vs user-initiated)
## Use of Data
- Purpose of data collection
- How data is processed
## Data Storage
- Where data is stored (local device, cloud server, region)
- How long data is retained
- Encryption methods used
## Data Sharing
- Third parties with whom data is shared (if any)
- Purpose of sharing
## User Rights
- How to access collected data
- How to request deletion
- How to opt out of data collection
## Contact
- Developer contact email
- Effective date of policy
Last Updated: YYYY-MM-DD
CWS 데이터 수집 고지 (Developer Dashboard)
// Dashboard → Privacy Tab에서 선택
데이터 유형별 체크:
- [ ] Personally identifiable information (이름, 이메일 등)
- [ ] Health information
- [ ] Financial information
- [ ] Authentication information
- [ ] Personal communications
- [ ] Location
- [ ] Web history
- [ ] User activity (클릭, 스크롤 등)
- [ ] Website content
각 항목별 추가 입력:
- Purpose of collection (기능 제공, 분석, 광고 등)
- Is data sold to third parties? (반드시 "No")
- Is data used for purposes unrelated to the extension? (반드시 "No")
- Is data transferred for creditworthiness/lending? (반드시 "No")
6. 권한 정당화 작성 가이드
Dashboard에서 정당화 입력
Developer Dashboard → [Extension] → Privacy → Permissions Justification
작성 패턴 (영문)
| 권한 | 정당화 예시 |
|---|---|
activeTab | "Used to access the current tab's content when the user clicks the extension icon, enabling text selection translation." |
storage | "Stores user preferences (language, theme) and cached translation history locally on the device." |
alarms | "Schedules periodic sync of user bookmarks every 15 minutes to keep data up to date." |
tabs | "Required to detect tab URL changes and show a page action icon on supported websites (e.g., *.github.com)." |
scripting | "Injects the translation overlay UI into the active tab when the user triggers a translation via keyboard shortcut." |
sidePanel | "Provides a persistent side panel UI where users can view and manage their task list alongside any webpage." |
notifications | "Sends desktop notifications when a monitored price drops below the user-configured threshold." |
contextMenus | "Adds a right-click context menu option to translate selected text without opening the popup." |
정당화 작성 원칙
| 원칙 | 설명 | 예시 |
|---|---|---|
| 사용자 행동 명시 | 언제, 어떻게 트리거되는지 | "When the user clicks..." |
| 구체적 목적 | 추상적이 아닌 구체적 기능 | ❌ "For the extension to work" |
| 데이터 범위 | 어떤 데이터에 접근하는지 | "Reads page title and URL only" |
| 최소 접근 | 왜 더 적은 권한으로는 안 되는지 | "activeTab alone is insufficient because..." |
7. 스토어 리스팅
이미지 규격
| 유형 | 크기 | 형식 | 필수 | 비고 |
|---|---|---|---|---|
| 아이콘 | 128x128 | PNG | O | 투명 배경 권장 |
| 스크린샷 (소) | 1280x800 또는 640x400 | PNG/JPEG | O (최소 1장) | 최대 5장 |
| 프로모션 타일 (소) | 440x280 | PNG/JPEG | 권장 | 검색 결과에 표시 |
| 프로모션 타일 (대) | 920x680 | PNG/JPEG | 선택 | Featured 선정 시 사용 |
| 마키 이미지 | 1400x560 | PNG/JPEG | 선택 | 카테고리 배너 |
스크린샷 가이드
✅ 권장:
- 실제 사용 화면 (확장이 동작하는 모습)
- 각 주요 기능별 1장씩
- 화면에 텍스트 오버레이로 기능 설명 추가
- 밝은 배경, 읽기 쉬운 폰트
❌ 회피:
- 스크린샷 없이 단색 배경에 로고만
- 텍스트로만 가득 찬 이미지
- 낮은 해상도 / 흐린 이미지
- 설치 전 상태만 보여주는 스크린샷
국제화 스토어 리스팅
// public/_locales/en/messages.json
{
"extensionName": {
"message": "My Extension",
"description": "Extension name shown in the store"
},
"extensionDescription": {
"message": "Translate any text with one click. Supports 100+ languages.",
"description": "Extension description shown in the store (132 chars max)"
}
}
// public/_locales/ko/messages.json
{
"extensionName": {
"message": "내 확장 프로그램"
},
"extensionDescription": {
"message": "클릭 한 번으로 텍스트를 번역합니다. 100개 이상의 언어를 지원합니다."
}
}
// manifest.json
{
"name": "__MSG_extensionName__",
"description": "__MSG_extensionDescription__",
"default_locale": "en"
}
카테고리 선택
| 카테고리 | 적합한 확장 |
|---|---|
| Accessibility | 스크린리더 보조, 색상 보정 |
| Blogging | 블로그 작성 도구 |
| Developer Tools | 개발자 도구, 디버깅 |
| Fun | 게임, 테마 |
| News & Weather | 뉴스 피드, 날씨 |
| Photos | 이미지 편집, 스크린샷 |
| Productivity | 생산성 도구 (가장 일반적) |
| Search Tools | 검색 도구, 키워드 하이라이트 |
| Shopping | 가격 비교, 쿠폰 |
| Social & Communication | SNS 도구, 메시징 |
8. 게시 및 업데이트
첫 게시 절차
| 단계 | 작업 | 상세 |
|---|---|---|
| 1 | ZIP 패키징 | npm run build → .output/ 압축 |
| 2 | Dashboard에서 업로드 | 새 항목 → ZIP 업로드 |
| 3 | 스토어 리스팅 입력 | 설명, 스크린샷, 카테고리 |
| 4 | 프라이버시 설정 | 데이터 수집 고지, 프라이버시 정책 URL |
| 5 | 권한 정당화 | 각 권한별 사용 목적 작성 |
| 6 | 배포 범위 선택 | 공개/비공개/테스터 |
| 7 | 심사 제출 | "Submit for Review" |
배포 범위
| 옵션 | 대상 | 용도 |
|---|---|---|
| Public | 전체 사용자 | 정식 릴리즈 |
| Unlisted | URL 알고 있는 사용자 | 베타 테스트, 내부 배포 |
| Private | 지정된 사용자/그룹 | 기업 내부 전용 |
| Trusted Testers | 등록된 테스터 | 출시 전 테스트 |
버전 업데이트 전략
// manifest.json 버전 규칙 (SemVer 준수)
{
"version": "1.2.3",
"version_name": "1.2.3 Beta" // 선택 (표시용)
}
| 변경 유형 | 버전 증가 | 심사 수준 |
|---|---|---|
| 버그 수정 | 1.2.3 → 1.2.4 | 빠른 심사 |
| 기능 추가 | 1.2.3 → 1.3.0 | 일반 심사 |
| 권한 추가 | 1.2.3 → 2.0.0 | 상세 심사 + 사용자 재동의 |
단계적 배포 (Staged Rollout)
Developer Dashboard → Distribution → Staged Rollout
단계:
1. 5% → 모니터링 (크래시, 에러 보고)
2. 25% → 안정성 확인
3. 50% → 대규모 테스트
4. 100% → 전체 배포
9. 심사 후 대응
거절 시 대응 절차
| 단계 | 작업 |
|---|---|
| 1 | 거절 이메일의 정확한 사유 확인 |
| 2 | 해당 Chrome Web Store Program Policies 조항 검토 |
| 3 | 코드/매니페스트/설명 수정 |
| 4 | 수정 내용을 Appeal 메시지에 상세 기술 |
| 5 | 재제출 |
Appeal 메시지 작성 템플릿
Subject: Appeal for [Extension Name] - Rejection on [Date]
Dear Chrome Web Store Review Team,
1. Extension ID: [ID]
2. Rejection Reason: [정확한 거절 사유 인용]
3. Changes Made:
- [수정 1]: [상세 설명]
- [수정 2]: [상세 설명]
4. Why this resolves the issue:
[기술적 근거 제시]
Please re-review. Thank you.
계정 정지 방지
| 위반 횟수 | 결과 |
|---|---|
| 1-2회 거절 | 경고, 재제출 가능 |
| 반복 위반 | 확장 삭제 |
| 심각한 위반 | 계정 정지 |