diff --git a/docs/customerio-messaging.md b/docs/customerio-messaging.md index ccfd4648a..a487db8b0 100644 --- a/docs/customerio-messaging.md +++ b/docs/customerio-messaging.md @@ -18,7 +18,7 @@ Embedded Cloud continues to own its existing integration. The default public browser keys in `src/shared/customerIo.ts` use the existing Cloud Customer.io source. Identity is the same Firebase UID used on Cloud. Desktop sends `identify` with the selected locale, a page named -**`desktop/local-workflow`**, and the SDK's delivery/interaction metrics. Page +**`desktop/comfyui`**, and the SDK's delivery/interaction metrics. Page properties also use this synthetic target, rather than the local workflow URL. Configure Desktop messages to match that page name. Audit campaigns with no page diff --git a/e2e/customerio.test.ts b/e2e/customerio.test.ts index 4800ff6e7..1eece1e03 100644 --- a/e2e/customerio.test.ts +++ b/e2e/customerio.test.ts @@ -9,7 +9,8 @@ const identity: CustomerIoSession = { userId: 'desktop-test-user', locale: 'ja', writeKey: 'test-write-key', - siteId: 'test-site' + siteId: 'test-site', + page: 'desktop/comfyui' } /** Exercise the shipped preload and real SDK without a ComfyUI install or vendor traffic. */ @@ -116,7 +117,7 @@ document.getElementById('close').onclick = () => parent.postMessage({gist:{insta properties: { gist: { campaignId: `fixture-delivery-${delivery}`, - routeRuleWeb: 'desktop/local-workflow', + routeRuleWeb: 'desktop/comfyui', persistent: request.headers()['x-gist-encoded-user-token'] === Buffer.from('second-test-user').toString('base64') @@ -198,7 +199,7 @@ document.getElementById('close').onclick = () => parent.postMessage({gist:{insta const events = requests.filter(({ url }) => /^https:\/\/cdp\.customer\.io\/v1\/[ipt]$/.test(url) ) - expect(events.some(({ body }) => body?.includes('"name":"desktop/local-workflow"'))).toBe(true) + expect(events.some(({ body }) => body?.includes('"name":"desktop/comfyui"'))).toBe(true) expect( events.every( ({ body }) => !/private-workflow|private-query|private-referrer/.test(body ?? '') @@ -209,6 +210,7 @@ document.getElementById('close').onclick = () => parent.postMessage({gist:{insta for (const { body } of pages) { expect(JSON.parse(body!).properties).toMatchObject({ search: '', referrer: '' }) } + const queues = requests.filter(({ url }) => url.includes('/api/v4/users')) expect(queues.length).toBeGreaterThanOrEqual(2) expect(queues.every(({ headers }) => headers['x-cio-site-id'] === identity.siteId)).toBe(true) diff --git a/src/main/lib/customerIoMessaging.ts b/src/main/lib/customerIoMessaging.ts index e9c34ab9d..6dca463ee 100644 --- a/src/main/lib/customerIoMessaging.ts +++ b/src/main/lib/customerIoMessaging.ts @@ -2,6 +2,7 @@ import { app, ipcMain, shell, type IpcMainEvent, type WebContents } from 'electr import type { ComfyWindowEntry } from '../host/registry' import { CUSTOMER_IO_DEFAULTS, + CUSTOMER_IO_PAGES, CUSTOMER_IO_ACTION, CUSTOMER_IO_READY, CUSTOMER_IO_STATE @@ -42,6 +43,7 @@ export function customerIoSession(entry: ComfyWindowEntry): CustomerIoSession | if (!userId) return null return { userId, + page: CUSTOMER_IO_PAGES.comfyui, locale: i18n.getLocale(), writeKey: process.env.COMFY_CUSTOMER_IO_WRITE_KEY || CUSTOMER_IO_DEFAULTS.writeKey, siteId: process.env.COMFY_CUSTOMER_IO_SITE_ID || CUSTOMER_IO_DEFAULTS.siteId diff --git a/src/renderer/src/customerIo/controller.test.ts b/src/renderer/src/customerIo/controller.test.ts index 22c0ade78..c07c3c474 100644 --- a/src/renderer/src/customerIo/controller.test.ts +++ b/src/renderer/src/customerIo/controller.test.ts @@ -6,7 +6,8 @@ const session: CustomerIoSession = { userId: 'user-a', locale: 'en', writeKey: 'test', - siteId: 'test' + siteId: 'test', + page: 'desktop/comfyui' } function client(): MessagingClient { return { @@ -35,6 +36,7 @@ describe('Desktop messaging lifecycle', () => { await controller.update({ ...session }) expect(load).toHaveBeenCalledTimes(1) expect(sdk.identify).toHaveBeenCalledExactlyOnceWith(session) + expect(sdk.page).toHaveBeenCalledExactlyOnceWith(session) expect(vi.mocked(sdk.identify).mock.invocationCallOrder[0]).toBeLessThan( vi.mocked(sdk.page).mock.invocationCallOrder[0]! ) diff --git a/src/renderer/src/customerIo/controller.ts b/src/renderer/src/customerIo/controller.ts index 79887c771..b1de6677b 100644 --- a/src/renderer/src/customerIo/controller.ts +++ b/src/renderer/src/customerIo/controller.ts @@ -2,7 +2,7 @@ import type { CustomerIoSession } from '../../../shared/customerIo' export interface MessagingClient { identify(session: CustomerIoSession): Promise - page(): Promise + page(session: CustomerIoSession): Promise reset(): Promise dismiss(): void } @@ -59,7 +59,7 @@ export function createMessagingController( await bounded(client.identify(session)) if (revision !== version) return identified = session - await bounded(client.page()) + await bounded(client.page(session)) }) .catch((error: unknown) => { client?.dismiss() diff --git a/src/renderer/src/customerIo/index.ts b/src/renderer/src/customerIo/index.ts index 88dde51bf..dabb2916b 100644 --- a/src/renderer/src/customerIo/index.ts +++ b/src/renderer/src/customerIo/index.ts @@ -3,8 +3,6 @@ import Gist from 'customerio-gist-web' import type { CustomerIoSession } from '../../../shared/customerIo' import { createMessagingController } from './controller' -const PAGE = 'desktop/local-workflow' - const controller = createMessagingController(async (session, currentSession) => { const analytics = AnalyticsBrowser.load( { writeKey: session.writeKey }, @@ -24,12 +22,13 @@ const controller = createMessagingController(async (session, currentSession) => await analytics.addSourceMiddleware(({ payload, next }) => { const current = currentSession() if (!current || payload.obj.userId !== current.userId) return + if (payload.obj.type === 'page' && payload.obj.name !== current.page) return // A desktop file path or local workflow URL is not a useful campaign page. payload.obj.context = { ...payload.obj.context, page: { - path: PAGE, - url: PAGE, + path: current.page, + url: current.page, title: 'ComfyUI Desktop', referrer: '', search: '' @@ -64,10 +63,10 @@ const controller = createMessagingController(async (session, currentSession) => Gist.setUserLocale(identity.locale) await analytics.identify(identity.userId, { locale: identity.locale }) }, - page: async () => { - await analytics.page(PAGE, { - url: PAGE, - path: PAGE, + page: async ({ page }) => { + await analytics.page(page, { + url: page, + path: page, title: 'ComfyUI Desktop', search: '', referrer: '' diff --git a/src/shared/customerIo.ts b/src/shared/customerIo.ts index 8b93169c8..32b178d12 100644 --- a/src/shared/customerIo.ts +++ b/src/shared/customerIo.ts @@ -8,9 +8,17 @@ export const CUSTOMER_IO_READY = 'customerio:ready' export const CUSTOMER_IO_STATE = 'customerio:state' export const CUSTOMER_IO_ACTION = 'customerio:action' +/** Stable page names used by Customer.io's in-app page rules. */ +export const CUSTOMER_IO_PAGES = { + comfyui: 'desktop/comfyui', + launcher: 'desktop/launcher' +} as const +export type CustomerIoPage = (typeof CUSTOMER_IO_PAGES)[keyof typeof CUSTOMER_IO_PAGES] + export interface CustomerIoSession { userId: string locale: string writeKey: string siteId: string + page: CustomerIoPage }