Dub 는 짧은 링크를 생성, 공유 및 추적하는 데 도움을 주는 강력한 링크 관리 플랫폼입니다. Dodo Payments와 Dub을 통합하면 고객이 구매를 완료할 때 판매 전환 이벤트를 자동으로 추적할 수 있어 마케팅 캠페인 및 추천 프로그램의 ROI를 측정할 수 있습니다.
고객이 다음을 수행할 때 Dub에서 “판매” 이벤트가 기록됩니다:
일회성 결제를 완료함
유료 요금제에 가입함
정기 구독 결제를 함
이 통합을 위해서는 링크에서 전환 추적이 활성화된 Dub 계정이 필요합니다.
작동 방식
Dub은 사용자가 Dub 짧은 링크를 클릭할 때 쿠키에 저장된 고유 클릭 ID (dub_id)를 통해 방문자를 추적합니다. 판매를 링크에 귀속시키기 위해서는 다음을 수행해야 합니다:
체크아웃 세션을 생성할 때 Dub의 클릭 ID 를 dub_id 쿠키에서 캡처합니다.
클릭 ID를 고객의 외부 ID와 함께 결제 메타데이터에 저장합니다.
결제가 성공할 때 판매 데이터를 Dub에 전송합니다 . Track API를 사용합니다.
이렇게 하면 Dub이 성공적인 판매를 원래 링크 클릭과 일치시켜 완전한 전환 귀속을 제공합니다.
전제 조건
이 통합을 설정하기 전에 다음을 확인하십시오:
Dub 계정 과 작업 공간이 있습니다.
링크에 대한 전환 추적이 활성화되어 있습니다.
Dub API 키 (설정 → API 키에서 Dub 대시보드에서 확인 가능)가 있습니다.
시작하기
Dub에서 전환 추적 활성화
Dub 대시보드에서 판매를 추적할 링크에 대한 전환 추적을 활성화합니다. 이렇게 하면 고객이 구매를 완료할 때 Dub이 판매 이벤트를 기록할 수 있습니다. Dub 문서 에서 전환 추적 활성화에 대해 자세히 알아보세요.
Dub API 키 가져오기
Dub 대시보드 → 설정 → API 키로 이동하여 conversions.write 범위로 새 API 키를 생성합니다.API 키를 안전하게 보관하고 클라이언트 측 코드에 노출하지 마십시오.
체크아웃에서 클릭 ID 캡처
체크아웃 세션을 생성할 때 쿠키에서 Dub 클릭 ID를 캡처하고 결제 메타데이터에 추가합니다.
웹훅을 통해 판매 데이터 전송
결제가 성공할 때 판매 데이터를 Dub의 Track API에 전송하도록 웹훅을 구성합니다.
완료!
이제 판매 전환 이벤트가 귀하의 Dub 분석 대시보드에 링크에 대한 완전한 귀속과 함께 나타납니다.
구현 가이드
1단계: 클릭 ID 및 고객 ID를 체크아웃 메타데이터에 추가
체크아웃 세션을 생성할 때 쿠키에서 Dub 클릭 ID를 캡처하고 고객의 외부 ID와 함께 결제 메타데이터에 포함합니다.
Next.js
Express.js
Python (FastAPI)
Go
import { cookies } from 'next/headers' ;
import DodoPayments from 'dodopayments' ;
const client = new DodoPayments ();
export async function createCheckout ( productId : string , customerId : string ) {
// Capture Dub click ID from cookie
const dubClickId = cookies (). get ( 'dub_id' )?. value ;
const payment = await client . payments . create ({
billing: {
city: 'New York' ,
country: 'US' ,
state: 'NY' ,
street: '123 Main St' ,
zipcode: '10001' ,
},
customer: {
email: '[email protected] ' ,
name: 'John Doe' ,
},
product_id: productId ,
metadata: {
dub_click_id: dubClickId , // Store Dub click ID
dub_external_id: customerId , // Store your customer's unique ID
},
});
return payment ;
}
2단계: Dub에 판매 데이터 전송
결제가 성공할 때 판매 데이터를 Dub의 Track API에 전송하도록 웹훅 엔드포인트를 구성합니다.
웹훅 섹션 열기
Dodo Payments 대시보드에서 웹훅 → + 엔드포인트 추가 로 이동하고 통합 드롭다운을 확장합니다.
변환 구성
결제 데이터를 Dub의 Track Sale API에 맞게 형식화하도록 변환 코드를 편집합니다.
테스트 및 생성
샘플 페이로드로 테스트하고 생성 을 클릭하여 통합을 활성화합니다.
변환 코드 예제
기본 판매 추적
결제가 성공할 때 판매를 추적합니다:
function handler ( webhook ) {
if ( webhook . eventType === "payment.succeeded" ) {
const payment = webhook . payload . data ;
// Only send to Dub if click ID exists in metadata
if ( payment . metadata && payment . metadata . dub_click_id ) {
webhook . payload = {
clickId: payment . metadata . dub_click_id ,
externalId: payment . metadata . dub_external_id || payment . customer . customer_id ,
amount: payment . total_amount , // Ensure the amount is in cents
currency: payment . currency || "USD" ,
paymentProcessor: "dodo" ,
invoiceId: payment . payment_id ,
metadata: {
customer_email: payment . customer . email ,
customer_name: payment . customer . name ,
product_id: payment . product_cart ? payment . product_cart . map ( product => product . product_id ). join ( ', ' ) : undefined ,
},
};
} else {
// Cancel dispatch if no click ID (organic traffic)
webhook . cancel = true ;
}
}
return webhook ;
}
See all 26 lines
구독 판매 추적
초기 구독 및 정기 결제를 모두 추적합니다:
function handler ( webhook ) {
const data = webhook . payload . data ;
// Track initial subscription activation
if ( webhook . eventType === "subscription.active" ) {
if ( data . metadata && data . metadata . dub_click_id ) {
webhook . payload = {
clickId: data . metadata . dub_click_id ,
externalId: data . metadata . dub_external_id || data . customer . customer_id ,
amount: data . recurring_pre_tax_amount , // Amount in cents
currency: data . currency || "USD" ,
paymentProcessor: "dodo" ,
invoiceId: data . subscription_id ,
eventName: "Subscription Started" ,
metadata: {
subscription_id: data . subscription_id ,
product_id: data . product_id ,
billing_interval: data . payment_frequency_interval ,
customer_email: data . customer . email ,
},
};
} else {
// Cancel dispatch if no click ID (organic traffic)
webhook . cancel = true ;
}
}
// Track recurring subscription payments
if ( webhook . eventType === "subscription.renewed" ) {
if ( data . metadata && data . metadata . dub_click_id ) {
webhook . payload = {
clickId: data . metadata . dub_click_id ,
externalId: data . metadata . dub_external_id || data . customer . customer_id ,
amount: data . recurring_pre_tax_amount ,
currency: data . currency || "USD" ,
paymentProcessor: "dodo" ,
invoiceId: ` ${ data . subscription_id } _ ${ Date . now () } ` ,
eventName: "Subscription Renewed" ,
metadata: {
subscription_id: data . subscription_id ,
product_id: data . product_id ,
customer_email: data . customer . email ,
},
};
} else {
// Cancel dispatch if no click ID (organic traffic)
webhook . cancel = true ;
}
}
return webhook ;
}
See all 52 lines
세금 제외 판매 추적
정확한 수익 추적을 위해 세전 금액만 Dub에 전송합니다:
function handler ( webhook ) {
if ( webhook . eventType === "payment.succeeded" ) {
const payment = webhook . payload . data ;
if ( payment . metadata && payment . metadata . dub_click_id ) {
// Calculate pre-tax amount (total minus tax)
const preTaxAmount = payment . total_amount - ( payment . tax || 0 );
webhook . payload = {
clickId: payment . metadata . dub_click_id ,
externalId: payment . metadata . dub_external_id || payment . customer . customer_id ,
amount: preTaxAmount , // Pre-tax amount in cents
currency: payment . currency || "USD" ,
paymentProcessor: "dodo" ,
invoiceId: payment . payment_id ,
metadata: {
total_amount: payment . total_amount ,
tax_amount: payment . tax || 0 ,
customer_email: payment . customer . email ,
},
};
} else {
// Cancel dispatch if no click ID (organic traffic)
webhook . cancel = true ;
}
}
return webhook ;
}
See all 28 lines
사용자 정의 이벤트 이름으로 판매 추적
다양한 유형의 판매를 분류하기 위해 사용자 정의 이벤트 이름을 사용합니다:
function handler ( webhook ) {
if ( webhook . eventType === "payment.succeeded" ) {
const payment = webhook . payload . data ;
if ( payment . metadata && payment . metadata . dub_click_id ) {
// Determine event name based on payment type
let eventName = "Purchase" ;
if ( payment . subscription_id ) {
eventName = "Subscription Purchase" ;
} else if ( payment . metadata && payment . metadata . is_upgrade ) {
eventName = "Plan Upgrade" ;
}
webhook . payload = {
clickId: payment . metadata . dub_click_id ,
externalId: payment . metadata . dub_external_id || payment . customer . customer_id ,
amount: payment . total_amount ,
currency: payment . currency || "USD" ,
paymentProcessor: "dodo" ,
invoiceId: payment . payment_id ,
eventName: eventName ,
metadata: {
product_id: payment . product_cart ? payment . product_cart . map ( product => product . product_id ). join ( ', ' ) : undefined ,
customer_email: payment . customer . email ,
},
};
} else {
// Cancel dispatch if no click ID (organic traffic)
webhook . cancel = true ;
}
}
return webhook ;
}
See all 33 lines
대안: 클라이언트 측 구현
웹훅을 사용하는 대신 서버에서 판매를 추적하려는 경우, 결제가 성공한 후 Dub의 Track API를 직접 호출할 수 있습니다:
Next.js (Server Action)
Node.js
'use server' ;
import { Dub } from 'dub' ;
const dub = new Dub ();
export async function trackSale (
paymentId : string ,
clickId : string ,
customerId : string ,
amount : number ,
currency : string
) {
await dub . track . sale ({
clickId: clickId ,
externalId: customerId ,
amount: amount ,
currency: currency ,
paymentProcessor: 'dodo' ,
invoiceId: paymentId ,
});
}
모범 사례
클릭 ID를 조기에 캡처 : 사용자가 나갔다가 나중에 돌아오더라도 정확한 귀속을 보장하기 위해 체크아웃 흐름에서 가능한 한 빨리 Dub 클릭 ID를 저장하십시오.
메타데이터에 클릭 ID를 항상 포함 : 클릭 ID가 없으면 Dub이 귀하의 링크에 수익을 귀속시킬 수 없습니다.
외부 ID를 일관되게 사용 : 정확한 고객 수준 분석을 위해 시스템에서 사용하는 동일한 고객 ID를 전달합니다.
유기적 트래픽을 우아하게 처리 : 클릭 ID가 없을 때 webhook.cancel = true를 설정하여 불필요한 API 호출을 피합니다.
샘플 결제로 테스트 : 라이브로 전환하기 전에 통합이 올바르게 작동하는지 확인합니다.
Dub 대시보드를 모니터링 : 판매가 올바르게 나타나고 적절한 귀속이 이루어지는지 확인합니다.
중요 사항
금액 형식 : Dub은 금액을 센트 단위로 기대합니다 (예: $10.00 = 1000)
통화 : ISO 4217 통화 코드를 사용합니다 (USD, EUR, GBP 등)
무료 체험 : $0 결제는 판매로 추적되지 않습니다.
환불 : 정확한 수익 보고를 위해 필요시 환불을 별도로 추적하는 것을 고려하십시오.
문제 해결
Dub API 키가 올바르고 conversions.write 범위가 있는지 확인합니다.
dub_click_id가 결제 메타데이터에 캡처되고 저장되고 있는지 확인합니다.
웹훅 변환이 페이로드를 올바르게 형식화하고 있는지 확인합니다.
웹훅이 payment.succeeded 이벤트에서 트리거되고 있는지 확인합니다.
Dub 링크에 대한 전환 추적이 활성화되어 있는지 확인합니다.
사용자가 체크아웃 전에 Dub 짧은 링크를 클릭하고 있는지 확인합니다.
dub_id 쿠키가 도메인에 올바르게 설정되고 있는지 확인합니다.
체크아웃 생성과 결제 완료 간에 클릭 ID가 일치하는지 확인합니다.
체크아웃 세션을 생성하기 전에 클릭 ID를 캡처하고 있는지 확인합니다.
JSON 구조가 Dub의 Track Sale API 형식과 일치하는지 확인합니다.
모든 필수 필드 (clickId, externalId, amount)가 있는지 확인합니다.
금액이 센트 단위인지 (정수, 소수점 아님) 확인합니다.
API 엔드포인트 URL이 올바른지 확인합니다: https://api.dub.co/track/sale
샘플 웹훅 페이로드로 변환을 테스트합니다.
payment.succeeded 이벤트에서만 추적하고 있는지 확인하고 payment.processing 이벤트에서는 추적하지 않도록 합니다.
각 판매에 대해 고유한 invoiceId 값을 사용합니다.
구독의 경우, 갱신 시 중복을 방지하기 위해 타임스탬프 또는 청구 기간을 추가합니다.
추가 리소스