Skip to content

Commit 08d431b

Browse files
authored
Merge pull request #24 from Swetrix/revenue-analytics
Revenue analytics
2 parents d523fc9 + 9466f60 commit 08d431b

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

src/Lib.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,108 @@ export class Lib {
593593
this.cachedData = null
594594
}
595595

596+
/**
597+
* Gets the anonymous profile ID for the current visitor.
598+
* If profileId was set via init options, returns that.
599+
* Otherwise, requests server to generate one from IP/UA hash.
600+
*
601+
* This ID can be used for revenue attribution with payment providers.
602+
*
603+
* @returns A promise that resolves to the profile ID string, or null on error.
604+
*
605+
* @example
606+
* ```typescript
607+
* const profileId = await swetrix.getProfileId()
608+
*
609+
* // Pass to Paddle Checkout for revenue attribution
610+
* Paddle.Checkout.open({
611+
* items: [{ priceId: 'pri_01234567890', quantity: 1 }],
612+
* customData: {
613+
* swetrix_profile_id: profileId,
614+
* swetrix_session_id: await swetrix.getSessionId()
615+
* }
616+
* })
617+
* ```
618+
*/
619+
async getProfileId(): Promise<string | null> {
620+
// If profileId is already set in options, return it
621+
if (this.options?.profileId) {
622+
return this.options.profileId
623+
}
624+
625+
if (!isInBrowser()) {
626+
return null
627+
}
628+
629+
try {
630+
const apiBase = this.getApiBase()
631+
const response = await fetch(`${apiBase}/log/profile-id`, {
632+
method: 'POST',
633+
headers: {
634+
'Content-Type': 'application/json',
635+
},
636+
body: JSON.stringify({ pid: this.projectID }),
637+
})
638+
639+
if (!response.ok) {
640+
return null
641+
}
642+
643+
const data = (await response.json()) as { profileId: string | null }
644+
return data.profileId
645+
} catch {
646+
return null
647+
}
648+
}
649+
650+
/**
651+
* Gets the current session ID for the visitor.
652+
* Session IDs are generated server-side based on IP and user agent.
653+
*
654+
* This ID can be used for revenue attribution with payment providers.
655+
*
656+
* @returns A promise that resolves to the session ID string, or null on error.
657+
*
658+
* @example
659+
* ```typescript
660+
* const sessionId = await swetrix.getSessionId()
661+
*
662+
* // Pass to Paddle Checkout for revenue attribution
663+
* Paddle.Checkout.open({
664+
* items: [{ priceId: 'pri_01234567890', quantity: 1 }],
665+
* customData: {
666+
* swetrix_profile_id: await swetrix.getProfileId(),
667+
* swetrix_session_id: sessionId
668+
* }
669+
* })
670+
* ```
671+
*/
672+
async getSessionId(): Promise<string | null> {
673+
if (!isInBrowser()) {
674+
return null
675+
}
676+
677+
try {
678+
const apiBase = this.getApiBase()
679+
const response = await fetch(`${apiBase}/log/session-id`, {
680+
method: 'POST',
681+
headers: {
682+
'Content-Type': 'application/json',
683+
},
684+
body: JSON.stringify({ pid: this.projectID }),
685+
})
686+
687+
if (!response.ok) {
688+
return null
689+
}
690+
691+
const data = (await response.json()) as { sessionId: string | null }
692+
return data.sessionId
693+
} catch {
694+
return null
695+
}
696+
}
697+
596698
/**
597699
* Gets the API base URL (without /log suffix).
598700
*/

src/index.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,63 @@ export function clearExperimentsCache(): void {
263263
LIB_INSTANCE.clearExperimentsCache()
264264
}
265265

266+
/**
267+
* Gets the anonymous profile ID for the current visitor.
268+
* If profileId was set via init options, returns that.
269+
* Otherwise, requests server to generate one from IP/UA hash.
270+
*
271+
* This ID can be used for revenue attribution with payment providers like Paddle.
272+
*
273+
* @returns A promise that resolves to the profile ID string, or null on error.
274+
*
275+
* @example
276+
* ```typescript
277+
* const profileId = await getProfileId()
278+
*
279+
* // Pass to Paddle Checkout for revenue attribution
280+
* Paddle.Checkout.open({
281+
* items: [{ priceId: 'pri_01234567890', quantity: 1 }],
282+
* customData: {
283+
* swetrix_profile_id: profileId,
284+
* swetrix_session_id: await getSessionId()
285+
* }
286+
* })
287+
* ```
288+
*/
289+
export async function getProfileId(): Promise<string | null> {
290+
if (!LIB_INSTANCE) return null
291+
292+
return LIB_INSTANCE.getProfileId()
293+
}
294+
295+
/**
296+
* Gets the current session ID for the visitor.
297+
* Session IDs are generated server-side based on IP and user agent.
298+
*
299+
* This ID can be used for revenue attribution with payment providers like Paddle.
300+
*
301+
* @returns A promise that resolves to the session ID string, or null on error.
302+
*
303+
* @example
304+
* ```typescript
305+
* const sessionId = await getSessionId()
306+
*
307+
* // Pass to Paddle Checkout for revenue attribution
308+
* Paddle.Checkout.open({
309+
* items: [{ priceId: 'pri_01234567890', quantity: 1 }],
310+
* customData: {
311+
* swetrix_profile_id: await getProfileId(),
312+
* swetrix_session_id: sessionId
313+
* }
314+
* })
315+
* ```
316+
*/
317+
export async function getSessionId(): Promise<string | null> {
318+
if (!LIB_INSTANCE) return null
319+
320+
return LIB_INSTANCE.getSessionId()
321+
}
322+
266323
export {
267324
LibOptions,
268325
TrackEventOptions,

0 commit comments

Comments
 (0)