이 글은 누구를 위한 것인가
- 무료 배송을 제공해야 할지, 임계값을 어디로 설정할지 고민하는 팀
- 배송비 전략이 없어 AOV(평균 주문 금액)가 낮은 쇼핑몰
- 지역별·상품별 배송비를 어떻게 설계해야 할지 모르는 팀
들어가며
"무료 배송"은 전환율을 높이지만 수익을 낮춘다. 임계값을 너무 낮게 설정하면 수익이 없고, 너무 높으면 고객이 이탈한다. 데이터 기반으로 최적 임계값을 찾아야 한다.
이 글은 bluefoxdev.kr의 이커머스 배송비 전략 를 참고하여 작성했습니다.
1. 배송비 모델 유형 비교
[배송비 정책 비교]
1. 완전 무료:
장점: 전환율 최고
단점: 소액 주문 시 마진 없음
적합: 고마진 상품, 구독 모델
2. 임계값 무료 (5만원 이상 무료):
장점: AOV 상승 효과
단점: 임계값 근처 이탈
적합: 대부분의 이커머스
3. 정액 배송비:
장점: 예측 가능
단점: 고액 주문 고객 불만
적합: 소형 전문몰
4. 실비 배송비:
장점: 정확한 비용 반영
단점: 복잡한 계산, 고객 혼란
적합: 대형·중량 상품
5. 멤버십 무료:
장점: 구독 락인 효과
단점: 구독 이탈 시 수익 감소
적합: 재구매율 높은 카테고리
[무료 배송 임계값 계산]
평균 배송비: 3,000원
마진율: 30%
→ 무료 배송 손익분기: 3,000 / 0.30 = 10,000원
→ 임계값: 20,000~30,000원 (2-3배) 설정
2. 배송비 계산 엔진
from dataclasses import dataclass
@dataclass
class ShippingRate:
base_fee: int
free_threshold: int | None
per_kg_fee: int = 0
remote_area_surcharge: int = 0
SHIPPING_RULES = {
"default": ShippingRate(base_fee=3000, free_threshold=50000),
"large_appliance": ShippingRate(base_fee=0, free_threshold=None, per_kg_fee=500),
"fresh": ShippingRate(base_fee=4000, free_threshold=80000),
"jeju": ShippingRate(base_fee=3000, free_threshold=None, remote_area_surcharge=3000),
}
async def calculate_shipping_fee(
cart_items: list[dict],
delivery_address: dict,
user_id: str,
) -> dict:
"""배송비 계산"""
order_total = sum(i["price"] * i["quantity"] for i in cart_items)
total_weight_kg = sum(i.get("weight_kg", 0.5) * i["quantity"] for i in cart_items)
# 회원 등급 확인 (무료 배송 멤버십)
membership = await get_user_membership(user_id)
if membership and membership["type"] == "prime":
return {
"shipping_fee": 0,
"reason": "Prime 멤버십 무료 배송",
"savings": SHIPPING_RULES["default"].base_fee,
}
# 지역 확인
region = classify_region(delivery_address["postal_code"])
# 상품 카테고리별 배송비 계산
fee_groups = {}
for item in cart_items:
category = item.get("shipping_category", "default")
if category not in fee_groups:
fee_groups[category] = {"items": [], "total": 0}
fee_groups[category]["items"].append(item)
fee_groups[category]["total"] += item["price"] * item["quantity"]
total_shipping_fee = 0
breakdown = []
for category, group in fee_groups.items():
rule = SHIPPING_RULES.get(category, SHIPPING_RULES["default"])
# 무료 임계값 체크
if rule.free_threshold and group["total"] >= rule.free_threshold:
fee = 0
note = f"무료 배송 ({rule.free_threshold:,}원 이상)"
else:
fee = rule.base_fee
if rule.per_kg_fee:
fee += int(total_weight_kg * rule.per_kg_fee)
note = f"기본 배송비"
# 도서산간 추가 배송비
if region == "remote" and rule.remote_area_surcharge:
fee += rule.remote_area_surcharge
note += " + 도서산간 추가"
total_shipping_fee += fee
breakdown.append({"category": category, "fee": fee, "note": note})
# 무료 배송까지 남은 금액
default_rule = SHIPPING_RULES["default"]
remaining_for_free = None
if default_rule.free_threshold and order_total < default_rule.free_threshold:
remaining_for_free = default_rule.free_threshold - order_total
return {
"shipping_fee": total_shipping_fee,
"breakdown": breakdown,
"remaining_for_free_shipping": remaining_for_free,
}
def classify_region(postal_code: str) -> str:
"""우편번호로 지역 분류"""
remote_prefixes = ["63", "695", "697"] # 제주, 울릉도 등
return "remote" if any(postal_code.startswith(p) for p in remote_prefixes) else "standard"
3. AOV 최적화 배송비 UX
function ShippingFeePrompt({ remainingAmount }: { remainingAmount: number | null }) {
if (!remainingAmount || remainingAmount <= 0) {
return (
<div className="bg-green-50 p-3 rounded text-sm text-green-700">
무료 배송 조건 충족! 배송비 3,000원 절약
</div>
);
}
return (
<div className="bg-blue-50 p-3 rounded text-sm">
<span className="font-semibold text-blue-700">
{remainingAmount.toLocaleString()}원
</span>
<span className="text-blue-600"> 더 담으면 무료 배송!</span>
<button className="ml-2 text-blue-500 underline text-xs">
추천 상품 보기
</button>
</div>
);
}
마무리
무료 배송 임계값의 황금 비율은 현재 AOV의 1.3-1.5배다. 현재 AOV가 35,000원이면 임계값을 45,000-50,000원으로 설정하면 AOV가 자연스럽게 올라간다. "X원 더 담으면 무료 배송" 메시지는 그 자체로 AOV를 10-15% 높이는 가장 간단한 UX다.