Shoplive 숏폼 Web SDK 연동 가이드
시청자가 어디서 숏폼을 만나는지를 기준으로, 페이지에 붙이는 방법을 안내합니다. 미션은 순서가 아니라 목록이니 필요한 것만 골라 적용하세요.
개요 & 요구사항
Shoplive 숏폼 Web SDK는 스크립트 태그 하나로 숏폼을 웹 페이지에 붙입니다. 별도 패키지 설치나 빌드 도구 설정이 필요 없습니다. SDK가 그리는 화면은 다섯 가지입니다.
| 화면 | 무엇인가 | 어디에 놓나 |
|---|---|---|
| 목록(컬렉션) | 숏폼 카드가 나열된 피드. 카드를 누르면 플레이어가 열림 | 메인 · 숏폼 탭 · 기획전 |
| 플레이어 | 전체 화면 세로 영상 + 상품·댓글·좋아요·공유. 아래 모든 경로의 도착지 | 모달로 자동 생성 (또는 고객사 영역에 인라인) |
| 프리뷰 | 화면 모서리에 떠서 음소거로 자동 재생되는 작은 플레이어 | 상품 상세 |
| 쇼케이스 | 상품 이미지 갤러리 자리를 차지하는 숏폼 카드 | 상품 상세 · 상품 목록 타일 |
| 스토리 | 브랜드·태그·그룹마다 원 하나씩, 인스타그램 스토리처럼 가로로 놓입니다 | 메인 · 숏폼 탭 |
필요한 것
| 항목 | 확인 방법 |
|---|---|
| Access Key | Shoplive Admin에서 확인. 라이브 SDK와 같은 키를 사용합니다 |
| 공개된 숏폼 | Shoplive Admin에 숏폼이 1건 이상 등록·공개돼 있어야 화면에 표시됩니다 |
| (상품 연동 시) 상품 URL | 숏폼에 연결된 상품에 이동 URL이 등록돼 있어야 클릭 시 상품 페이지로 이동합니다 |
진입 경로 지도 — 어떤 페이지에 붙이나요?
시청자가 서 있는 페이지를 고르면 붙여야 할 것이 정해집니다. 위쪽 다섯 가지는 서로 독립이고 순서가 없습니다 — 하나만 써도 되고 여러 개를 함께 써도 됩니다. 아래 네 가지는 어떤 방식으로 노출했든 그 뒤에 공통으로 필요한 것입니다. 기능 이름을 이미 알고 있다면 왼쪽 사이드바에서 바로 찾아가도 됩니다.
| 시청자가 있는 곳 | 붙이는 것 | 가이드 |
|---|---|---|
| 메인 · 숏폼 탭 · 기획전 페이지 | 목록(컬렉션) | 미션 1 · 컬렉션 — 목록으로 노출 |
| 상품 상세 — 구석에 살짝 | 프리뷰 | 미션 3 · 프리뷰 — 화면 구석에 띄우기 |
| 상품 상세 — 갤러리 자리에 크게 · 상품 목록 타일 | 쇼케이스 | 미션 4 · 쇼케이스 — 상품 갤러리 자리에 |
| 메인 · 숏폼 탭 — 브랜드·태그별로 골라 보게 | 스토리 | 미션 2 · 스토리 — 브랜드·태그별로 모아 보기 |
| 배너 · 버튼 · 이벤트 랜딩 | 코드로 플레이어 열기 | 미션 5 · 플레이어 — 코드로 직접 열기 |
| (노출한 뒤) 공유받은 링크 · 광고 URL | 딥링크 | 미션 6 · 딥링크 — 공유 링크로 열기 |
| (노출한 뒤) 댓글 · 좋아요 · 북마크 | 사용자 정보 | 미션 7 · 사용자 정보 연결 |
| (노출한 뒤) 상품 클릭 · 공유 · 애널리틱스 | 이벤트 처리 | 미션 8 · 이벤트 · 상품 클릭 · 데이터 수집 |
| (노출한 뒤) 구매 완료 페이지 — 시청이 구매로 이어졌는지 | 구매 전환 보고 | 미션 9 · 구매 전환 트래킹 |
| 모달 대신 고객사 영역에 플레이어 · Shopify · SPA 등 | — | 부록 |
shoplive.js)와 숏폼(shoplive-shortform.js)은 별도 스크립트이지만 같은 window.cloud.shoplive 객체에 함수를 추가하는 방식이라 한 페이지에 함께 로드할 수 있습니다. 초기화는 각각(initPlugin / initShortform) 호출하고, 사용자 정보 함수(setUserObject·setUserJWT·logout)는 두 SDK가 공유하므로 한 번만 호출합니다.빠른 시작
가장 짧은 경로로 숏폼 목록을 띄우는 예시입니다. 스크립트 태그 한 줄, 초기화 한 줄, 표시 한 줄입니다.
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
cloud.shoplive.initShortform({ accessKey: 'YOUR_ACCESS_KEY' });
</script>
<div id="shoplive-shortform-area"></div>
<script>
cloud.shoplive.setShortformCollection('shoplive-shortform-area');
</script>
호출 순서 규칙
initShortform()은 페이지에서 한 번만 호출합니다. 두 번째 호출은 무시됩니다.- 표시 함수(
setShortformCollection·showShortformPreview·setShortformShowcase·showShortformPlayerModal)는initShortform()전에 호출해도 내부 큐에 쌓였다가 초기화가 끝나면 자동 실행됩니다. 스크립트가<head>와<body>에 나뉘어 있어도 됩니다. - 단, SDK 스크립트 태그 자체는
cloud.shoplive를 호출하는 코드보다 앞에 있어야 합니다.
다음 단계화면 용어 가이드 →
화면 용어 가이드
숏폼 SDK 는 같은 영상을 여러 모양으로 보여 줍니다. 미션마다 그 모양의 이름을 그대로 쓰기 때문에, 읽다가 "쇼케이스가 프리뷰와 뭐가 다르지?" 싶을 때 이 절로 돌아오세요. 각 모양을 누르면 해당 미션으로 갑니다.
화면 모양
위 그림은 실제 화면이 아니라 모양만 그린 것입니다. 어디에 놓는지는 진입 경로 지도에 있습니다.
실제 화면
div 안에 SDK가 카드 목록을 통째로 그리고, 더 불러오기·필터 탭·클릭 시 플레이어 열기까지 그 안에서 처리합니다. 헤더 등 페이지의 나머지는 그대로입니다.
헷갈리기 쉬운 짝
| 용어 | 이것과 헷갈립니다 | 구분하는 법 |
|---|---|---|
| 컬렉션 | Admin 의 「그룹」 · 카드 한 장 | 화면에서 말하는 컬렉션은 목록 영역 전체입니다. 반면 코드의 shortformCollectionId 는 운영자가 Admin 에서 큐레이션한 묶음을 가리키고, Admin 화면은 그것을 「그룹」이라고 부릅니다 (미션 2) |
| 프리뷰 | 쇼케이스 | 프리뷰는 페이지 위에 떠 있어 레이아웃이 그대로이고, 쇼케이스는 갤러리 자리를 대신 차지해 레이아웃 안에 들어갑니다. 둘 다 상품 URL 연동을 쓰고, 한 페이지에 함께 붙일 수도 있습니다 |
| 플레이어 | 컬렉션 · 프리뷰 · 쇼케이스 | 플레이어는 위 모든 경로의 도착지입니다. 기본은 화면을 덮는 모달이고, 고객사 영역 안에 인라인으로 붙일 수도 있습니다 (부록 A) |
이전 ← 빠른 시작다음 → 미션 1 · 컬렉션 — 목록으로 노출
미션 1 · 컬렉션 — 숏폼 목록을 페이지에 노출하기
컬렉션은 id를 가진 빈 div에 렌더링됩니다. 카드를 클릭하면 SDK가 자동으로 플레이어(모달)를 열어 그 숏폼부터 재생하므로 목록만 깔아도 재생까지 동작합니다. 컬렉션이 화면에서 어디까지를 가리키는지는 화면 용어 가이드 · 실제 화면에 있습니다.
1단계 · 레이아웃 고르기
GRID1 기본카드가 크게GRID2카드가 작게HORIZONTAL한 줄로 가로 스크롤| 템플릿 | 모양 | 어울리는 곳 |
|---|---|---|
GRID1 | 카드가 크게 보이고, 제목·브랜드가 카드 위에 겹쳐 표시됩니다. default 값 | 숏폼이 주인공인 기획전·전용 탭 |
GRID2 | 카드가 작게 보이고, 제목·브랜드가 카드 아래에 표시됩니다. 같은 화면에 GRID1보다 많은 숏폼이 들어갑니다 | 다른 콘텐츠와 함께 놓이는 목록 영역 |
HORIZONTAL | 줄바꿈 없이 한 줄로 놓여 가로로 스크롤됩니다. 좌우 화살표·자동 흐름 옵션 제공 | 메인 페이지 중간 띠, 상품 상세 하단 "관련 숏폼" |
2단계 · 어떤 숏폼을 보여줄지 — 필터 선택
이 단계는 건너뛰어도 됩니다. 필터를 하나도 주지 않으면 Admin에 공개된 숏폼이 기본 순서대로 표시되므로, 1단계에서 본 setShortformCollection('컨테이너id') 한 줄만으로 목록이 동작합니다. 아래 옵션은 특정 조건의 숏폼만 노출하고 싶을 때 필요한 것만 골라 추가하세요.
<div id="shoplive-shortform-area"></div>
<script >
cloud.shoplive.setShortformCollection('shoplive-shortform-area', {
template: 'HORIZONTAL',
tags: ['sale', 'new'], // 태그로 필터. 문자열이 아니라 배열로 전달합니다
tagSearchOperator: 'OR', // 'OR' 하나라도 일치 · 'AND' 모두 일치
displayTags: ['sale', 'new', 'best'], // 목록 상단에 필터 탭으로 노출
horizontalOption: { hasDirectionWhenHorizontal: true, lineItemCount: 4 }
});
</script>
| 옵션 | 설명 |
|---|---|
tags: string[] | Admin에서 숏폼에 붙인 태그로 필터. tagSearchOperator로 OR/AND 선택 |
brands: string[] | 브랜드 식별자로 필터 |
skus: string[] | 연결된 상품 SKU로 필터 — 상품 상세 하단 "이 상품이 나오는 숏폼"에 적합 |
shortformCollectionId | Admin에서 만든 그룹 하나를 그대로 노출 |
shuffle: true | 랜덤 순서 |
sortProperty / sortDirection | 정렬 기준과 방향. sortProperty는 'createdAt'(등록일) · 'updatedAt'(수정일) · 'viewCount'(조회) · 'likeCount'(좋아요) · 'commentCount'(댓글) · 'shareCount'(공유) · 'bookmarkCount'(북마크) 중 하나, sortDirection은 'asc' | 'desc'. 지정하지 않으면 Admin에서 정해 둔 순서를 그대로 따릅니다 |
displayTags: string[] | 목록 상단에 필터 탭으로 노출할 태그. 시청자가 탭을 눌러 좁혀 볼 수 있음 |
brands·tags는 반드시 배열
tags: 'sale'처럼 문자열을 넘기면 콘솔에 "tags" property must be array 에러가 찍히고 렌더링이 중단됩니다. 값이 하나여도 ['sale']로 감싸세요.여기에 넣는 tags·brands 값은 Admin에서 숏폼에 붙여 둔 값과 정확히 같아야 합니다. 어디서 정해지는지는 아래와 같습니다.
tags·displayTags로, Brand에 연결한 브랜드가 brands로 필터됩니다. 숏폼 하나에 태그는 5개까지 붙일 수 있습니다.
brands에 넘기는 값은 브랜드 이름(Title)이 아니라 Brand Identifier입니다. 브랜드를 만들 때 정한 이 문자열을 그대로 배열에 넣으세요.3단계 · 더 불러오기 정책 — 버튼 vs 무한 스크롤 선택
이 단계도 건너뛸 수 있습니다. 아무것도 지정하지 않으면 목록 아래에 더보기 버튼이 붙습니다(hasMoreButton 기본값 true). false로 두면 버튼이 사라지는 대신 무한 스크롤로 바뀌니, 그렇게 바꾸고 싶을 때만 지정하세요.
| 설정 | GRID1 · GRID2 | HORIZONTAL |
|---|---|---|
hasMoreButton: true (기본) | 하단 더보기 버튼. 누르면 다음 묶음이 붙고 포커스가 새 카드로 이동 | 스크롤 끝에 가까워지면 자동으로 다음 묶음 로드 |
hasMoreButton: false | 목록 끝이 화면에 들어오면 자동 로드 (무한 스크롤) | 자동 로드. 단 limit을 함께 지정하면 그 개수에서 멈춤 |
| 옵션 | 설명 |
|---|---|
rows | 처음에 보여줄 행 수. 기본 2 |
limit | 목록에 표시할 최대 숏폼 수. HORIZONTAL + hasMoreButton: false에서는 "정확히 N개만" 보여주는 용도 |
4단계 · 표시 옵션 선택
이 단계도 전부 선택 사항입니다. 지정하지 않으면 아래 기본값으로 동작합니다.
| 옵션 | 기본값 | 설명 |
|---|---|---|
productLayout | 'CIRCLE' | 카드에 표시되는 상품 썸네일 모양('CIRCLE' 원형 · 'CARD' 카드형). 계정에 별도 설정이 있으면 그 값이 'CIRCLE'보다 우선하고, 코드로 지정하면 그보다도 우선합니다 |
disablePreviewVideoPlay | false | true로 주면 카드에 마우스를 올렸을 때의 미리보기 영상 재생을 끕니다 |
previewVideoAutoPlayType | 없음 | 'intersection'을 주면 카드가 화면에 들어오는 시점에 미리보기 영상을 재생합니다 (HORIZONTAL 외 템플릿) |
horizontalOption.hasDirectionWhenHorizontal | false | true로 주면 가로 스크롤 좌우에 화살표 버튼을 표시합니다 (HORIZONTAL 전용) |
horizontalOption.lineItemCount | 없음 | 한 줄에 보일 카드 수. 지정하면 컨테이너 너비를 이 수로 나눠 카드 폭을 계산합니다. 없으면 템플릿 기본 폭 (HORIZONTAL 전용) |
horizontalOption.autoFlow | false | true로 주면 카드가 우→좌로 자동으로 흐릅니다 (HORIZONTAL 전용) |
horizontalOption.insideDescription | false | true로 주면 브랜드·제목·설명을 카드 아래가 아니라 카드 내부 하단(그라데이션 위 흰 글씨)에 표시합니다. 카드 아래 정보 영역은 그리지 않습니다 (HORIZONTAL 전용) |
horizontalOption.scrollIndicator | false | true로 주면 목록 아래에 가로 스크롤 진행 바를 표시합니다. 클릭·드래그로 이동할 수 있고, 카드가 한 화면에 다 들어가 스크롤할 것이 없으면 그리지 않습니다 (HORIZONTAL 전용) |
showProduct | false | true로 주면 각 카드 아래에 연결 상품을 최대 2개(썸네일·상품명·가격) 표시합니다. 상품이 2개 이상이면 상품 더보기 링크가 붙고, 누르면 플레이어가 열립니다(모바일 레이아웃에서는 상품 목록이 열린 채로 진입). 이때 카드 내부의 상품 버튼은 중복이라 숨깁니다 — 내부 버튼 자체는 Admin 의 컬렉션 설정이 따로 제어합니다 |
enableGestureSlide | true | false로 주면 드래그/스와이프를 끄고 화살표 버튼으로만 이동합니다 |
disableQueryParamHistory | false | true로 주면 카드 클릭 시 URL에 숏폼 ID를 기록하지 않습니다 — 딥링크 참고 |
가로 스크롤 띠에 상품 목록과 카드 내부 설명까지 붙이는 조합 예시입니다. 세 옵션은 각각 독립이라 필요한 것만 골라 쓰면 됩니다.
// 가로 스크롤 + 카드 아래 상품 목록 + 제목·설명을 카드 안에 + 스크롤 진행 바
cloud.shoplive.setShortformCollection('shoplive-shortform-area', {
template: 'HORIZONTAL',
showProduct: true,
horizontalOption: {
insideDescription: true,
scrollIndicator: true,
hasDirectionWhenHorizontal: true,
lineItemCount: 5
}
});
showProduct 의 상품 목록은 목록 조회 응답에 든 상품으로 먼저 그리고, 연결 상품이 더 있으면 카드가 화면에 들어올 때 나머지를 한 번 더 가져옵니다. 노출 카드 수만큼 요청이 늘 수 있으니, 숏폼마다 상품을 많이 연결한 목록에서는 limit·rows 로 첫 화면의 카드 수를 조절하세요.
5단계 · 정리하기 선택
탭 전환 등으로 목록을 치워야 하면 destroyShortformCollection('컨테이너id')를 호출합니다. 인자를 생략하면 페이지의 모든 컬렉션을 제거합니다. 같은 컨테이너에 setShortformCollection을 다시 호출하면 기존 목록을 정리하고 새로 그리므로, 필터를 바꿔 다시 그릴 때는 destroy 없이 재호출해도 됩니다.
완료 확인
- 지정한
div위치에 선택한 템플릿 모양으로 숏폼 카드가 렌더링된다 - 카드를 클릭하면 전체 화면 플레이어가 열리고 그 숏폼부터 재생된다
- 목록 끝에서 더보기 버튼(또는 무한 스크롤)로 다음 묶음이 이어진다
- 필터를 걸었다면 조건에 맞는 숏폼만 표시된다 — 아무것도 안 뜨면 Admin에서 해당 태그·SKU의 공개 숏폼이 있는지 확인
이전 ← 화면 용어 가이드다음 → 미션 2 · 스토리 — 브랜드·태그별로 모아 보여주기
미션 2 · 스토리 — 브랜드·태그별로 모아 보여주기
조건 1개가 원 1개입니다. 브랜드 3개를 주면 원 3개가 생기고, 각 원은 그 조건의 숏폼 묶음을 대표합니다. 시청자가 원을 누르면 그 묶음이 열립니다.
위 캡처처럼 브랜드만으로 원을 그리려면 brands 하나만 넘기면 됩니다. 넘긴 순서대로 왼쪽부터 원이 놓입니다. 배열에는 Admin 브랜드의 Identifier 를 넣습니다 — 원 아래에 보이는 브랜드명(Title)이 아니므로, 대소문자까지 그대로 옮겨 적으세요(1단계 ② 참고).
// 캡처와 같은 스토리 — 브랜드 3개 = 원 3개
cloud.shoplive.setShortformStory('story-tray', {
brands: ['shoplive', 'shoplive2', 'TESTER']
});
<div id="story-tray"></div>
<script>
cloud.shoplive.setShortformStory('story-tray', {
brands: ['mybrand'],
tags: ['신상'],
shortformCollectionIds: ['1272599072386056193']
});
</script>
위 예시는 원 3개짜리 스토리를 그립니다 — 브랜드 1개 + 태그 1개 + 그룹 1개.
1단계 · 어떤 원을 만들지
세 가지 조건을 섞어 쓸 수 있고, 배열에 넣은 순서대로 원이 놓입니다. 원의 라벨과 이미지는 SDK 가 조회 결과에서 자동으로 뽑습니다 — 따로 지정하지 않습니다.
| 조건 | 원의 라벨 | 원의 이미지 |
|---|---|---|
brands | 브랜드명. 없으면 넘긴 식별자 그대로 | 브랜드 로고 → 없으면 첫 숏폼 썸네일 |
tags | 태그 문자열 그대로 | 첫 숏폼 썸네일 |
shortformCollectionIds | 그룹 제목. 없으면 ID 그대로 | 첫 숏폼 썸네일 |
shortformCollectionIds 에 넣는 값은 Admin 에서 운영자가 큐레이션한 숏폼 그룹의 ID 입니다. 코드상의 이름(collection)과 Admin 의 표기(그룹)가 다르니, 담당자와 이야기할 때 헷갈리지 않도록 주의하세요. 같은 값을 컬렉션·프리뷰에서는 shortformCollectionId(단수)로 씁니다.세 조건의 값은 모두 Admin 숏폼 편집 화면에서 정해집니다. 어디서 확인하는지 순서대로 보겠습니다.
brands·tags·shortformCollectionIds 에 대응합니다. 여기에 붙여 둔 값과 코드에 넘긴 값이 같아야 그 원에 숏폼이 모입니다.
brands 에 넣는 값은 Identifier 열입니다 — 숫자 ID 도, 화면에 보이는 Title 도 아닙니다. 위처럼 Title 이 같은 Shoplive 브랜드가 둘이어도 Identifier(Shoplive · shoplive)로 구분되니, 대소문자까지 그대로 옮겨 적으세요.
shortformCollectionIds 에 넣는 그룹 ID 입니다. 옆의 링크 아이콘으로 복사할 수 있습니다.
해당하는 숏폼이 0건이거나 조회에 실패한 원은 그려지지 않습니다. 조건 3개를 넘겼는데 원이 2개만 보인다면 나머지 하나에 공개된 숏폼이 없는 것입니다 — 어느 원이 어떻게 됐는지는 렌더 결과 이벤트로 확인할 수 있습니다.
2단계 · 원을 눌렀을 때 선택
기본은 전체 화면 플레이어 모달이 열리는 것입니다. grid: true 를 주면 대신 스토리 아래에 그 조건의 컬렉션이 깔립니다.
기본 (grid 미지정) | grid: true | |
|---|---|---|
| 첫 진입 | 스토리만 보입니다 | 첫 번째 원이 자동으로 활성되고 그 컬렉션이 함께 보입니다 |
| 원을 누르면 | 플레이어 모달이 열립니다 | 모달은 열리지 않고 아래 컬렉션이 그 조건으로 교체됩니다 |
| 플레이어는 언제 | 원을 누를 때 | 아래 컬렉션 카드를 누를 때 |
// 스토리 아래에 컬렉션을 함께 깔고, 원으로 골라 보게 한다
cloud.shoplive.setShortformStory('story-tray', {
brands: ['brand-a', 'brand-b'],
grid: true
});
// 컬렉션을 스토리 바로 아래가 아니라 페이지의 다른 자리에 두고 싶다면
cloud.shoplive.setShortformStory('story-tray', {
brands: ['brand-a', 'brand-b'],
grid: true,
gridContainerId: 'my-collection-area'
});
gridContainerId 로 지정한 요소가 없거나, 스토리 자신 또는 그 조상을 가리키면(그 경우 스토리가 스스로를 지워 버립니다) 콘솔에 경고를 남기고 스토리 바로 아래로 되돌립니다. 컬렉션의 레이아웃은 GRID2 로 고정이며 컬렉션의 template·rows 같은 옵션은 이 모드에서 지정할 수 없습니다.
3단계 · 새 숏폼 표시 — 무지개 링과 회색 링
인스타그램과 같은 규칙입니다. 아직 안 본 숏폼이 있으면 무지개 링, 다 봤으면 회색 링입니다. 고객사가 할 일은 없고 SDK 가 알아서 처리합니다.
- 기록 시점은 클릭입니다 — 원이 화면에 그려진 것만으로는 '본 것'이 되지 않습니다
- 브라우저의
localStorage에 저장하므로 기기·브라우저마다 따로입니다. 로그인 여부와 무관합니다 - 다음 방문 때 저장해 둔 목록에 없는 숏폼이 하나라도 있으면 다시 무지개가 됩니다. 숏폼이 지워지기만 했다면 회색을 유지합니다
렌더 결과 확인 선택
0건인 원은 조용히 사라지므로, 어느 조건이 비어 있는지 알고 싶다면 ON_SHORTS_STORY_RENDERED 를 들으세요. 원 하나하나의 결과가 배열로 옵니다.
cloud.shoplive.addShortformEventListener(function (event) {
if (event.name !== 'ON_SHORTS_STORY_RENDERED') return;
event.payload.items.forEach(function (item) {
// { type: 'brand' | 'tag' | 'collection', identifier, success, label, shortsCount }
if (!item.success || item.shortsCount === 0) {
console.warn('원이 그려지지 않았습니다:', item.type, item.identifier);
}
});
});
정리하기
SPA 에서 페이지를 벗어날 때 호출합니다. 인자를 생략하면 페이지의 모든 스토리를 지웁니다. grid 모드로 깔린 컬렉션도 함께 정리됩니다.
cloud.shoplive.destroyShortformStory('story-tray');
알아 둘 것 — 같은 페이지에 같은 조건의 원이 둘 있으면 링 색이 즉시 동기화되지 않습니다(다음 로드 때 맞춰집니다). 또 스토리 둘이 같은 gridContainerId 를 가리키면 나중에 그린 쪽이 이깁니다. 인자 없는 destroyShortformCollection() 은 grid 모드로 깔린 컬렉션까지 지웁니다.
완료 확인
- 지정한
div안에 조건 수만큼 원이 그려진다 (숏폼이 0건인 조건은 제외) - 원 아래 라벨이 브랜드명 · 태그 · 그룹 제목으로 나온다
- 원을 누르면 플레이어가 열린다 (
grid: true면 아래 컬렉션이 교체된다) - 한 번 누른 원은 다시 방문했을 때 회색 링으로 바뀐다
미션 3 · 프리뷰 — 화면 구석에 작게 띄우기
initShortform() 완료 · Shoplive Admin 접근 권한 (1단계에서 사용)프리뷰는 화면 네 모서리 중 한 곳에 떠 있는 음소거된 작은 플레이어입니다. 컨테이너를 만들 필요 없이 SDK가 페이지에 직접 붙이며, 시청자가 닫으면 일정 시간 다시 뜨지 않게 할 수 있습니다.
1단계 · Admin에서 상품 URL 연결하기
프리뷰에서 실제로 손이 많이 가는 곳은 코드가 아니라 Admin 설정입니다. 호출은 showShortformPreview() 한 줄이면 되지만, 그 한 줄이 무엇을 띄울지는 Admin에 등록된 상품 URL이 결정하기 때문입니다.
SDK는 프리뷰를 띄울 때 현재 페이지의 주소를 서버에 보내 "이 주소에 연결된 숏폼"을 찾습니다. 그래서 Admin에서 아래 두 가지가 되어 있어야 합니다.
- 상품에 URL을 등록합니다. 시청자가 보게 될 고객사 상품 상세 페이지 주소를 그대로 넣습니다. 이 값이 프리뷰 조회의 기준입니다.
- 그 상품을 숏폼에 연결하고 공개합니다. 연결된 상품이 없거나 숏폼이 비공개면 조회 결과가 0건이라 프리뷰가 뜨지 않습니다.
?utm_source=…)나 www 유무처럼 사소한 차이로도 조회가 빗나갑니다. 같은 상품이 여러 주소로 열리는 쇼핑몰이라면 2단계의 sku 방식을 쓰세요.2단계 · 무엇이 뜰지 정하기
Admin 준비가 끝났다면 호출은 한 줄입니다. 아래 세 가지 중 페이지 성격에 맞는 것을 고르세요.
| 호출 | 보여주는 숏폼 | 언제 쓰나 |
|---|---|---|
showShortformPreview() | 현재 페이지 URL에 연결된 관련 숏폼 (기본) | Admin에서 숏폼의 상품에 등록한 URL이 현재 페이지와 일치할 때 |
showShortformPreview({ sku }) | 현재 URL + SKU 힌트로 관련 숏폼 조회 | 같은 상품이 여러 URL로 열리는 쇼핑몰 |
showShortformPreview({ tags | brands | skus | shortformCollectionId }) | 지정한 필터 조건으로 조회 (URL은 보지 않음) | "세일 태그 숏폼 중 하나"처럼 페이지와 무관한 노출 |
<!-- 1. SDK 로드 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
// 2. 초기화
cloud.shoplive.initShortform({ accessKey: 'YOUR_ACCESS_KEY' });
// 3. 프리뷰 호출 — 현재 페이지 주소에 연결된 숏폼을 띄웁니다
cloud.shoplive.showShortformPreview();
// 같은 상품이 여러 주소로 열린다면 SKU 를 함께
// cloud.shoplive.showShortformPreview({ sku: 'PRODUCT_SKU' });
</script>
3단계 · 위치와 크기 선택
이 단계도 건너뛸 수 있습니다. 아무것도 지정하지 않으면 위치·크기 모두 계정 기본값으로 표시됩니다. 페이지 레이아웃과 겹치거나 크기를 조정해야 할 때만 아래 옵션을 쓰세요.
position 키와 화면 위치. 키를 눌러 보세요 — 위 화면과 오른쪽 미리보기에서 프리뷰가 그 자리로 옮겨갑니다. 지정하지 않으면 계정 기본값이 적용됩니다.
position과 size는 객체를 중첩해서 넘깁니다. 아래 형태 그대로 쓰면 됩니다.
cloud.shoplive.showShortformPreview({
// 어느 모서리에 띄울지 — 네 키 중 하나만 true 로
position: { 'bo-ri': true },
// 기기 폭에 따라 다른 크기 — 필요한 기기만 적으면 됩니다
size: {
desktop: { width: '160px' }, // 넓은 화면
tablet: { width: '18vw', maxWidth: '150px' }, // 태블릿
mobile: { width: '28vw', maxWidth: '140px' } // 모바일
},
resizable: true // 시청자가 모서리를 끌어 크기를 바꿀 수 있게
});
| 필드 | 넣는 값 | 설명 |
|---|---|---|
position | { 'bo-ri': true } | 네 모서리 중 하나만 true. 키는 위 그림 참고 (to=위 · bo=아래 · le=왼쪽 · ri=오른쪽) |
size.desktop | { width, maxWidth, | 넓은 화면에서의 크기 |
size.tablet | 태블릿 폭에서의 크기 | |
size.mobile | 모바일 폭에서의 크기 | |
resizable | true | 시청자가 모서리를 드래그해 크기 조절 (그 세션 동안 유지) |
기기 구분 기준 — 어느 폭에서 무엇이 적용되나
세 키는 브라우저 창 너비(뷰포트 폭)로 갈립니다. 기기 종류를 감지하는 것이 아니라 폭만 봅니다 — 데스크톱에서 창을 좁히면 tablet·mobile 값이 적용됩니다.
| 키 | 적용되는 창 너비 | 지정하지 않았을 때 크기 |
|---|---|---|
size.desktop | 1025px 이상 | 너비 17vw (최대 200px) · 높이 17vw × 15/9 (최대 332px) |
size.tablet | 481 ~ 1024px | 너비 26vw (최대 200px) · 높이 26vw × 15/9 (최대 332px) |
size.mobile | 480px 이하 | 너비 35vw (최대 200px) · 높이 35vw × 3/2 (최대 332px) |
어느 구간이든 최소 크기는 너비 100px · 높이 150px 로 고정되어, 값을 더 작게 줘도 그 아래로는 줄어들지 않습니다.
'160px'·'20vw'처럼 단위를 포함한 문자열로 넣습니다. 기기 구분은 필요한 것만 적으면 되고, 적지 않은 구간은 위 표의 기본값을 따릅니다.width만 바꾸면 세로가 어긋납니다
height를 함께 주지 않으면 높이는 기본 계산식이 그대로 쓰입니다. 예를 들어 데스크톱에서 width: '160px'만 주면 너비는 160px이 되지만 높이는 여전히 17vw × 15/9로 계산되어, 창이 넓을수록 위아래로 길쭉해집니다. 크기를 조정할 때는 width와 height를 짝으로 지정하세요.
// 권장 — 너비와 높이를 함께 (숏폼은 9:16 세로 영상)
size: {
desktop: { width: '160px', height: '284px' },
mobile: { width: '28vw', height: 'calc(28vw * 16 / 9)' }
}
4단계 · 닫기 정책
closePolicyExpiry | 시청자가 ✕로 닫은 뒤 |
|---|---|
| 미지정 | 이 브라우저 세션 안에서는 다시 표시하지 않음 |
0 | 미지정과 같음 (세션 내 재표시 없음) |
N (분) | N분 동안 다시 표시하지 않음. 세션이 바뀌어도 유지됨 (브라우저 저장소에 기록) |
iframe 안에서 열림 ④ 브라우저 PIP로 재생하던 상태에서 이동해 온 페이지 ⑤ 조건에 맞는 숏폼이 0건 — 이 경우 SDK는 프리뷰를 만들지 않고 에러도 내지 않습니다. 개발 중에 안 뜨면 먼저 브라우저의 localStorage·sessionStorage를 비우고 다시 확인하세요.시청자가 프리뷰를 드래그하는 동안에는 ON_DRAG_START_PREVIEW / ON_DRAG_END_PREVIEW 이벤트가 발생합니다(이벤트 처리). 프리뷰가 하단 구매 바 같은 요소를 가릴 때 잠시 숨기는 용도로 활용할 수 있습니다.
전체 코드
2단계의 최소 형태에 위치·닫기 정책까지 더한 실전 구성입니다. 옵션을 하나도 주지 않으면 위치·크기는 계정 기본값을 따릅니다.
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
cloud.shoplive.initShortform({ accessKey: 'YOUR_ACCESS_KEY' });
// 상품 상세 페이지에서 호출 — 이 페이지 주소에 연결된 숏폼이 뜹니다
cloud.shoplive.showShortformPreview({
position: { 'bo-ri': true }, // 우하단
closePolicyExpiry: 60 // 닫으면 60분 동안 다시 뜨지 않음
});
</script>
SPA 라우팅으로 상품 상세를 벗어날 때는 cloud.shoplive.hideShortformPreview()로 정리하세요.
완료 확인
- Admin에 등록한 상품 URL과 같은 주소의 페이지에서 프리뷰가 뜬다
- 상품 상세 진입 시 지정한 모서리에 작은 플레이어가 음소거로 자동 재생된다
- 프리뷰를 탭하면 전체 화면 플레이어가 열리고, ✕를 누르면 사라진다
- 닫은 뒤 새로고침하면 닫기 정책대로 다시 뜨지 않는다
이전 ← 미션 2 · 스토리 — 브랜드·태그별로 모아 보여주기다음 → 미션 4 · 쇼케이스 — 상품 갤러리 자리에
미션 4 · 쇼케이스 — 상품 갤러리 자리를 숏폼으로
프리뷰가 페이지 위에 떠 있는 것과 달리, 쇼케이스는 페이지 레이아웃 안에 들어갑니다. 기존 갤러리 자리를 그대로 차지하므로 상품 상세의 첫인상을 영상으로 바꾸는 효과가 있습니다.
1단계 · 상품 상세에 적용
<!-- 고객사 페이지에 이미 있는 상품 이미지 갤러리 -->
<div id="product-gallery">
<img src="product-1.jpg" alt="">
<img src="product-2.jpg" alt="">
</div>
<script>
// 현재 페이지 URL에 연결된 숏폼을 조회해 갤러리 자리에 렌더링
cloud.shoplive.setShortformShowcase('product-gallery');
</script>
인자를 생략하면 현재 페이지 URL을 기준으로 관련 숏폼을 찾습니다. Admin에서 숏폼에 연결한 상품의 URL과 현재 페이지 URL이 일치해야 하므로, 쿼리 파라미터가 자주 붙는 페이지라면 아래 url 모드로 정규화된 URL을 직접 넘기세요.
컨테이너에는 크기가 정해져 있어야 합니다. 대부분의 상품 상세는 갤러리 영역에 이미 폭·비율이 잡혀 있으므로 그대로 쓰면 되고, 크기가 없는 빈 div라면 width·height 또는 aspect-ratio를 페이지 CSS 에서 지정해 주세요.
2단계 · 상품 목록에 적용 — url · shortformId 모드
| 모드 | 호출 | 카드를 탭하면 | 활용처 |
|---|---|---|---|
| 현재 URL (기본) | setShortformShowcase(id) | 플레이어(모달)가 열림 | 상품 상세 |
| URL 지정 | setShortformShowcase(id, { url }) | 해당 URL로 페이지 이동 | 상품 목록에서 상품별 타일에 숏폼 전시 |
| 숏폼 ID 지정 | setShortformShowcase(id, { shortformId }) | 플레이어(모달)가 열림 | 한 페이지에 서로 다른 쇼케이스 여러 개. url과 함께 주면 shortformId 우선 |
3단계 · 원본 갤러리와의 관계
기본값(removeOriginalDOM: true)에서 SDK는 렌더링에 성공한 뒤에만 컨테이너의 기존 자식 요소를 제거합니다. 그 전까지는 원본 갤러리가 그대로 보이고, 조회 실패·설정 OFF 등으로 렌더링하지 않으면 원본을 건드리지 않습니다. 따라서 스켈레톤이나 로딩 처리를 따로 만들 필요가 없습니다. 원본을 유지한 채 덧그리고 싶다면 removeOriginalDOM: false를 주세요.
렌더링 결과는 ON_SHORTS_SHOWCASE_RENDERED 이벤트로 알려줍니다 — payload.success가 true면 shortsId·shorts가, false면 reason이 들어 있습니다. 성공 시 갤러리 인디케이터를 숨기는 등의 후처리에 사용하세요.
div:empty { display: none } 규칙이 SDK의 투명 클릭 영역을 숨겨 영상은 보이는데 탭이 안 되는 문제가 있었습니다. 렌더링은 되는데 반응이 없으면 개발자 도구로 컨테이너 안 .csl-로 시작하는 요소들에 페이지 CSS가 덮어쓰고 있지 않은지 확인하세요.완료 확인
- 상품 상세 진입 시 갤러리 자리에 숏폼 카드가 렌더링되고 원본 이미지가 사라진다 (설정이 꺼진 상품에서는 원본이 그대로 보인다)
- 카드를 탭하면 플레이어가 열린다 (
url모드라면 해당 상품 페이지로 이동) - 카드가 2장 이상이면 하단에 썸네일 스트립이 보이고 좌우 스와이프가 동작한다
미션 5 · 플레이어 — 코드로 직접 열기
initShortform() 완료 · 재생할 숏폼 ID 또는 필터 조건1단계 · 여는 방법 고르기
| 구분 | 방법 A · 숏폼 ID 지정 | 방법 B · 필터 조건 지정 |
|---|---|---|
| 호출 | showShortformPlayerModal({ ids: [...] }) | showShortformPlayerModal({ tags: [...] }) 등 |
| 재생 목록 | 넘긴 ID 순서 그대로. startIndex로 시작 위치 지정. 숏폼 하나만 열 때도 따로 쓰는 옵션 없이 ids: ['SHORTFORM_ID']처럼 ID 하나만 넣으면 됩니다 | 조건에 맞는 숏폼을 서버에서 조회. shortsId로 시작 숏폼 지정 |
| 대표 활용처 | 특정 영상으로 바로 진입하는 배너·이벤트 랜딩 | "세일 태그 영상 전부 보기" 같은 버튼 |
<!-- 1. SDK 로드 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
// 2. 초기화
cloud.shoplive.initShortform({ accessKey: 'YOUR_ACCESS_KEY' });
</script>
<!-- 3. 이 버튼을 누르면 플레이어가 열립니다 -->
<button id="open-shortform">추천 영상 보기</button>
<script>
document.getElementById('open-shortform').addEventListener('click', function () {
// 방법 A — 숏폼 ID 로 직접 지정 (ID 는 Admin 숏폼 상세에서 확인)
cloud.shoplive.showShortformPlayerModal({
ids: ['SHORTFORM_ID_1', 'SHORTFORM_ID_2'], // 하나만 열려면 ['SHORTFORM_ID']
startIndex: 0, // 두 번째부터 시작하려면 1
muted: true // 초기 음소거 (브라우저 자동재생 정책 대응에 유용)
});
// 방법 B — 필터 조건으로 목록을 만들어 재생
// cloud.shoplive.showShortformPlayerModal({
// tags: ['sale'],
// shortsId: 'SHORTFORM_ID_TO_START' // 선택 — 목록 중 이 숏폼부터
// });
});
</script>
2단계 · (선택) 재생 목록에 더 추가하기
방법 A로 열었을 때 시청자가 목록 끝에 가까워지면 SDK가 NEEDS_SHORTFORM_LIST_MORE 이벤트를 보냅니다. 이 이벤트를 받아(이벤트 처리) 다음 페이지 ID를 shortformPlayerAppendList로 넘기면 끊김 없이 이어집니다.
<!-- 1. SDK 로드 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
// 2. 초기화
cloud.shoplive.initShortform({ accessKey: 'YOUR_ACCESS_KEY' });
// 3. 목록 끝에 가까워지면 SDK 가 이 이벤트를 보냅니다
cloud.shoplive.addShortformEventListener(function (name, payload) {
if (name === 'NEEDS_SHORTFORM_LIST_MORE') {
fetchNextPageIds().then(function (ids) { // 고객사 서버에서 다음 ID 목록 조회
cloud.shoplive.shortformPlayerAppendList({ ids: ids });
});
}
});
</script>
3단계 · 닫기와 음소거 선택
플레이어는 시청자가 직접 닫을 수 있고 음소거도 스스로 조작하므로, 아래 함수는 고객사 코드에서 제어해야 할 때만 씁니다. 예를 들어 SPA 라우팅으로 페이지를 벗어날 때 닫거나, 페이지의 다른 영상과 소리가 겹치지 않게 맞출 때입니다.
<!-- 1. SDK 로드 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
// 2. 초기화
cloud.shoplive.initShortform({ accessKey: 'YOUR_ACCESS_KEY' });
</script>
<!-- 3. 고객사 페이지의 버튼에서 제어 -->
<button id="close-shortform">닫기</button>
<button id="toggle-mute">소리 켜기 / 끄기</button>
<script>
// 열린 플레이어 닫기
document.getElementById('close-shortform').addEventListener('click', function () {
cloud.shoplive.dismissShortformPlayerModal();
});
// 음소거 토글 — 현재 상태를 읽어 뒤집습니다 (페이지 전체 플레이어에 공통 적용)
document.getElementById('toggle-mute').addEventListener('click', function () {
var isMuted = cloud.shoplive.getShortformGlobalMuteState(); // true = 음소거 중
cloud.shoplive.setShortformGlobalMuteState(!isMuted);
});
</script>
setShortformGlobalMuteState를 다시 호출할 필요가 없습니다.완료 확인
- 버튼 클릭 등 고객사 코드에서 호출하면 전체 화면 플레이어가 열리고, 지정한 숏폼(또는 목록의 첫 숏폼)부터 재생된다
- 목록 끝에서
NEEDS_SHORTFORM_LIST_MORE가 들어오고, 추가한 ID가 이어서 재생된다 dismissShortformPlayerModal()로 닫힌다
미션 6 · 딥링크 — 공유 링크로 특정 숏폼 열기
1단계 · URL 규칙
SDK가 로드된 페이지 URL에 아래 파라미터가 있으면, 페이지가 열리는 즉시 그 숏폼의 플레이어가 자동으로 열립니다. 광고 랜딩·푸시·SNS 공유 링크에 그대로 쓸 수 있습니다.
https://my-shop.com/shorts?__sl_shorts_id=SHORTFORM_ID
| 파라미터 | 필수 | 설명 |
|---|---|---|
__sl_shorts_id | 필수 | 열 숏폼 ID |
__sl_cq | 선택 | 재생 목록을 만들 필터 조건(JSON, URL 인코딩). 예: {"tags":["sale"]}. 없으면 해당 숏폼 기준으로 목록 구성 |
2단계 · SDK가 URL을 건드리는 방식
어느 경로로든 플레이어가 열리면 SDK는 현재 URL에 ?__sl_shorts_id=…를 추가하고(pushState), 닫으면 되돌립니다. 덕분에 —
- 재생 중 주소창 URL을 복사해 보내면 받은 사람도 같은 숏폼이 열린 상태로 페이지가 뜹니다.
- 모바일에서 뒤로가기를 누르면 페이지를 떠나지 않고 플레이어만 닫힙니다.
- 플레이어의 공유 버튼이 만드는 URL(이벤트 처리의
ON_CLICK_SHARE_BUTTONpayload.url)도 이 규칙을 따릅니다.
3단계 · 자체 라우터가 있는 SPA라면
disableQueryParamHistory: true를 표시 함수마다
React Router·Vue Router 등이 URL 변화를 감시하는 페이지에서는 SDK의 pushState가 라우터를 자극해 화면이 바뀌거나 플레이어가 닫힐 수 있습니다. 이 경우 플레이어를 열 수 있는 모든 호출 — setShortformCollection · showShortformPreview · showShortformPlayerModal — 에 disableQueryParamHistory: true를 넣어 URL 기록을 끄세요. 이때 1단계의 딥링크 자동 오픈도 함께 꺼지므로, 딥링크가 필요하면 페이지 진입 시 라우터의 쿼리를 읽어 showShortformPlayerModal({ ids: [id] })를 직접 호출합니다.완료 확인
?__sl_shorts_id=…가 붙은 URL을 새 탭에 붙여넣으면 해당 숏폼이 자동으로 열린다- 플레이어가 열린 상태에서 주소창 URL이 바뀌고, 뒤로가기로 플레이어만 닫힌다
- (SPA)
disableQueryParamHistory를 켰다면 URL이 바뀌지 않고 라우터가 반응하지 않는다
이전 ← 미션 5 · 플레이어 — 코드로 직접 열기다음 → 미션 7 · 사용자 정보 연결
미션 7 · 사용자 정보 연결
initShortform() 완료 · (JWT 인증 시) 백엔드 서명 로직 준비 (5단계)사용자 정보를 연결하지 않으면 시청자는 게스트로 처리됩니다. 게스트도 시청·상품 클릭은 가능하지만 댓글처럼 계정이 필요한 기능을 누르면 LOGIN_REQUIRED 이벤트가 발생합니다(이벤트 처리에서 처리). 사용자 정보 함수는 라이브 SDK와 공유합니다(2단계).
setUserObject()·setUserJWT() 는 사용자 정보를 넘기는 것이지, 사용자를 인증하는 것이 아닙니다 로그인(아이디·비밀번호, 소셜 로그인 등)은 전적으로 고객사 사이트가 합니다. 이 함수들은 지금 시청자가 누구인지 Shoplive 에 알려 주기만 해서, 댓글·좋아요·북마크와 시청 통계가 그 회원 기준으로 남게 합니다. Shoplive 는 사용자의 자격 증명을 확인하지 않습니다. JWT 인증은 그 정보가 고객사 서버가 발급했고 바뀌지 않았는지(서명)를 Shoplive 가 확인할 수 있고, 간편 인증(userObject)은 그 확인 없이 정보를 그대로 넘깁니다.1단계 · 로그인 상태에 따라 고르기 — 권장 방식
| 사용자 | 권장 | 이유 |
|---|---|---|
| 비로그인 | 아무것도 호출하지 않음 (게스트) | SDK가 익명 식별자를 자동 발급해 브라우저에 보존하므로 시청 통계는 그대로 집계됩니다. 댓글처럼 계정이 필요한 기능을 누르면 LOGIN_REQUIRED 이벤트가 발생합니다 |
| 로그인 (권장) | setUserJWT() — 서버가 서명한 JWT (JWT 인증) | 고객사 서버에서 서명하므로 클라이언트에서 위변조할 수 없습니다 |
| 로그인 (백엔드 작업이 어려울 때) | setUserObject() — userId·이름 등을 직접 전달 (간편 인증) | 클라이언트 값을 서명 없이 그대로 넘깁니다. 식별·통계에는 충분하지만 권한 검증에는 쓰지 마세요 |
| 로그인 (Cafe24·WISA·고도몰·Shopify 쇼핑몰) | 플랫폼 자동 연동 | 쇼핑몰이 이미 아는 로그인 상태를 SDK가 읽어 갑니다. 위 두 방식과 택일이며, 사용자 정보를 직접 넘기면 그 값이 우선합니다 |
| 로그아웃 · 사용자 정보 초기화 | cloud.shoplive.logout() · 또는 setUserObject(null) / setUserJWT(null) | 설정한 사용자 정보를 지우고 게스트 상태로 돌아갑니다 |
setUserJWT() 를 부르기 직전마다) 백엔드에서 새로 발급한 JWT 를 받아 initShortform({ userJWT }) 또는 setUserJWT() → 로그아웃 시 logout()(또는 null 전달)로 사용자 정보 초기화.
비로그인으로 보여 주다가 게스트가 댓글 등을 누르면 LOGIN_REQUIRED 로 로그인을 유도하는 식으로 써도 됩니다(미션 8).2단계 · 선택한 사용자 정보 연결 방식으로 호출
초기화 시점에 로그인 상태를 이미 알고 있다면 initShortform()에 포함시키고, 로그인이 나중에 확정되는 상황(SPA 등)이라면 setUserObject() / setUserJWT()를 따로 호출합니다. 로그아웃 시 사용자 정보 초기화는 logout() 또는 setUserObject(null) · setUserJWT(null) 입니다. 여기서 쓰는 함수와 값은 라이브 SDK와 완전히 같습니다 — 라이브를 이미 연동했다면 그때 쓴 코드를 그대로 옮겨 오면 됩니다.
<!-- 1. SDK 로드 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
// 2. 로그인 사용자 정보 — 간편 인증은 userId 만 필수
var userObject = {
userId: 'MEMBER_ID', // 필수 — 로그인 사용자의 고유 ID (4단계 해싱 권장). 빈 값이면 게스트
userName: 'NICKNAME' // 선택 — 댓글·프로필에 표시되는 이름
};
// 3. 방법 1 — 초기화 시점에 로그인 상태를 이미 알고 있다면 initShortform() 에 바로 포함
cloud.shoplive.initShortform({
accessKey: 'YOUR_ACCESS_KEY',
userObject: userObject
// JWT 인증이라면 userObject 대신: userJWT: 'USER_JWT' (5단계에서 발급)
});
</script>
<script>
// 3. 방법 2 — 로그인이 나중에 확정된다면(SPA 등) 초기화 이후 따로 호출
// 위 initShortform() 에서는 accessKey 만 넘기고, 로그인 완료 시점에 부릅니다
// cloud.shoplive.setUserObject(userObject);
// cloud.shoplive.setUserJWT('USER_JWT'); // JWT 인증
// 4. 로그아웃 · 사용자 정보 초기화 — 설정한 사용자 정보를 지우고 게스트 상태로 돌아갑니다
// cloud.shoplive.logout();
// 또는 넘긴 값을 null 로: cloud.shoplive.setUserObject(null) / cloud.shoplive.setUserJWT(null)
</script>
라이브 SDK와 같은 함수를 공유합니다. 한 페이지에 라이브 플러그인(shoplive.js)까지 올렸다면 setUserObject · setUserJWT · logout은 두 SDK가 같은 값을 바라봅니다. 어느 쪽에서 호출하든 양쪽에 함께 반영되고, 마지막에 호출한 값이 남습니다. 따로 두 번 호출할 필요 없이 로그인·로그아웃 시점에 한 번만 부르세요.
initShortform({ guestUid })로 고객사가 관리하는 익명 ID를 직접 넘겨 일관성을 유지할 수 있습니다.3단계 · 쇼핑몰 플랫폼을 쓴다면 — 자동 연동 선택
Cafe24·WISA·고도몰·Shopify로 만든 쇼핑몰이라면, setUserObject()를 직접 부르는 대신 initShortform()에 platform만 넘겨 쇼핑몰의 로그인 상태를 읽어 가게 할 수 있습니다. 2단계의 대안이지 2단계에 더하는 작업이 아닙니다.
userObject·userJWT가 없을 때만 플랫폼 자동 연동을 시도합니다. initShortform()에 사용자 정보를 함께 넘겼다면 그 값이 쓰이고 platform은 무시됩니다. 둘 중 하나만 쓰세요.platform 값 | 어떻게 읽어 가나 | 고객사가 페이지에 준비할 것 |
|---|---|---|
'CAFE24' | Cafe24 스킨의 로그인 상태 모듈이 그려 주는 회원 정보를 읽습니다. 값이 늦게 채워지는 스킨이면 채워질 때까지 기다렸다 연결합니다 | 스킨에 로그인 상태 모듈이 없다면 아래 A를 넣습니다 |
'WISA' · 'GODOMALL' | 페이지에 있는 약속된 id의 엘리먼트에서 회원 정보를 읽습니다 | 아래 B의 두 엘리먼트를 직접 출력해야 합니다 |
'SHOPIFY' | 위와 같은 방식으로 읽고, 더해서 플레이어 안 장바구니 기능이 켜집니다 | B + shopify 설정 (부록 C) |
어느 경우든 공통 레이아웃(모든 페이지가 공유하는 머리말 영역)에 넣어, 어떤 페이지로 들어와도 로그인 상태가 잡히게 하는 것이 좋습니다.
<!-- 1. SDK 로드 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<!-- A. Cafe24 — 스킨에 로그인 상태 모듈이 없을 때만 추가합니다.
{$id} {$name} 은 Cafe24 가 로그인 회원의 아이디·이름으로 바꿔 줍니다 -->
<div module="Layout_stateLogon" style="display:none;">{$id} {$name}</div>
<!-- B. WISA · 고도몰 · Shopify — 회원 정보를 이 id 로 출력합니다.
중괄호 안은 쇼핑몰 솔루션이 제공하는 회원 변수로 바꿔 넣으세요
· 고도몰 : {=gSess.memId} / {=gSess.memNm}
· WISA : {{$회원아이디}} / {{$회원명}}
비로그인 상태에서는 값이 비므로 게스트로 동작합니다 -->
<div style="display:none;">
<span id="cloud-shoplive-user-id">MEMBER_ID</span>
<span id="cloud-shoplive-user-name">NICKNAME</span>
</div>
<script>
// 2. platform 만 넘깁니다 — setUserObject 는 호출하지 않습니다
cloud.shoplive.initShortform({
accessKey: 'YOUR_ACCESS_KEY',
platform: 'CAFE24' // 'CAFE24' | 'WISA' | 'GODOMALL' | 'SHOPIFY'
});
</script>
visibility: hidden으로 숨기면 값이 비어 버립니다
회원 정보 엘리먼트를 화면에 보이지 않게 처리할 때, display: none이나 화면 밖으로 밀어내는 방식은 값을 읽는 데 문제가 없지만 visibility: hidden은 빈 문자열로 읽혀 게스트가 됩니다. 또 Cafe24를 제외한 나머지는 초기화 시점에 한 번만 읽으므로, 회원 정보를 스크립트로 나중에 채운다면 initShortform()을 그 뒤에 호출하세요.연결됐는지 확인하려면. 로그인 상태로 플레이어를 열어 댓글에 표시되는 이름을 보면 됩니다. Cafe24에서 회원 정보 영역을 찾지 못하면 콘솔에 Failed - Get Cafe24 account가 남고, 나머지 플랫폼은 엘리먼트가 없으면 조용히 게스트로 남습니다. 자동 연동이 여의치 않으면 2단계처럼 setUserObject()를 직접 호출하면 됩니다.
4단계 · ID 해싱 — 회원 ID 원문을 노출하지 않기
내부 회원 ID를 원문 그대로 넘기지 않으려면, 고객사 서버에서 해싱한 값을 userId로 사용하세요. Shoplive는 원본 ID를 알 수 없지만, 고객사는 같은 알고리즘·salt로 다시 계산해 원래 사용자와 대응시킬 수 있습니다. 같은 사용자가 항상 같은 값이 나오도록(재방문 식별·통계) 일관된 방식으로 처리하면 됩니다. 라이브 SDK와 함께 쓴다면 두 SDK에 같은 해시값을 넘겨야 한 사용자로 집계됩니다.
// Node.js — 고객사 서버에서 해싱합니다 (salt·알고리즘은 항상 같게)
const crypto = require('crypto');
function hashUserId(raw) {
return crypto.createHash('sha256')
.update(raw + 'YOUR_SALT')
.digest('hex');
}
const userId = hashUserId('MEMBER_ID'); // userObject.userId 나 JWT 의 userId 로 씁니다
setUserJWT())를 사용하세요. salt 정책은 Shoplive 팀과 합의된 값을 권장합니다.5단계 · JWT 인증용 토큰 만들기 (고객사 백엔드)
JWT 인증에 쓸 JWT 는 Shoplive 가 발급한 Secret Key 로 고객사 백엔드가 서명합니다. 페이지는 백엔드에서 받은 JWT 를 initShortform({ userJWT }) 나 setUserJWT() 로 넘기기만 합니다.
- Shoplive 담당자에게서 Secret Key 를 받습니다 — base64 로 인코딩된 문자열입니다
- 로그인한 사용자 정보로 아래 payload 를 만들고 HS256 으로 서명합니다
- 페이지가 요청할 때마다(
setUserJWT()를 부르기 직전마다) JWT 를 새로 발급해 내려 줍니다. 브라우저에 JWT 를 저장해 두고 다시 쓰지 않습니다
exp 까지 계속 쓸 수 있습니다. 페이지를 열 때마다, 또는 setUserJWT() 를 부를 때마다 백엔드에서 새 JWT 를 받게 하세요.exp 는 필수입니다
간편 인증의 userObject 에는 없는 필드입니다. JWT 라이브러리가 제공하는 만료 설정 API(아래 예시의 setExpiration · expiresIn)로 지정하세요 — 라이브러리가 exp를 채워 줍니다. 표시 이름은 name·userName 어느 쪽이든 되고, 둘 다 있으면 userName이 우선합니다.| claim | 필수 | 설명 | 예 |
|---|---|---|---|
exp | 필수 | 만료 시각 (Unix 초). 라이브러리의 만료 설정으로 채웁니다 | 1516239022 |
userId | 필수 | 로그인 사용자의 고유 ID. 해시 값을 써도 됩니다(4단계). 없으면 콘솔에 Invalid JWT - Empty userId가 찍히고 토큰이 무시됨 | MEMBER_ID |
iat | 선택 | 발급 시각 (Unix 초) | 1516195822 |
name 또는 userName | 선택 | 댓글·프로필에 표시되는 이름. 둘 다 있으면 userName 우선. 금칙어는 *로 대체되어 표시 | NICKNAME |
gender | 선택 | 성별 — m · f · 빈 값(미지정) | f |
age | 선택 | 나이. 통계에는 5세 단위로 그룹화되어 표시됨 | 27 |
userScore | 선택 | 사용자 등급 (-100 ~ 100). 이벤트 추첨 제한 등의 기준 | 10 |
userType | 선택 | 입장 제한(Entry Type) 설정 시 참조되는 값 | VIP |
profile | 선택 | 채팅 목록 프로필 이미지 URL, 권장 64x64px | https://…/profile.png |
custom | 선택 | 자유 형식 데이터, 최대 1KB | {"grade":"vip"} |
숏폼 SDK 가 토큰에서 직접 읽는 것은 userId·표시 이름·exp 입니다. 나머지 클레임은 라이브 SDK 와 같은 JWT 체계를 따릅니다. 한 페이지에서 라이브 플레이어도 쓴다면 setUserJWT() 로 넘긴 토큰 하나를 두 SDK 가 함께 쓰므로, 라이브에서 쓰는 클레임(userScore·userType 등)도 같은 토큰에 넣으세요.
서명하기
서명 예시입니다. 두 코드는 같은 토큰을 만듭니다 — Secret Key 가 base64 문자열이라 라이브러리에 따라 그대로 넣을지 디코딩해서 넣을지가 다르다는 점만 주의하세요.
// Java — jjwt. signWith 이 base64 문자열을 알아서 디코딩합니다
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
String base64EncodedSecretKey = "YOUR_BASE64_SECRET_KEY"; // Shoplive 담당자가 전달
long expiration = System.currentTimeMillis() + 12 * 60 * 60 * 1000L; // 12시간
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey)
.setExpiration(new Date(expiration))
.setIssuedAt(new Date())
.claim("userId", "MEMBER_ID") // 필수
.claim("name", "NICKNAME") // 선택 — 표시 이름
.claim("userScore", 10) // 선택
.claim("userType", "VIP") // 선택
.compact();
// Node.js — jsonwebtoken. secretKey 를 직접 디코딩해서 넘겨야 합니다
const jwt = require('jsonwebtoken');
const base64EncodedSecretKey = 'YOUR_BASE64_SECRET_KEY'; // Shoplive 담당자가 전달
const secret = Buffer.from(base64EncodedSecretKey, 'base64'); // ← 디코딩 필요
const token = jwt.sign(
{
userId: 'MEMBER_ID', // 필수
name: 'NICKNAME', // 선택 — 표시 이름
userScore: 10, // 선택
userType: 'VIP' // 선택
},
secret,
{ algorithm: 'HS256', expiresIn: '12h' }
);
userId로 다른 사용자로 위장한 토큰을 만들 수 있습니다. 브라우저에서 번들되는 코드나 공개 저장소에 넣지 말고, 반드시 고객사 서버에서만 서명한 뒤 완성된 토큰만 프런트로 내려보내세요. 간편 인증(setUserObject())은 서명이 없어 권한 검증에 쓸 수 없습니다.완료 확인
- 로그인 후 플레이어에서 댓글을 작성하면 지정한 이름으로 표시된다
- 게스트 상태에서 댓글 입력을 시도하면
LOGIN_REQUIRED이벤트가 발생한다 (기본 동작은 안내alert) logout()(또는null전달)으로 사용자 정보를 초기화하면 다시 게스트로 동작한다
미션 8 · 이벤트 · 상품 클릭 · 데이터 수집
initShortform() 완료 · 상품 클릭을 다룬다면 Admin에서 숏폼에 상품 연결 완료숏폼 SDK의 이벤트 처리는 목적이 다른 두 채널로 나뉩니다. 무엇을 하려는지에 따라 하나 또는 둘 다 사용합니다.
1단계 · 어느 채널을 쓸지 고르기
| 구분 | messageCallback — 동작 바꾸기 | addShortformEventListener — 관찰하기 |
|---|---|---|
| 등록 위치 | initShortform({ messageCallback: { 이벤트명: fn } }) | cloud.shoplive.addShortformEventListener(fn) (여러 개 등록 가능) |
| 함수 형태 | (payload) => void — 이벤트별로 함수 하나 | (eventName, payload) => void — 모든 이벤트가 한 함수로 |
| 기본 동작 | 고객사가 등록한 함수가 기본 동작을 대체합니다. 예: 상품 클릭 시 SDK의 페이지 이동 대신 고객사 코드 실행 | 기본 동작은 그대로 실행되고, 알림만 받습니다 |
| 대표 활용처 | 로그인 페이지로 보내기 · 상품 클릭을 SPA 라우터로 처리 · 공유 UI 커스텀 | GA·Amplitude 등 애널리틱스 전송 · 시청 시간 집계 |
2단계 · 기본 동작 바꾸기 — messageCallback
아래 7개 이벤트는 SDK에 기본 동작이 있습니다. 바꾸고 싶은 것만 등록하세요 — 등록하지 않은 이벤트는 기본 동작이 그대로 실행됩니다.
| 이벤트 | 언제 | 기본 동작 | payload 주요 필드 |
|---|---|---|---|
PLAY_SHORTFORM_DETAIL | 숏폼을 눌러 재생이 시작되는 순간 | 전체 화면 플레이어 모달을 엶 | shorts · shortsId · muted · shortsCollection |
PLAY_SHORTFORM_DETAIL — 모달 대신 자체 페이지로 보내는 등 진입 자체를 바꿀 때 씁니다. 숏폼 ID는 딥링크 진입이면 shortsId, 그 밖에는 shorts.shortsId에 실리므로 payload.shorts?.shortsId || payload.shortsId로 읽으세요. 이 이벤트만 리스너(3단계)로는 전달되지 않으니, 재생 시작을 관찰만 하려면 DETAIL_ON_PLAYER_SHOW를 쓰세요. | |||
CLOSE_SHORTFORM_DETAIL | 플레이어를 닫을 때 — 닫기(✕) 버튼 · 아래로 쓸어내림 · 브라우저 뒤로가기 | 플레이어를 닫고, 열릴 때 추가했던 URL 쿼리를 되돌립니다 | triggeredBrowserBack |
CLOSE_SHORTFORM_DETAIL — 플레이어를 벗어날 때 고객사 화면을 되돌리거나(SPA 라우팅) 닫힘을 집계할 때 씁니다. 브라우저 뒤로가기로 닫힌 경우에만 payload.triggeredBrowserBack이 true이고, 이때는 이미 히스토리가 이동한 뒤라 SDK도 history.back()을 부르지 않습니다. 닫힘을 관찰만 하려면 DETAIL_ON_PLAYER_DISMISS를 쓰세요. | |||
LOGIN_REQUIRED | 게스트가 댓글 등 로그인 필요 기능을 누름 | 안내 alert | type (예: 'comment') |
ON_CLICK_PRODUCT_ITEM | 플레이어의 상품 카드·상품 목록 항목 클릭 | location.href = payload.product.url | product(상품) · shorts(숏폼) |
ON_CLICK_PRODUCT_BANNER | 상품 배너 클릭 | location.href = payload.scheme | scheme |
ON_CLICK_LINK_BUTTON | 링크 버튼 클릭 | location.href = payload.scheme | scheme |
ON_CLICK_SHARE_BUTTON | 공유 버튼 클릭 | OS 공유 시트(navigator.share) → 없으면 URL 클립보드 복사 | url · shorts |
ON_CLICK_PRODUCT_ITEM 의 payload.product.url 과 ON_CLICK_PRODUCT_BANNER · ON_CLICK_LINK_BUTTON 의 payload.scheme 끝에 csl_bp=1 이 자동으로 붙습니다. 다음 페이지에서도 PIP 를 이어 가기 위한 표식입니다.
이 URL 을 고객사 로직에서 가공한다면 모르는 파라미터가 섞여 들어올 수 있다는 점을 감안하세요 — 지우면 이동한 페이지에서 PIP 가 끊깁니다. 지금 페이지의 주소에
csl_bp 가 있을 때만 붙으므로, 평소에는 원래 URL 그대로입니다.cloud.shoplive.initShortform({
accessKey: 'YOUR_ACCESS_KEY',
messageCallback: {
// 게스트가 로그인 필요 기능을 눌렀을 때 → 고객사 로그인 페이지로
LOGIN_REQUIRED: function (payload) {
location.href = '/login?returnTo=' + encodeURIComponent(location.href);
},
// 상품 클릭 → 새 탭 대신 SPA 라우터로 이동 (기본 동작인 location.href 를 대체)
ON_CLICK_PRODUCT_ITEM: function (payload) {
var product = payload.product; // productId, name, url, sku, discountPrice …
myRouter.push('/products/' + product.sku);
cloud.shoplive.dismissShortformPlayerModal();
},
// 공유 → 고객사 공유 UI 사용
ON_CLICK_SHARE_BUTTON: function (payload) {
openMyShareSheet({ title: payload.shorts.shortsDetail.title, url: payload.url });
}
}
});
이 7개 말고 다른 이벤트를 다루고 싶다면. 위 표는 SDK에 기본 동작이 있어 바꿀 수 있는 이벤트이고, 숏폼이 보내는 이벤트는 이보다 훨씬 많습니다. 좋아요·북마크·댓글·태그 클릭처럼 기본 동작이 없는 이벤트는 바꿀 것이 없으므로 3단계의 리스너로 관찰합니다. 어떤 이벤트가 오는지는 레퍼런스 · 이벤트 사전에서 전체 목록을 확인하세요.
3단계 · 관찰하기 — addShortformEventListener
등록한 함수는 이벤트 사전의 트래킹·알림 이벤트를 전부 받습니다. 이벤트 이름으로 분기해 필요한 것만 애널리틱스로 보내세요. 이름은 영역_동작 규칙이라 접두어로 묶어 처리하기 쉽습니다.
cloud.shoplive.addShortformEventListener(function (eventName, payload) {
switch (eventName) {
case 'COLLECTION_CLICK_ITEM': // 목록에서 카드 클릭
case 'DETAIL_CLICK_PRODUCT_CARD': // 플레이어에서 상품 카드 클릭
case 'DETAIL_CLICK_LIKE':
case 'DETAIL_CLICK_SHARE':
analytics.track('shoplive_' + eventName.toLowerCase(), payload);
break;
case 'VIDEO_TOTAL_VIEWING_TIME': // 숏폼 하나를 떠날 때 누적 시청 시간
analytics.track('shortform_watch', {
shortsId: payload.shortsId,
seconds: payload.totalViewingTime,
duration: payload.videoDuration
});
break;
}
});
4단계 · 시청 시간과 세션
| 수단 | 설명 |
|---|---|
VIDEO_TOTAL_VIEWING_TIME 이벤트 | 시청자가 숏폼 하나를 떠날 때(다음으로 넘기거나 닫을 때) 누적 시청 시간을 전달 — shortsId · totalViewingTime(초) · videoDuration · videoDurationText |
getShortformTotalViewingTime() | 현재 재생 중인 숏폼의 누적 시청 시간을 즉시 읽음 (같은 필드) |
setShortformSessionId(id) | 고객사 세션 ID를 시청 로그에 함께 남겨 자체 분석 데이터와 매칭 |
shoplive.js)의 sendConversionEvent가 담당합니다. 붙이는 방법은 미션 9 · 구매 전환 트래킹에서 이어집니다.완료 확인
- 등록한
messageCallback이벤트에서 기본 동작 대신 고객사가 등록한 함수가 실행된다 (예: 상품 클릭 시 페이지가 새로 로드되지 않고 라우터로 이동) - 등록하지 않은 이벤트(예: 공유)는 기본 동작이 그대로 동작한다
- 리스너에서
COLLECTION_CLICK_ITEM→DETAIL_ON_PLAYER_SHOW→VIDEO_TOTAL_VIEWING_TIME순으로 이벤트가 들어온다
이전 ← 미션 7 · 사용자 정보 연결다음 → 미션 9 · 구매 전환 트래킹
미션 9 · 구매 전환 트래킹 — 시청이 구매로 이어졌는지
userId시청자가 상품을 눌러 상품 페이지로 이동하는 순간 숏폼 SDK의 추적은 끝납니다. 그 뒤 결제가 성사됐는지는 고객사 페이지에서만 알 수 있으므로, 구매 완료 시점에 직접 한 번 알려주어야 "이 숏폼이 매출을 얼마나 만들었는가"가 집계됩니다.
sendConversionEvent()는 숏폼 번들이 아니라 라이브 플러그인 shoplive.js에 들어 있습니다. 구매 완료 페이지에는 숏폼을 띄울 일이 없으므로 shoplive-shortform.js는 필요 없고, 이 한 줄만 넣으면 됩니다. Access Key는 숏폼과 같은 키입니다.1단계 · 어디에 넣나
주문이 확정된 뒤 한 번만 열리는 페이지 — 보통 주문 완료·결제 완료 페이지입니다. 장바구니나 결제 진행 화면에 넣으면 이탈한 주문까지 구매로 집계되고, 새로고침으로 여러 번 열리는 페이지에 넣으면 같은 주문이 중복 보고됩니다.
2단계 · 구매 완료 보고
SDK 로드 → 초기화 → 사용자 정보 → 보고 순서입니다. 초기화가 끝나기 전에 sendConversionEvent()를 불러도 SDK가 대기시켰다가 실행하므로 순서 때문에 실패하지는 않습니다.
<!-- 1. 라이브 플러그인 로드 — 숏폼 번들(shoplive-shortform.js)이 아닙니다 -->
<script src="https://static.shoplive.cloud/shoplive.js"></script>
<script>
// 2. 초기화 — 숏폼과 같은 Access Key
cloud.shoplive.initPlugin({ accessKey: 'YOUR_ACCESS_KEY' });
// 3. 로그인 사용자라면 시청할 때와 "같은" userId 를 넣습니다 (3단계 참고)
cloud.shoplive.setUserObject({ userId: 'MEMBER_ID' });
// 4. 구매 완료 보고
cloud.shoplive.sendConversionEvent({
accessKey: 'YOUR_ACCESS_KEY', // 필수
eventType: 'purchase', // 필수
orderId: 'UNIQUE_ORDER_ID', // 주문번호 — 중복 보고를 가려내는 데 쓰입니다
products: [
{ sku: 'PRODUCT_SKU_1', purchaseUnitPrice: 10000, purchaseQuantity: 1 },
{ sku: 'PRODUCT_SKU_2', purchaseUnitPrice: 15000, purchaseQuantity: 2 }
]
});
</script>
| 필드 | 필수 | 설명 |
|---|---|---|
accessKey | 필수 | 숏폼과 같은 키. 초기화에 넘겼더라도 이 객체에 다시 넣어야 합니다 — 없으면 콘솔에 Invalid request만 찍히고 전송되지 않습니다 |
eventType | 필수 | 구매 완료는 'purchase'. 장바구니 담기 시점을 따로 보고하는 'cartIn' 값도 있으나, 집계에 어떻게 반영되는지는 Shoplive 담당자와 확인하세요 |
orderId | 선택 | 고객사 주문번호 |
products | 선택 | 구매한 상품 배열. 공식 가이드 예제는 sku · purchaseUnitPrice · purchaseQuantity를 사용합니다. 이 밖에 productId · customerProductId · currency를 함께 보낼 수 있습니다 |
timestamp | 선택 | 구매 시각. 넣지 않으면 호출 시각이 쓰입니다 |
custom | 선택 | 고객사가 함께 남기고 싶은 임의 값 |
예전 자료에서 init()을 보셨다면. 초기화를 cloud.shoplive.init()으로 적어 둔 예제가 남아 있습니다. 이 함수는 initPlugin()의 옛 이름(deprecated)이고 동작은 같으니, 새로 작성한다면 initPlugin()을 쓰세요.
3단계 · 시청 기록과 이어 붙는 기준
보고한 구매는 시청 기록과 같은 사람으로 인식돼야 전환으로 집계됩니다. 기준은 로그인 여부에 따라 둘로 나뉩니다.
| 구분 | 이어 붙는 기준 | 고객사가 맞춰야 할 것 |
|---|---|---|
| 로그인 사용자 | userId | 숏폼을 볼 때 미션 7 · 사용자 정보 연결로 넘긴 값과 완전히 같은 값을 구매 완료 페이지에서도 넘깁니다. 해싱했다면 같은 해시값이어야 합니다 |
| 비로그인(게스트) | 브라우저에 저장된 익명 식별자 | 호출할 것은 없지만 같은 브라우저 · 같은 도메인이어야 합니다 (아래 주의) |
localStorage에 저장되고, localStorage는 도메인별로 분리됩니다. 숏폼을 보여준 페이지와 구매 완료 페이지의 도메인이 다르면(예: www.shop.com에서 보고 order.shop.com에서 결제) 같은 사람으로 이어지지 않습니다. 도메인을 맞추기 어렵다면 로그인 사용자 기준(userId)으로 집계하는 것이 확실합니다.완료 확인
- 구매 완료 페이지에서 네트워크 탭에
/conversion/event요청이 한 번 기록된다 - 새로고침·뒤로가기로 같은 주문이 여러 번 보고되지 않는다
- (로그인) 요청이 나갈 때의
userId가 숏폼을 볼 때 넘긴 값과 같다 - 집계 결과는 Shoplive Admin의 전환 리포트에서 확인합니다 — 반영에 시간이 걸릴 수 있으니 수치가 바로 보이지 않으면 담당자에게 문의하세요
이전 ← 미션 8 · 이벤트 · 상품 클릭 · 데이터 수집다음 → 전체 예제
전체 예제 — 컬렉션 · 플레이어 열기 · 사용자 정보 · 이벤트를 한 페이지에
숏폼 탭 페이지 하나에 목록·버튼으로 열기·사용자 인증·이벤트 처리를 모두 적용한 형태입니다. 그대로 복사해 YOUR_* 값만 바꾸면 동작합니다. 상품 상세 페이지라면 여기에 프리뷰 또는 쇼케이스 호출 한 줄을 더하면 됩니다.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
<!-- 1. SDK 로드 — cloud.shoplive 를 쓰는 코드보다 앞에 -->
<script src="https://static.shoplive.cloud/shoplive-shortform.js"></script>
<script>
// 2. 초기화 + 기본 동작 재정의 (이벤트 처리)
cloud.shoplive.initShortform({
accessKey: 'YOUR_ACCESS_KEY',
messageCallback: {
LOGIN_REQUIRED: function () {
location.href = '/login?returnTo=' + encodeURIComponent(location.href);
},
ON_CLICK_PRODUCT_ITEM: function (payload) {
location.href = payload.product.url; // 기본 동작과 같지만, 여기서 UTM 추가 등 가공 가능
}
}
});
// 3. 로그인 사용자라면 연결 (사용자 정보) — 게스트라면 생략
var loginUserId = 'YOUR_HASHED_USER_ID';
if (loginUserId) {
cloud.shoplive.setUserObject({ userId: loginUserId, userName: 'YOUR_USER_NAME' });
}
// 4. 애널리틱스 전송 (이벤트 처리)
cloud.shoplive.addShortformEventListener(function (eventName, payload) {
if (eventName === 'COLLECTION_CLICK_ITEM' || eventName === 'VIDEO_TOTAL_VIEWING_TIME') {
console.log('[shoplive]', eventName, payload); // → analytics.track(...)
}
});
</script>
</head>
<body>
<header>고객사 사이트 헤더</header>
<!-- 5. 목록 노출 (컬렉션) -->
<div id="shoplive-shortform-area"></div>
<script>
cloud.shoplive.setShortformCollection('shoplive-shortform-area', {
template: 'GRID2',
hasMoreButton: false // 무한 스크롤
});
</script>
<!-- 6. 특정 숏폼으로 바로 열기 (플레이어 열기) -->
<button onclick="cloud.shoplive.showShortformPlayerModal({ ids: ['YOUR_SHORTFORM_ID'] })">
이번 주 추천 영상 보기
</button>
</body>
</html>
이전 ← 미션 9 · 구매 전환 트래킹다음 → 부록
부록 · 특정 상황에서만
위 미션에 들어가지 않는, 특정 상황에서만 필요한 기능입니다.
A. 인라인 플레이어 뷰 — 모달 대신 고객사 영역에
플레이어를 전체 화면 모달이 아니라 페이지의 특정 div 안에 그리고 싶을 때(예: 데스크톱에서 좌측 목록·우측 플레이어 레이아웃) 사용합니다. 한 번 호출하면 이후 컬렉션 클릭도 모달 대신 이 영역에서 재생됩니다.
// 컨테이너는 width·height 가 있어야 합니다 (없으면 SDK가 100%로 채움)
cloud.shoplive.setShortformPlayerView('my-player-area', { tags: ['sale'], muted: true });
// 같은 영역의 콘텐츠만 교체
cloud.shoplive.replaceShortformPlayerView({ ids: ['SHORTFORM_ID'] });
// 제거 — 사용 중이던 컨테이너 id 를 반환
var containerId = cloud.shoplive.destroyShortformPlayerViewAndGetContainerId();
setShortformPlayerView는 다른 표시 함수와 달리 컨테이너 존재를 먼저 확인합니다. <head>에서 호출하면 컨테이너를 찾지 못해 조용히 종료되니, 컨테이너 div 뒤에 두거나 DOMContentLoaded 이후에 호출하세요.B. 커스텀 숏폼 — 고객사 데이터로 플레이어 구성
Shoplive 숏폼 ID에 고객사가 가진 메타데이터(제목·크리에이터·좋아요 수·외부 상품 등)를 덧씌워 재생합니다. 자체 커뮤니티나 크리에이터 시스템을 가진 고객사가 인라인 플레이어 뷰(A)와 함께 쓰는 고급 기능이라, 적용 전 Shoplive 담당자와 협의하세요.
| 함수 | 설명 |
|---|---|
appendCustomShortforms({ customShortforms: [...] }) | 목록이 비어 있으면 새로 만들고, 있으면 이어 붙임 |
setCustomShortform(customShortform) | 특정 shortsId의 데이터 갱신 (좋아요 토글 등) |
removeShortform({ shortsIds: [...] }) | 목록에서 제거 |
객체 필드는 필드 사전 · 커스텀 숏폼 객체을 참고하세요. extra에 넣은 값은 이벤트 payload에 그대로 돌아오므로 고객사 식별자를 실어 보낼 수 있습니다.
C. Shopify — 플레이어 안에서 장바구니 담기
Shopify 스토어라면 platform: 'SHOPIFY'와 shopify 옵션을 주면 상품 카드 클릭 시 페이지 이동 대신 플레이어 안에서 옵션 선택 → 수량 → 장바구니 추가까지 처리됩니다.
cloud.shoplive.initShortform({
accessKey: 'YOUR_ACCESS_KEY',
platform: 'SHOPIFY',
shopify: {
cartLink: '/cart', // 장바구니 이동 링크
customUISections: ['shopify-section-cart-drawer'] // 담기 후 갱신할 테마 섹션 id (선택)
}
});
shopify 필드 | 설명 |
|---|---|
cartLink | 장바구니로 이동할 링크. 미지정 시 테마 기본 장바구니 동작을 따릅니다 |
customUISections | 담기 성공 후 다시 그릴 테마 섹션 id 배열. 지정하지 않으면 cart-drawer · cart-icon-bubble · cart-notification · cart-drawer-items · cart-drawer-footer를 갱신합니다. 테마가 다른 이름을 쓴다면 그 id 를 넣으세요 — <section id="shopify-section-custom-bubble">라면 'custom-bubble'처럼 shopify-section- 접두어를 뺀 값입니다 |
tax | 옵션 선택 UI의 가격에 소비세를 더해 보여줍니다 — { displayTaxIncluded: true, taxRate: 0.1 }(10%). 두 값이 모두 있어야 적용되며 taxRate가 0이면 무시됩니다 |
// 세금 포함가로 보여줘야 하는 스토어라면
cloud.shoplive.initShortform({
accessKey: 'YOUR_ACCESS_KEY',
platform: 'SHOPIFY',
shopify: {
tax: {
displayTaxIncluded: true, // 가격에 소비세를 더해 표시
taxRate: 0.1 // 소비세율 10%
}
}
});
세금 가산 후 절사 규칙. 소수점을 쓰지 않는 통화(KRW · JPY · THB · IDR · INR · CLP · MMK · VND · PKR)는 정수로 버림하고, 그 밖의 통화는 소수점 두 자리까지 남기고 버립니다. 이 값은 표시 전용이며 실제 결제 금액은 Shopify가 계산합니다.
Shopify는 코드를 넣는 자리가 테마 파일이라 흐름이 조금 다릅니다. 아래 순서로 진행합니다.
Layout → theme.liquid에 SDK 로드와 initShortform()을 넣습니다. 모든 페이지에서 한 번만 실행되도록 테마 레이아웃에 두는 것이 핵심입니다.
</>)로 바꾼 뒤, 컨테이너 <div>와 컬렉션 호출을 넣습니다. 테마에서 이미 초기화했으므로 여기서는 표시 함수만 부르면 됩니다.D. SPA에서 쓰기
initShortform({ isSPA: true })— 클라이언트 라우팅으로 페이지가 바뀌어도 SDK를 유지합니다.initShortform은 한 페이지 수명에서 한 번만 동작하며 두 번째 호출은 무시됩니다.- 컴포넌트가 사라질 때
destroyShortformCollection(id)/hideShortformPreview()를 호출해 정리하세요. 컨테이너 DOM만 제거하면 SDK 내부에는 인스턴스가 남습니다. - 라우터가 URL 변화를 감시한다면 표시 함수마다
disableQueryParamHistory: true를 주세요 (딥링크).
E. 라이브 SDK와 같은 페이지에서 쓰기
두 스크립트를 모두 로드하고 initPlugin·initShortform을 각각 호출합니다. 로드 순서는 상관없습니다 — 뒤에 로드되는 쪽이 앞의 cloud.shoplive 객체에 자기 함수를 추가합니다. setUserObject·setUserJWT·logout은 공유 함수라 한 번만 호출하면 두 SDK에 모두 반영됩니다. 라이브 미니 프리뷰와 숏폼 프리뷰가 같은 모서리에 겹치지 않도록 SDK가 위치를 조정합니다.
F. RequireJS / AMD 환경
페이지가 RequireJS로 모듈을 관리한다면 initShortform({ useAMD: true, AMDLoader: require })처럼 로더를 넘겨 SDK가 그 로더로 내부 모듈을 불러오게 합니다. 일반 <script> 로드 환경에서는 필요 없습니다.
G. 고객사 앱 웹뷰 안에서 띄우기 — 영상이 재생되려면
숏폼을 붙인 웹 페이지를 고객사 앱의 웹뷰로 여는 경우(하이브리드 앱), 웹뷰 쪽 설정을 바꾸지 않으면 영상이 재생되지 않거나 전체 화면으로 튀어나갑니다. SDK는 <video playsinline muted>로 인라인 자동재생을 시도하는데, 웹뷰의 기본값이 이를 막기 때문입니다. 아래는 앱 코드에서 한 번만 설정하면 됩니다.
| 플랫폼 | 설정 | 안 하면 |
|---|---|---|
iOS (WKWebView) | configuration.allowsInlineMediaPlayback = true | 재생이 시작되는 순간 네이티브 전체 화면 플레이어로 전환돼 숏폼 UI가 사라집니다 |
Android (WebView) | settings.mediaPlaybackRequiresUserGesture = false | 시청자가 직접 탭하기 전까지 자동재생이 시작되지 않습니다 — 컬렉션 카드·프리뷰가 정지 화면으로 보입니다 |
// iOS — WKWebView 를 만들 때
let configuration = WKWebViewConfiguration()
configuration.allowsInlineMediaPlayback = true
let webView = WKWebView(frame: rect, configuration: configuration)
// Android — WebView 생성 후
webView.settings.mediaPlaybackRequiresUserGesture = false
함수 색인
cloud.shoplive.*에서 웹 연동에 쓰는 함수 전체를 진입 경로별로 묶었습니다. 이름을 알고 있을 때 어느 문서를 볼지 찾는 용도입니다.
| 묶음 | 함수 | 가이드 |
|---|---|---|
| 초기화 | initShortform(config) | 빠른 시작 · 필드 |
| 목록 | setShortformCollection(containerId, config?) · destroyShortformCollection(containerId?) | 컬렉션 |
| 프리뷰 | showShortformPreview(config?) · hideShortformPreview() | 프리뷰 |
| 쇼케이스 | setShortformShowcase(containerId, config?) | 쇼케이스 |
| 스토리 | setShortformStory(containerId, config?) · destroyShortformStory(containerId?) | 스토리 |
| 플레이어 열기·제어 | showShortformPlayerModal(config?) · dismissShortformPlayerModal() · shortformPlayerAppendList({ ids | shortforms }) · setShortformGlobalMuteState(bool) · getShortformGlobalMuteState() | 플레이어 열기 |
| 사용자 | setUserObject(user | null) · setUserJWT(jwt | null) · logout() | 미션 7 · 사용자 정보 연결 |
| 이벤트 | addShortformEventListener(fn) · removeShortformEventListener(fn) · (init 옵션) messageCallback | 이벤트 처리 |
| 시청 데이터 | getShortformTotalViewingTime() · setShortformSessionId(id?) | 이벤트 처리 · 시청 시간과 세션 |
| 인라인 플레이어 | setShortformPlayerView(containerId, config?) · replaceShortformPlayerView(config?) · destroyShortformPlayerViewAndGetContainerId() | 부록 A |
| 커스텀 숏폼 | appendCustomShortforms({ customShortforms }) · setCustomShortform(obj) · removeShortform({ shortsIds }) | 부록 B |
이 표에 없는 이름이 cloud.shoplive에 보인다면 모바일 앱 SDK 연동용이거나 예전 이름입니다. 웹 연동에서는 사용하지 않습니다.
이전 ← 부록다음 → 설정 객체 필드 사전
설정 객체 필드 사전
각 함수에 넘기는 설정 객체에 어떤 값을 넣을 수 있는지 모아 둔 목록입니다. accessKey를 빼면 대부분 선택 항목이라, 필요한 것만 넣고 나머지는 비워 두면 기본값 또는 계정 설정값으로 동작합니다.
containerId는 숏폼 ID가 아니라 고객사 페이지 DOM 요소의 id입니다
아래 컬렉션 · 쇼케이스 · 인라인 플레이어 뷰 세 함수는 고객사가 페이지에 미리 만들어 둔 빈 요소 안에 화면을 그립니다. 그래서 첫 번째 인자로 넘기는 값은 그릴 자리인 <div>의 id 속성값입니다 — Admin에서 보는 숏폼 ID가 아닙니다. CSS 선택자가 아니라 document.getElementById()로 찾으므로 #은 붙이지 않습니다.<!-- 1. 숏폼이 그려질 빈 요소를 만들고 id 를 붙입니다 -->
<div id="shortform-area"></div>
<script>
// 2. 그 id 문자열을 첫 번째 인자로 넘깁니다 ('#shortform-area' 아님)
cloud.shoplive.setShortformCollection('shortform-area');
</script>
그 id를 가진 요소를 찾지 못하면 콘솔에 Invalid containerId를 남기고 아무것도 그리지 않습니다. 반대로 프리뷰와 플레이어 모달은 SDK가 화면 위에 직접 띄우므로 이 인자가 없습니다.
초기화 — initShortform(config)
| 필드 | 필수 | 설명 |
|---|---|---|
accessKey | 필수 | Shoplive에서 발급한 고객사 식별 키 |
userObject / userJWT | 선택 | 로그인 사용자 정보. 이후 setUserObject / setUserJWT로 변경 가능 (미션 7 · 사용자 정보 연결) |
guestUid | 선택 | 비로그인 사용자 식별 ID. 미설정 시 SDK가 발급해 브라우저에 보존 |
messageCallback | 선택 | 이벤트별 기본 동작 재정의 함수 맵 (이벤트 처리) |
platform | 선택 | 쇼핑몰의 로그인 상태를 SDK가 읽어 가게 합니다 — 'CAFE24' · 'WISA' · 'GODOMALL' · 'SHOPIFY'. 값에 따라 페이지에 준비할 것이 다르므로 사용자 정보 연결 · 플랫폼 자동 연동을 함께 보세요 |
shopify | 선택 | Shopify 전용 — cartLink · customUISections[] |
isSPA | 선택 | true면 페이지 전환 시 SDK를 재초기화하지 않고 유지 (부록 D) |
useAMD / AMDLoader | 선택 | RequireJS 환경 (부록 F) |
customerDeviceId | 선택 | 고객사가 쓰는 기기 식별 ID. 넣으면 SDK가 보내는 모든 요청에 같은 값이 함께 실려, 고객사 로그와 Shoplive 기록을 기기 단위로 맞춰 볼 수 있습니다 |
anonId | 선택 | 고객사가 관리하는 비로그인 식별자. 구매 전환 집계에 함께 쓰입니다. 페이지 URL에 ?anonId=로 넘겨도 동일하게 인식됩니다 |
gaId | 선택 | Google Analytics 클라이언트 ID. 넣어 두면 Shoplive 기록과 GA 데이터를 같은 사용자로 맞출 수 있습니다. ?gaId= 쿼리도 동일 |
ceId | 선택 | 전환 집계에 쓰는 익명 식별자. 넣지 않는 것이 기본이며, SDK가 브라우저에 자동 생성·보존합니다. 고객사가 자체 식별자로 덮어써야 할 때만 지정하세요 (전환 · 이어 붙는 기준) |
useWebVideoPlayer | 선택 | true면 HLS 대신 브라우저 기본 비디오 재생을 사용합니다. 특정 환경에서 재생이 되지 않을 때의 대응책이므로, 평소에는 넣지 마세요 |
여기에 없는 값을 코드에서 보셨다면. 모바일 앱 웹뷰에서 SDK를 띄울 때 앱이 넘기는 값(광고 식별자 등)이거나, 특정 고객사와 개별 협의된 값, 또는 Shoplive 개발용 값입니다. 웹 페이지에 직접 연동할 때는 쓰지 않습니다.
필터 공통 필드 — 어떤 숏폼을 가져올지
컬렉션 · 플레이어 모달 · 프리뷰 · 인라인 플레이어 뷰에서 공통으로 쓸 수 있는 필드입니다. 아래 각 함수 표에는 이 필드에 더해 그 함수에만 있는 것을 적었습니다.
| 필드 | 타입 | 설명 |
|---|---|---|
tags | string[] | 태그 필터 |
tagSearchOperator | 'OR' | 'AND' | 태그 매칭 방식 |
brands | string[] | 브랜드 식별자 필터 |
skus | string[] | 연결 상품 SKU 필터 |
shortformCollectionId | string | Admin 그룹 ID |
shuffle | boolean | 랜덤 순서 |
sortProperty / sortDirection | string | 정렬 기준 / 방향('asc' | 'desc'). 값은 컬렉션 · 필터 참고. 미지정 시 Admin 정렬 순서 |
컬렉션 — setShortformCollection(containerId, config)
필터 공통 필드에 더해 아래를 넣을 수 있습니다.
| 필드 | 기본값 | 설명 |
|---|---|---|
template | 'GRID1' | 'GRID1' · 'GRID2' · 'HORIZONTAL' |
hasMoreButton | true | 더보기 버튼. false면 무한 스크롤 (컬렉션 · 더 불러오기 정책) |
rows | 2 | 초기 표시 행 수 |
limit | — | 최대 숏폼 수 |
displayTags | — | 상단 필터 탭 태그 목록 |
productLayout | 'CIRCLE' | 'CIRCLE' · 'CARD'. 계정 설정이 있으면 그 값이 우선 |
disablePreviewVideoPlay | false | 카드 호버 시 미리보기 재생 끄기 |
previewVideoAutoPlayType | — | 'intersection' — 뷰포트 진입 시 재생 |
horizontalOption | — | hasDirectionWhenHorizontal · lineItemCount · autoFlow · insideDescription(제목·설명을 카드 안에) · scrollIndicator(목록 아래 스크롤 진행 바) — 컬렉션 · 표시 옵션 |
showProduct | false | 카드 아래에 연결 상품 최대 2개 + 상품 더보기 (컬렉션 · 표시 옵션) |
enableGestureSlide | true | 드래그/스와이프 허용 |
disableQueryParamHistory | false | URL 쿼리 기록 끄기 |
플레이어 모달 — showShortformPlayerModal(config)
필터 공통 필드에 더해 아래를 넣을 수 있습니다. ids 또는 shortforms가 있으면 필터 필드는 무시됩니다.
| 필드 | 설명 |
|---|---|
ids | 재생할 숏폼 ID 배열 (순서 유지) |
startIndex | ids 중 시작 위치 (0부터). 범위를 넘으면 0 |
shortsId | 필터 모드에서 시작할 숏폼 ID |
muted | 초기 음소거 |
disableQueryParamHistory | URL 쿼리 기록 끄기 |
프리뷰 — showShortformPreview(config)
필터 공통 필드에 더해 아래를 넣을 수 있습니다. 필터 필드를 하나도 주지 않으면 현재 페이지 URL 기준으로 관련 숏폼을 조회합니다.
| 필드 | 설명 |
|---|---|
sku · name | 현재 URL 조회에 더하는 상품 SKU · 상품명 힌트 |
position | { 'to-ri' | 'to-le' | 'bo-ri' | 'bo-le': true } |
size | 기기별 크기. { desktop: { width: '160px' }, mobile: { width: '28vw' } } 처럼 중첩 객체로. 각 기기는 width·maxWidth·height·maxHeight를 CSS 문자열로 받으며 전부 선택 (프리뷰 · 위치와 크기) |
closePolicyExpiry | 닫은 뒤 재표시 금지 시간(분). 미지정·0이면 세션 내 재표시 없음 |
resizable | 시청자 크기 조절 허용 |
disableQueryParamHistory | URL 쿼리 기록 끄기 |
쇼케이스 — setShortformShowcase(containerId, config)
| 필드 | 기본값 | 설명 |
|---|---|---|
shortformId | — | 직접 지정할 숏폼 ID. url보다 우선 |
url | 현재 페이지 URL | 관련 숏폼 조회 기준 URL. 지정 시 카드 탭은 이 URL로 이동 |
thumbnail | true | 하단 카드 썸네일 스트립 (카드 2장 이상일 때만 표시) |
removeOriginalDOM | true | 렌더 성공 후 컨테이너의 기존 자식 제거 |
스토리 — setShortformStory(containerId, config)
조건 배열 셋 중 적어도 하나는 넣어야 원이 생깁니다. 필터 공통 필드는 쓰지 않습니다.
| 필드 | 기본값 | 설명 |
|---|---|---|
brands | — | string[] 브랜드 식별자. 1개당 원 1개 |
tags | — | string[] 태그. 1개당 원 1개 |
shortformCollectionIds | — | string[] Admin 의 숏폼 그룹 ID. 1개당 원 1개 (스토리 · 1단계) |
size | 72 | 원의 지름(px) |
grid | false | true 면 스토리 아래에 활성 조건의 컬렉션을 GRID2 로 함께 렌더 (스토리 · 2단계) |
gridContainerId | — | grid 모드에서 컬렉션을 그릴 다른 컨테이너의 id. 없거나 스토리 자신·조상이면 경고 후 스토리 아래로 되돌립니다 |
인라인 플레이어 뷰 — setShortformPlayerView(containerId, config)
필터 공통 필드와 플레이어 모달의 ids · shortforms · startIndex · shortsId · muted를 그대로 쓰고, 여기에 customShortforms(커스텀 숏폼 객체 배열)를 더 넣을 수 있습니다.
커스텀 숏폼 객체 — appendCustomShortforms · setCustomShortform
| 필드 | 설명 |
|---|---|
shortsId | 필수. Shoplive 숏폼 ID |
customShortformId | 고객사 숏폼 고유 ID |
title · description · backButtonTitle | 제목 · 설명 · 뒤로가기 버튼 옆 제목 |
creatorName · creatorImage · creatorLevel · levelImageUrl · creatorIsFollow | 크리에이터 표시 정보와 팔로우 상태 |
likeCount · likeCountText · isLike · commentsCount · commentCountText | 좋아요·댓글 수와 표시 텍스트 |
linkButton { url, title } | 외부 링크 버튼 |
externalProducts[] | 외부 상품 — productId · sku · name · brand · url · imageUrl · currency · originalPrice 등 |
extra | 고객사 자유 데이터. 이벤트 payload에 그대로 포함되어 반환 |
이벤트 payload — 상품 · 숏폼
| 객체 | 주요 필드 |
|---|---|
payload.product | productId · name · brand · url · sku · imageUrl · currency · originalPrice · discountPrice · discountRate |
payload.shorts | shortsId · shortsDetail.{title, description, tags, brand} · cards[] · shortsIndex · (커스텀 숏폼이면) custom |
이벤트 사전
addShortformEventListener로 받을 수 있는 이벤트 전체입니다. 기본 동작이 있는 7종만 messageCallback으로 동작을 바꿀 수 있고(이벤트 처리 · 기본 동작 바꾸기), 나머지는 관찰용입니다.
기본 동작이 있는 이벤트 (7)
PLAY_SHORTFORM_DETAIL · CLOSE_SHORTFORM_DETAIL · LOGIN_REQUIRED · ON_CLICK_PRODUCT_ITEM · ON_CLICK_PRODUCT_BANNER · ON_CLICK_LINK_BUTTON · ON_CLICK_SHARE_BUTTON — 상세는 이벤트 처리의 표를 참고하세요.
알림 이벤트 (6)
| 이벤트 | 언제 | payload |
|---|---|---|
ON_SHORTFORM_DETAIL_READY | 플레이어가 준비됨 | shorts |
VIDEO_TOTAL_VIEWING_TIME | 숏폼 하나를 떠날 때 | shortsId · totalViewingTime · videoDuration · videoDurationText |
NEEDS_SHORTFORM_LIST_MORE | ID 지정 재생 목록의 끝에 가까워짐 | — |
ON_SHORTS_SHOWCASE_RENDERED | 쇼케이스 렌더링 결과 | success · shortsId · shorts | reason |
ON_SHORTS_STORY_RENDERED | 스토리의 원별 렌더 결과 | items[] — type(brand|tag|collection) · identifier · success · label · shortsCount |
ON_DRAG_START_PREVIEW / ON_DRAG_END_PREVIEW | 프리뷰 드래그 시작·끝 | — |
트래킹 이벤트
| 영역 | 이벤트 |
|---|---|
| 목록(컬렉션) | COLLECTION_SHOW · COLLECTION_SHOW_WHEN_VIDEO_PLAY · COLLECTION_CLICK_ITEM · COLLECTION_CLICK_VIEW_MORE |
| 프리뷰 | PREVIEW_SHOWN · PREVIEW_HIDDEN · PREVIEW_CLICK_SHOW · PREVIEW_CLICK_CLOSE |
| 플레이어 — 표시·재생 | DETAIL_ON_PLAYER_SHOW · DETAIL_ON_PLAYER_DISMISS · DETAIL_ACTIVE(숏폼 전환) · DETAIL_EMPTY · DETAIL_VIEWING_SECONDS · DETAIL_VIDEO_LOOP · DETAIL_SEEK_VIDEO · DETAIL_PAUSE_VIDEO · DETAIL_RESUME_VIDEO · DETAIL_CLICK_MUTE · DETAIL_CLICK_UNMUTE · DETAIL_CLICK_BACK_BUTTON · DETAIL_EXTERNAL_VIDEO_ON_ERROR · DETAIL_EXTERNAL_VIDEO_RECOVERED_FROM_ERROR |
| 플레이어 — 상품·링크 | DETAIL_CLICK_PRODUCT_CARD · DETAIL_SWIPE_PRODUCT_CARD · DETAIL_EXPAND_PRODUCT_LIST · DETAIL_DISMISS_PRODUCT_LIST · DETAIL_CLICK_PRODUCT_LIST_ITEM · DETAIL_CLICK_PRODUCT_BANNER · DETAIL_CLICK_LINK_BUTTON · DETAIL_CLICK_BRAND · DETAIL_CLICK_LIVE_CAMPAIGN_LINK |
| 플레이어 — 소셜 | DETAIL_CLICK_LIKE · DETAIL_CLICK_SHARE · DETAIL_CLICK_BOOKMARK · DETAIL_CLICK_CREATOR_PROFILE · DETAIL_CLICK_FOLLOW_BUTTON · DETAIL_CLICK_COMMENT · DETAIL_CLOSE_COMMENT · DETAIL_CREATE_COMMENT · DETAIL_UPDATE_COMMENT · DETAIL_DELETE_COMMENT · DETAIL_CLICK_REPLY · DETAIL_CLICK_COMMENT_LIKE · DETAIL_CLICK_MORE_OPTION_BUTTON |
| 플레이어 — 탐색·태그 | DETAIL_EXPAND_DESCRIPTION · DETAIL_COLLAPSE_DESCRIPTION · DETAIL_CLICK_TAG · DETAIL_CLICK_FILTER_TAG · DETAIL_CLICK_TAG_COLLECTION_ITEM · DETAIL_CLOSE_TAG_COLLECTION · DETAIL_CLICK_CREATOR_SHORTFORM_COLLECTION_ITEM · DETAIL_CLOSE_CREATOR_SHORTFORM_COLLECTION |
이전 ← 필드 사전다음 → 트러블슈팅 & FAQ
트러블슈팅 & FAQ
아무것도 안 떠요 (콘솔에 에러도 없어요)
브라우저 콘솔을 먼저 확인하세요. 정상 초기화면 [shoplive shortform initShortform start] 로그가 찍힙니다. 그 다음 아래 메시지 중 무엇이 보이는지에 따라 원인이 갈립니다.
| 콘솔 메시지 | 원인 · 조치 |
|---|---|
Invalid Shorts settings | Access Key가 잘못됐거나 설정 조회 실패. 이 경우 그 전에 호출한 표시 함수들도 모두 유실되므로 키를 고친 뒤 새로고침 |
Invalid containerId | 컨테이너 div의 id가 넘긴 값과 다르거나, 호출 시점에 DOM에 없음 |
"tags" property must be array | tags·brands를 문자열로 넘김 → 배열로 수정 (컬렉션) |
| (경고 후 아무 동작 없음) | 계약 상태 등 계정 문제일 수 있음 — Shoplive 담당자에게 문의 |
메시지가 하나도 없다면 <script src="…shoplive-shortform.js">가 cloud.shoplive.* 호출보다 앞에 있는지, 그리고 Admin에 필터 조건(태그·SKU)에 맞는 공개 숏폼이 있는지 확인하세요.
프리뷰나 쇼케이스만 안 떠요
둘 다 "조건이 맞지 않으면 조용히 안 그리는" 것이 정상 동작입니다. 프리뷰는 뜨지 않는 5가지 경우, 쇼케이스는 사전 준비(사용 설정 2개 + 컨테이너 크기)를 순서대로 확인하세요. 개발 중이라면 브라우저 저장소를 비우는 것이 첫 단계입니다.
iOS에서 영상이 자동 재생되지 않고 정지 화면만 보여요
SDK는 iOS 자동재생 정책에 맞게 음소거·인라인 재생으로 시작합니다. 그래도 특정 기기에서만 정지 화면이면 그 기기의 설정 → 손쉬운 사용 → 동작 → "비디오 미리 보기 자동 재생"이 꺼져 있는지 확인하세요. 저전력 모드·데이터 절약 모드도 같은 결과를 냅니다. 사용자가 의도적으로 끈 설정이라 코드로 우회할 수 없고, 탭하면 정상 재생됩니다.
단, 고객사 앱의 웹뷰로 연 페이지라면 원인이 다릅니다 — 웹뷰 설정 때문에 인라인 자동재생이 막힌 것이므로 앱 코드에서 고칠 수 있습니다. 부록 G · 고객사 앱 웹뷰 안에서 띄우기를 보세요.
플레이어가 열릴 때 고객사 SPA 라우터가 반응해요 / 뒤로가기가 이상해요
SDK가 URL에 __sl_shorts_id를 pushState하기 때문입니다. 표시 함수 호출에 disableQueryParamHistory: true를 주세요 (딥링크).
상품을 클릭하면 페이지가 통째로 새로 로드돼요
ON_CLICK_PRODUCT_ITEM의 기본 동작이 location.href = product.url입니다. messageCallback에 이 이벤트를 등록해 라우터 이동으로 바꾸세요 (이벤트 처리). 새 탭으로 열고 싶다면 그 안에서 window.open(payload.product.url)을 호출하면 됩니다.
쇼케이스가 렌더링은 되는데 탭해도 반응이 없어요
페이지 전역 CSS가 SDK의 투명 클릭 영역을 숨기는 경우입니다 (예: div:empty { display: none }). 개발자 도구에서 컨테이너 안 .csl- 요소들에 페이지 CSS가 적용돼 있는지 확인하고, 해당 규칙을 컨테이너 밖으로 한정하세요 (쇼케이스).
플레이어 모양이 고객사 사이트에서만 깨져요
SDK는 고객사 DOM 안에 그려지므로 페이지의 전역 스타일과 충돌할 수 있습니다. SDK 요소는 sl-·csl- 접두어를 쓰지만, 페이지에 video·img 같은 태그 단위 전역 스타일(예: img { width: 100% !important })이 있으면 영향을 받습니다. 개발자 도구로 깨진 요소에 어떤 규칙이 적용되는지 확인하고 규칙 범위를 좁히세요. 해결이 어려우면 Shoplive 담당자에게 문의하세요.
초기화 전에 호출해도 되는 함수와 안 되는 함수
표시 함수(setShortformCollection · showShortformPreview · setShortformShowcase · showShortformPlayerModal)는 초기화 전에 호출하면 큐에 쌓였다가 자동 실행됩니다. 반면 destroy* · hideShortformPreview · shortformPlayerAppendList · get/setShortformGlobalMuteState · getShortformTotalViewingTime은 즉시 실행되므로 초기화가 끝난 뒤(또는 표시 함수가 동작한 뒤) 호출하세요. setShortformPlayerView는 부록 A의 주의사항을 참고하세요.
CSP(Content-Security-Policy)를 쓰고 있어요. 어떤 도메인을 허용해야 하나요?
| 지시어 | 허용할 출처 | 용도 |
|---|---|---|
script-src | https://static.shoplive.cloudhttps://cdnjs.cloudflare.com | SDK 본체·지연 로드 청크는 static, HLS 재생 라이브러리(hls.js)는 cdnjs에서 받아옵니다 |
style-src | https://static.shoplive.cloud · 'unsafe-inline' | SDK 스타일시트 · 계정 커스텀 스타일(인라인) |
connect-src | https://config.shoplive.cloud · https://api.shoplive.cloud · https://*.shoplive.cloud | 고객사 설정 · 숏폼 API · 시청 로그 · 영상 세그먼트 |
media-src · img-src | https://*.shoplive.cloud · blob: | 영상(HLS는 blob: 필요) · 썸네일 |
정확한 API 호스트는 계정 설정에 따라 다를 수 있으니 배포 전 네트워크 탭으로 확인하세요.