이 글은 누구를 위한 것인가
- 유튜브, 인스타그램 릴스처럼 영상에서 바로 구매 가능하게 만들고 싶은 팀
- 상품 리뷰 영상과 구매를 연결하려는 이커머스 콘텐츠 팀
- 쇼퍼블 비디오 플레이어를 직접 개발해야 하는 프론트엔드 개발자
들어가며
영상은 상품의 실제 사용감을 가장 잘 전달한다. 하지만 "영상 보다가 구매하려고 하면 어떻게 사지?" — 이 마찰을 제거하는 것이 쇼퍼블 비디오의 핵심이다.
이 글은 bluefoxdev.kr의 콘텐츠 커머스 전략 을 참고하여 작성했습니다.
1. 쇼퍼블 비디오 구현 방식
[구현 방식 비교]
방식 1: 타임라인 태그 (timestamp → 상품)
├── 영상 편집자가 타임스탬프별 상품 태깅
├── 플레이어가 현재 시간에 맞는 상품 표시
└── 예: 0:30에 빨간 재킷 → 하단에 상품 카드 노출
방식 2: 영상 위 클릭 영역 (핫스팟)
├── 영상 위에 클릭 가능한 영역 설정
├── 재킷 위치에 클릭하면 상품 팝업
└── 제작 비용 높음, 모바일에서 어려움
방식 3: AI 자동 태깅
├── 영상 분석 AI가 상품 자동 인식
├── 제품 카탈로그와 매칭
└── 구현 복잡, 정확도 70~80%
[권장 구현: 방식 1 + 방식 3 혼합]
편집자가 중요 장면만 수동 태깅 + AI 보조
2. 쇼퍼블 비디오 플레이어
import { useRef, useState, useEffect } from 'react';
interface ProductTag {
timestampStart: number; // 초
timestampEnd: number;
productId: string;
productName: string;
price: number;
imageUrl: string;
}
interface ShoppableVideoProps {
videoUrl: string;
productTags: ProductTag[];
}
function ShoppableVideo({ videoUrl, productTags }: ShoppableVideoProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const [currentTime, setCurrentTime] = useState(0);
const [activeProducts, setActiveProducts] = useState<ProductTag[]>([]);
useEffect(() => {
const video = videoRef.current;
if (!video) return;
const handleTimeUpdate = () => {
const t = video.currentTime;
setCurrentTime(t);
setActiveProducts(
productTags.filter(tag => t >= tag.timestampStart && t <= tag.timestampEnd)
);
};
video.addEventListener('timeupdate', handleTimeUpdate);
return () => video.removeEventListener('timeupdate', handleTimeUpdate);
}, [productTags]);
return (
<div className="relative w-full">
<video
ref={videoRef}
src={videoUrl}
controls
className="w-full rounded-lg"
/>
{/* 상품 오버레이 */}
{activeProducts.length > 0 && (
<div className="absolute bottom-16 left-4 right-4 flex gap-3 overflow-x-auto">
{activeProducts.map(product => (
<ProductCard key={product.productId} product={product} />
))}
</div>
)}
</div>
);
}
function ProductCard({ product }: { product: ProductTag }) {
const [added, setAdded] = useState(false);
return (
<div className="flex-shrink-0 bg-white/90 backdrop-blur rounded-xl p-3 flex items-center gap-3 shadow-lg min-w-[200px]">
<img
src={product.imageUrl}
alt={product.productName}
className="w-12 h-12 object-cover rounded-lg"
/>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{product.productName}</p>
<p className="text-sm text-gray-600">{product.price.toLocaleString()}원</p>
</div>
<button
onClick={() => { addToCart(product.productId); setAdded(true); }}
className={`text-xs px-3 py-1.5 rounded-full font-medium ${
added ? 'bg-green-100 text-green-700' : 'bg-blue-600 text-white'
}`}
>
{added ? '담김' : '담기'}
</button>
</div>
);
}
3. 타임라인 태깅 관리 도구 (어드민)
// 비디오 태그 관리 API
interface VideoTagRequest {
videoId: string;
tags: {
timestampStart: number;
timestampEnd: number;
productId: string;
}[];
}
async function saveVideoTags(req: VideoTagRequest): Promise<void> {
await db.transaction(async (trx) => {
// 기존 태그 삭제
await trx.delete('video_product_tags').where({ video_id: req.videoId });
// 새 태그 삽입
if (req.tags.length > 0) {
await trx.insert('video_product_tags').values(
req.tags.map(tag => ({
video_id: req.videoId,
product_id: tag.productId,
timestamp_start: tag.timestampStart,
timestamp_end: tag.timestampEnd,
}))
);
}
});
}
마무리
쇼퍼블 비디오의 핵심은 "보는 것에서 사는 것으로" 마찰을 줄이는 것이다. 타임라인 기반 태깅은 구현이 단순하면서도 효과가 크다. 비디오 중 구매 버튼을 클릭한 사용자는 영상 없이 상품을 발견한 사용자보다 구매율이 훨씬 높다. 콘텐츠팀과 협업하여 주요 상품을 영상에 자연스럽게 노출하는 것이 전략의 시작이다.