posthog?.capture('new_app_created')}
disabled={isSubmitting}
>
{isSubmitting && (
diff --git a/apps/passport/app/root.tsx b/apps/passport/app/root.tsx
index 9aae45190c..dc66d3afd9 100644
--- a/apps/passport/app/root.tsx
+++ b/apps/passport/app/root.tsx
@@ -256,9 +256,6 @@ export default function App() {
autocapture: false,
})
posthog?.reset()
- posthog?.group('app', browserEnv?.appProps?.clientId, {
- name: browserEnv?.appProps?.name,
- })
} catch (ex) {
console.error(ex)
}
diff --git a/apps/passport/app/routes/authorize.tsx b/apps/passport/app/routes/authorize.tsx
index 4d1dc6456d..9cbc03df7c 100644
--- a/apps/passport/app/routes/authorize.tsx
+++ b/apps/passport/app/routes/authorize.tsx
@@ -46,7 +46,6 @@ import { Helmet } from 'react-helmet'
import { getRGBColor, getTextColor } from '@proofzero/design-system/src/helpers'
import { AccountURNSpace } from '@proofzero/urns/account'
import type { DropdownSelectListItem } from '@proofzero/design-system/src/atoms/dropdown/DropdownSelectList'
-import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export type UserProfile = {
displayName: string
@@ -374,19 +373,6 @@ export const action: ActionFunction = async ({ request, context }) => {
throw json({ message: 'Failed to authorize' }, 400)
}
- await createAnalyticsEvent({
- eventName: 'app_authorized',
- distinctId: identityURN,
- apiKey: context.env.POSTHOG_API_KEY,
- groups: {
- app: clientId,
- },
- properties: {
- clientId: clientId,
- scope: scope,
- },
- })
-
const redirectParams = new URLSearchParams({
code: authorizeRes.code,
state: authorizeRes.state,
@@ -444,8 +430,8 @@ export default function Authorize() {
return [AuthorizationControlSelection.ALL]
} else {
return connectedAccounts?.length
- ? connectedAccounts.filter(
- (acc) => persona.connected_accounts?.includes(acc.value)
+ ? connectedAccounts.filter((acc) =>
+ persona.connected_accounts?.includes(acc.value)
)
: []
}
@@ -457,8 +443,8 @@ export default function Authorize() {
return [AuthorizationControlSelection.ALL]
} else {
return connectedSmartContractWallets?.length
- ? connectedSmartContractWallets.filter(
- (acc) => persona.erc_4337?.includes(acc.value)
+ ? connectedSmartContractWallets.filter((acc) =>
+ persona.erc_4337?.includes(acc.value)
)
: []
}
diff --git a/apps/passport/app/routes/settings.tsx b/apps/passport/app/routes/settings.tsx
index c83f306cb8..3229187b8f 100644
--- a/apps/passport/app/routes/settings.tsx
+++ b/apps/passport/app/routes/settings.tsx
@@ -159,7 +159,9 @@ export default function SettingsLayout() {
// need to identify only once
useEffect(() => {
- if (!isIdentified) posthog?.identify(identityURN)
+ if (!isIdentified) {
+ posthog?.identify(identityURN)
+ }
setIsIdentified(true)
}, [isIdentified])
diff --git a/apps/passport/app/routes/settings/accounts/rename.tsx b/apps/passport/app/routes/settings/accounts/rename.tsx
index 980b093851..2586b342ea 100644
--- a/apps/passport/app/routes/settings/accounts/rename.tsx
+++ b/apps/passport/app/routes/settings/accounts/rename.tsx
@@ -1,21 +1,9 @@
import type { ActionFunction } from '@remix-run/cloudflare'
import { getCoreClient } from '~/platform.server'
-import {
- getDefaultAuthzParams,
- getValidatedSessionContext,
-} from '~/session.server'
import { getRollupReqFunctionErrorWrapper } from '@proofzero/utils/errors'
-import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export const action: ActionFunction = getRollupReqFunctionErrorWrapper(
async ({ request, context }) => {
- const { identityURN } = await getValidatedSessionContext(
- request,
- getDefaultAuthzParams(request),
- context.env,
- context.traceSpan
- )
-
const formData = await request.formData()
const name = formData.get('name') as string
const accountURN = formData.get('id') as string
@@ -25,16 +13,6 @@ export const action: ActionFunction = getRollupReqFunctionErrorWrapper(
nickname: name,
})
- await createAnalyticsEvent({
- apiKey: context.env.POSTHOG_API_KEY,
- distinctId: identityURN,
- eventName: 'account_renamed',
- properties: {
- accountId: accountURN,
- nickname: name,
- },
- })
-
return null
}
)
diff --git a/apps/passport/app/routes/settings/advanced.tsx b/apps/passport/app/routes/settings/advanced.tsx
index c2f599f6a6..e48b314dda 100644
--- a/apps/passport/app/routes/settings/advanced.tsx
+++ b/apps/passport/app/routes/settings/advanced.tsx
@@ -80,6 +80,12 @@ export const action: ActionFunction = getRollupReqFunctionErrorWrapper(
await coreClient.identity.deleteIdentityNode.mutate({
identity: identityURN,
})
+
+ await createAnalyticsEvent({
+ apiKey: context.env.POSTHOG_API_KEY,
+ eventName: 'identity_deleted_identity',
+ distinctId: identityURN,
+ })
} catch (ex) {
console.error(ex)
throw new RollupError({
@@ -89,12 +95,6 @@ export const action: ActionFunction = getRollupReqFunctionErrorWrapper(
})
}
- await createAnalyticsEvent({
- apiKey: context.env.POSTHOG_API_KEY,
- eventName: 'delete_rollup_identity',
- distinctId: identityURN,
- })
-
return await destroyUserSession(
request,
'/',
diff --git a/apps/passport/app/routes/settings/applications/$clientId/revoke.tsx b/apps/passport/app/routes/settings/applications/$clientId/revoke.tsx
index ffc5ad0da6..15a6bf3855 100644
--- a/apps/passport/app/routes/settings/applications/$clientId/revoke.tsx
+++ b/apps/passport/app/routes/settings/applications/$clientId/revoke.tsx
@@ -7,13 +7,12 @@ import { getCoreClient } from '~/platform.server'
import { getFlashSession, commitFlashSession } from '~/session.server'
import { BadRequestError } from '@proofzero/errors'
import { getRollupReqFunctionErrorWrapper } from '@proofzero/utils/errors'
-import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export const action: ActionFunction = getRollupReqFunctionErrorWrapper(
async ({ request, params, context }) => {
const session = await getFlashSession(request, context.env)
- const { jwt, identityURN } = await getValidatedSessionContext(
+ const { jwt } = await getValidatedSessionContext(
request,
context.authzQueryParams,
context.env,
@@ -33,16 +32,6 @@ export const action: ActionFunction = getRollupReqFunctionErrorWrapper(
issuer: new URL(request.url).origin,
})
- await createAnalyticsEvent({
- apiKey: context.env.POSTHOG_API_KEY,
- distinctId: identityURN,
- eventName: 'app_authorization_revoked',
- properties: {
- clientId,
- },
- groups: { app: clientId },
- })
-
session.flash(
'tooltipMessage',
JSON.stringify({
diff --git a/packages/utils/analytics.ts b/packages/utils/analytics.ts
index aeb7b9f861..e6750388be 100644
--- a/packages/utils/analytics.ts
+++ b/packages/utils/analytics.ts
@@ -3,20 +3,17 @@ export const createAnalyticsEvent = async ({
apiKey,
distinctId,
properties,
- groups,
}: {
eventName: string
apiKey: string
distinctId: string
- groups?: Record
properties?: Record
}) => {
const body = JSON.stringify({
api_key: apiKey,
event: eventName,
distinct_id: distinctId,
- groups: groups,
- properties: properties,
+ properties,
})
const init = {
diff --git a/platform/account/src/jsonrpc/methods/resolveIdentity.ts b/platform/account/src/jsonrpc/methods/resolveIdentity.ts
index c5ac3380fd..bdd9923be6 100644
--- a/platform/account/src/jsonrpc/methods/resolveIdentity.ts
+++ b/platform/account/src/jsonrpc/methods/resolveIdentity.ts
@@ -38,7 +38,7 @@ export const resolveIdentityMethod = async ({
}): Promise => {
const nodeClient = ctx.account
- let eventName = 'identity-resolved'
+ let eventName = 'account_resolved_identity'
let resultURN = await nodeClient?.class.getIdentity()
if (input.jwt && resultURN) {
@@ -56,7 +56,7 @@ export const resolveIdentityMethod = async ({
} else {
const name = hexlify(randomBytes(IDENTITY_OPTIONS.length))
urn = IdentityURNSpace.componentizedUrn(name)
- eventName = 'identity-created'
+ eventName = 'account_created_identity'
}
const caller = router.createCaller(ctx)
await caller.account.setIdentity(urn) // this will lazy create an identity node when identity worker is called
@@ -73,7 +73,9 @@ export const resolveIdentityMethod = async ({
apiKey: ctx.POSTHOG_API_KEY,
eventName,
distinctId: resultURN,
- groups: { app: input.clientId },
+ properties: {
+ $groups: { app: input.clientId },
+ },
})
return {
diff --git a/platform/authorization/src/jsonrpc/methods/authorize.ts b/platform/authorization/src/jsonrpc/methods/authorize.ts
index b2c4dae438..1ef45c3693 100644
--- a/platform/authorization/src/jsonrpc/methods/authorize.ts
+++ b/platform/authorization/src/jsonrpc/methods/authorize.ts
@@ -8,6 +8,7 @@ import { initExchangeCodeNodeByName } from '../../nodes'
import { hexlify } from '@ethersproject/bytes'
import { randomBytes } from '@ethersproject/random'
import { PersonaData } from '@proofzero/types/application'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export const AuthorizeMethodInput = z.object({
identity: IdentityURNInput,
@@ -59,5 +60,18 @@ export const authorizeMethod = async ({
personaData
)
+ // We don't track hacky way to create user session.
+ if (!scope.includes('admin')) {
+ await createAnalyticsEvent({
+ eventName: 'identity_authorized_app',
+ distinctId: identity,
+ apiKey: ctx.POSTHOG_API_KEY,
+ properties: {
+ scope: scope,
+ $groups: { app: clientId },
+ },
+ })
+ }
+
return { ...result }
}
diff --git a/platform/authorization/src/jsonrpc/methods/exchangeToken.ts b/platform/authorization/src/jsonrpc/methods/exchangeToken.ts
index 5c63aaf515..158956b7c7 100644
--- a/platform/authorization/src/jsonrpc/methods/exchangeToken.ts
+++ b/platform/authorization/src/jsonrpc/methods/exchangeToken.ts
@@ -38,6 +38,7 @@ import {
userClaimsFormatter,
} from '@proofzero/security/persona'
import { UnauthorizedError } from '@proofzero/errors'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
const AuthenticationCodeInput = z.object({
grantType: z.literal(GrantType.AuthenticationCode),
@@ -121,15 +122,30 @@ export const exchangeTokenMethod: ExchangeTokenMethod = async ({
input,
}) => {
const { grantType } = input
+ let result, eventObject
if (grantType == GrantType.AuthenticationCode) {
- return handleAuthenticationCode({ ctx, input })
+ result = handleAuthenticationCode({ ctx, input })
+ eventObject = 'authn_code'
} else if (grantType == GrantType.AuthorizationCode) {
- return handleAuthorizationCode({ ctx, input })
+ result = handleAuthorizationCode({ ctx, input })
+ eventObject = 'auth_code'
} else if (grantType == GrantType.RefreshToken) {
- return handleRefreshToken({ ctx, input })
+ result = handleRefreshToken({ ctx, input })
+ eventObject = 'refresh_token'
} else {
throw new UnsupportedGrantTypeError(grantType)
}
+
+ await createAnalyticsEvent({
+ eventName: `app_exchanged_${eventObject}`,
+ distinctId: ctx.identityURN as IdentityURN,
+ apiKey: ctx.POSTHOG_API_KEY,
+ properties: {
+ $groups: { app: input.clientId },
+ },
+ })
+
+ return result
}
const handleAuthenticationCode: ExchangeTokenMethod<
diff --git a/platform/authorization/src/jsonrpc/methods/revokeAppAuthorization.ts b/platform/authorization/src/jsonrpc/methods/revokeAppAuthorization.ts
index 37264d27e7..9a5db67180 100644
--- a/platform/authorization/src/jsonrpc/methods/revokeAppAuthorization.ts
+++ b/platform/authorization/src/jsonrpc/methods/revokeAppAuthorization.ts
@@ -5,16 +5,12 @@ import { router } from '@proofzero/platform.core'
import { Context } from '../../context'
import { initAuthorizationNodeByName } from '../../nodes'
-import {
- EDGE_AUTHORIZES,
- ROLLUP_INTERNAL_ACCESS_TOKEN_URN,
-} from '../../constants'
+import { EDGE_AUTHORIZES } from '../../constants'
import { IdentityURNSpace } from '@proofzero/urns/identity'
import { AuthorizationURNSpace } from '@proofzero/urns/authorization'
-import { generateJKU, getPrivateJWK } from '../../jwk'
-import { generateTraceContextHeaders } from '@proofzero/platform-middleware/trace'
import { EDGE_HAS_REFERENCE_TO } from '@proofzero/types/graph'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export const RevokeAppAuthorizationMethodInput = z.object({
clientId: z.string().min(1),
@@ -143,4 +139,13 @@ export const revokeAppAuthorizationMethod: RevokeAppAuthorizationMethod =
}
await authorizationNode.class.deleteAll()
+
+ await createAnalyticsEvent({
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: identityURN,
+ eventName: 'identity_revoked_authorization',
+ properties: {
+ $groups: { app: clientId },
+ },
+ })
}
diff --git a/platform/identity/src/jsonrpc/methods/identity-groups/createIdentityGroup.ts b/platform/identity/src/jsonrpc/methods/identity-groups/createIdentityGroup.ts
index 34843366c4..6dfbe60d20 100644
--- a/platform/identity/src/jsonrpc/methods/identity-groups/createIdentityGroup.ts
+++ b/platform/identity/src/jsonrpc/methods/identity-groups/createIdentityGroup.ts
@@ -7,7 +7,8 @@ import { IdentityGroupURNSpace } from '@proofzero/urns/identity-group'
import { EDGE_MEMBER_OF_IDENTITY_GROUP } from '@proofzero/types/graph'
import { Context } from '../../../context'
-import { IdentityURN } from '@proofzero/urns/identity'
+import type { IdentityURN } from '@proofzero/urns/identity'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export const CreateIdentityGroupInputSchema = z.object({
name: z.string(),
@@ -39,4 +40,29 @@ export const createIdentityGroup = async ({
tag: EDGE_MEMBER_OF_IDENTITY_GROUP,
dst: baseGroupURN,
})
+
+ await createAnalyticsEvent({
+ eventName: '$groupidentify',
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: ctx.identityURN as IdentityURN,
+ properties: {
+ $groups: { group: groupURN },
+ $group_type: 'group',
+ $group_key: groupURN,
+ $group_set: {
+ name: input.name,
+ groupURN: groupURN,
+ date_joined: new Date().toISOString(),
+ },
+ },
+ })
+
+ await createAnalyticsEvent({
+ eventName: 'identity_created_group',
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: ctx.identityURN as IdentityURN,
+ properties: {
+ $groups: { group: groupURN },
+ },
+ })
}
diff --git a/platform/identity/src/jsonrpc/methods/identity-groups/inviteIdentityGroupMember.ts b/platform/identity/src/jsonrpc/methods/identity-groups/inviteIdentityGroupMember.ts
index 59faf87512..ba7732c5fe 100644
--- a/platform/identity/src/jsonrpc/methods/identity-groups/inviteIdentityGroupMember.ts
+++ b/platform/identity/src/jsonrpc/methods/identity-groups/inviteIdentityGroupMember.ts
@@ -13,6 +13,7 @@ import { router } from '@proofzero/platform.core'
import { AccountURN, AccountURNSpace } from '@proofzero/urns/account'
import generateRandomString from '@proofzero/utils/generateRandomString'
import { IdentityURN } from '@proofzero/urns/identity'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
export const InviteIdentityGroupMemberInputSchema = z.object({
identityGroupURN: IdentityGroupURNValidator,
@@ -87,6 +88,15 @@ export const inviteIdentityGroupMember = async ({
inviteCode,
})
+ await createAnalyticsEvent({
+ eventName: 'group_invited_member',
+ distinctId: inviterIdentityURN,
+ apiKey: ctx.POSTHOG_API_KEY,
+ properties: {
+ $groups: { group: identityGroupURN },
+ },
+ })
+
return {
inviteCode,
}
diff --git a/platform/starbase/src/jsonrpc/methods/createApp.ts b/platform/starbase/src/jsonrpc/methods/createApp.ts
index 712fde740d..9877caecb0 100644
--- a/platform/starbase/src/jsonrpc/methods/createApp.ts
+++ b/platform/starbase/src/jsonrpc/methods/createApp.ts
@@ -5,6 +5,8 @@ import * as oauth from '../../OAuth'
import { getApplicationNodeByClientId } from '../../nodes/application'
import { ApplicationURNSpace } from '@proofzero/urns/application'
import { EDGE_APPLICATION } from '../../types'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
+import { ServicePlanType } from '@proofzero/types/identity'
export const CreateAppInputSchema = z.object({
clientName: z.string(),
@@ -55,6 +57,32 @@ export const createApp = async ({
console.log(`Created app ${clientId} for account ${ctx.accountURN}`)
}
+ await createAnalyticsEvent({
+ eventName: '$groupidentify',
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: ctx.identityURN,
+ properties: {
+ $groups: { app: clientId },
+ $group_type: 'app',
+ $group_key: clientId,
+ $group_set: {
+ name: input.clientName,
+ plan: ServicePlanType.FREE,
+ clientId: clientId,
+ date_joined: new Date().toISOString(),
+ },
+ },
+ })
+
+ await createAnalyticsEvent({
+ eventName: 'identity_created_app',
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: ctx.identityURN,
+ properties: {
+ $groups: { app: clientId },
+ },
+ })
+
return {
clientId: clientId,
}
diff --git a/platform/starbase/src/jsonrpc/methods/deleteApp.ts b/platform/starbase/src/jsonrpc/methods/deleteApp.ts
index 37cbe9c0f9..bdcb658e78 100644
--- a/platform/starbase/src/jsonrpc/methods/deleteApp.ts
+++ b/platform/starbase/src/jsonrpc/methods/deleteApp.ts
@@ -7,6 +7,8 @@ import { ApplicationURNSpace } from '@proofzero/urns/application'
import { AppClientIdParamSchema } from '../validators/app'
import { EDGE_APPLICATION } from '../../types'
import { EDGE_HAS_REFERENCE_TO } from '@proofzero/types/graph'
+import { createAnalyticsEvent } from '@proofzero/utils/analytics'
+import type { IdentityURN } from '@proofzero/urns/identity'
export const DeleteAppInput = AppClientIdParamSchema
@@ -64,5 +66,12 @@ export const deleteApp = async ({
})
await appDO.class.delete()
- console.log(`Deleted app ${input.clientId} from account ${ctx.accountURN}`)
+ await createAnalyticsEvent({
+ apiKey: ctx.POSTHOG_API_KEY,
+ eventName: 'identity_deleted_app',
+ distinctId: ctx.identityURN as IdentityURN,
+ properties: {
+ $groups: { app: input.clientId },
+ },
+ })
}
diff --git a/platform/starbase/src/jsonrpc/methods/publishApp.ts b/platform/starbase/src/jsonrpc/methods/publishApp.ts
index d07d1ae61b..dd3b5cf0ff 100644
--- a/platform/starbase/src/jsonrpc/methods/publishApp.ts
+++ b/platform/starbase/src/jsonrpc/methods/publishApp.ts
@@ -8,6 +8,7 @@ import { createAnalyticsEvent } from '@proofzero/utils/analytics'
import { Context } from '../context'
import { getApplicationNodeByClientId } from '../../nodes/application'
+import type { IdentityURN } from '@proofzero/urns/identity'
export const PublishAppInput = z.object({
clientId: z.string(),
@@ -57,25 +58,14 @@ export const publishApp = async ({
await appDO.class.publish(input.published)
- let eventName = undefined
-
- if (!appDetails.published && input.published) {
- eventName = 'app_published'
- } else if (appDetails.published && !input.published) {
- /**
- * We can unpublish an app only if it was published before.
- */
- eventName = 'app_unpublished'
- }
-
- if (eventName)
- await createAnalyticsEvent({
- distinctId: ctx.accountURN as string,
- eventName,
- apiKey: ctx.POSTHOG_API_KEY,
- properties: { client_id: input.clientId },
- groups: { app: input.clientId },
- })
+ await createAnalyticsEvent({
+ distinctId: ctx.identityURN as IdentityURN,
+ eventName: input.published
+ ? 'identity_published_app'
+ : 'identity_unpublished_app',
+ apiKey: ctx.POSTHOG_API_KEY,
+ properties: { $groups: { app: input.clientId } },
+ })
return {
published: true,
diff --git a/platform/starbase/src/jsonrpc/methods/setAppPlan.ts b/platform/starbase/src/jsonrpc/methods/setAppPlan.ts
index b731c497dc..c9db49fad5 100644
--- a/platform/starbase/src/jsonrpc/methods/setAppPlan.ts
+++ b/platform/starbase/src/jsonrpc/methods/setAppPlan.ts
@@ -54,17 +54,6 @@ export const setAppPlan = async ({
dst: appURN,
})
}
-
- await createAnalyticsEvent({
- eventName: 'app_pro_plan_set',
- apiKey: ctx.POSTHOG_API_KEY,
- distinctId: input.identityURN,
- groups: { app: input.clientId },
- properties: {
- clientId: input.clientId,
- plan,
- },
- })
} else {
await caller.edges.removeEdge({
src: identityURN,
@@ -72,4 +61,28 @@ export const setAppPlan = async ({
dst: appURN,
})
}
+
+ // This is the way how we can update group properties
+ // https://posthog.com/tutorials/frontend-vs-backend-group-analytics
+ await createAnalyticsEvent({
+ eventName: '$groupidentify',
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: identityURN,
+ properties: {
+ $group_type: 'app',
+ $group_key: clientId,
+ $group_set: {
+ plan,
+ },
+ },
+ })
+
+ await createAnalyticsEvent({
+ eventName: `app_set_${plan}_plan`,
+ apiKey: ctx.POSTHOG_API_KEY,
+ distinctId: identityURN,
+ properties: {
+ $groups: { app: clientId },
+ },
+ })
}