mirror of https://github.com/vector-im/riot-web
Add new user signup event tracking in PostHog (#8412)
parent
1127db0514
commit
1ed68a718f
|
@ -88,7 +88,7 @@
|
||||||
"linkifyjs": "^4.0.0-beta.4",
|
"linkifyjs": "^4.0.0-beta.4",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"maplibre-gl": "^1.15.2",
|
"maplibre-gl": "^1.15.2",
|
||||||
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#4aef17b56798639906f26a8739043a3c5c5fde7e",
|
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#761751d7a96c129f118f1e3a89f27e77bbfddf9e",
|
||||||
"matrix-encrypt-attachment": "^1.0.3",
|
"matrix-encrypt-attachment": "^1.0.3",
|
||||||
"matrix-events-sdk": "^0.0.1-beta.7",
|
"matrix-events-sdk": "^0.0.1-beta.7",
|
||||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
||||||
|
|
|
@ -72,11 +72,11 @@ export interface IMatrixClientPeg {
|
||||||
* If we've registered a user ID we set this to the ID of the
|
* If we've registered a user ID we set this to the ID of the
|
||||||
* user we've just registered. If they then go & log in, we
|
* user we've just registered. If they then go & log in, we
|
||||||
* can send them to the welcome user (obviously this doesn't
|
* can send them to the welcome user (obviously this doesn't
|
||||||
* guarentee they'll get a chat with the welcome user).
|
* guarantee they'll get a chat with the welcome user).
|
||||||
*
|
*
|
||||||
* @param {string} uid The user ID of the user we've just registered
|
* @param {string} uid The user ID of the user we've just registered
|
||||||
*/
|
*/
|
||||||
setJustRegisteredUserId(uid: string): void;
|
setJustRegisteredUserId(uid: string | null): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the current user has just been registered by this
|
* Returns true if the current user has just been registered by this
|
||||||
|
@ -139,7 +139,8 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
public setJustRegisteredUserId(uid: string | null): void {
|
public setJustRegisteredUserId(uid: string | null): void {
|
||||||
this.justRegisteredUserId = uid;
|
this.justRegisteredUserId = uid;
|
||||||
if (uid) {
|
if (uid) {
|
||||||
window.localStorage.setItem("mx_registration_time", String(new Date().getTime()));
|
const registrationTime = Date.now().toString();
|
||||||
|
window.localStorage.setItem("mx_registration_time", registrationTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time"));
|
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time"), 10);
|
||||||
const diff = Date.now() - registrationTime;
|
const diff = Date.now() - registrationTime;
|
||||||
return (diff / 36e5) <= hours;
|
return (diff / 36e5) <= hours;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import posthog, { PostHog } from 'posthog-js';
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { UserProperties } from "matrix-analytics-events/types/typescript/UserProperties";
|
import { UserProperties } from "matrix-analytics-events/types/typescript/UserProperties";
|
||||||
|
import { Signup } from 'matrix-analytics-events/types/typescript/Signup';
|
||||||
|
|
||||||
import PlatformPeg from './PlatformPeg';
|
import PlatformPeg from './PlatformPeg';
|
||||||
import SdkConfig from './SdkConfig';
|
import SdkConfig from './SdkConfig';
|
||||||
|
@ -50,6 +51,10 @@ export interface IPosthogEvent {
|
||||||
"$set_once"?: void;
|
"$set_once"?: void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IPostHogEventOptions {
|
||||||
|
timestamp?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
export enum Anonymity {
|
export enum Anonymity {
|
||||||
Disabled,
|
Disabled,
|
||||||
Anonymous,
|
Anonymous,
|
||||||
|
@ -117,6 +122,7 @@ export class PosthogAnalytics {
|
||||||
private static ANALYTICS_EVENT_TYPE = "im.vector.analytics";
|
private static ANALYTICS_EVENT_TYPE = "im.vector.analytics";
|
||||||
private propertiesForNextEvent: Partial<Record<"$set" | "$set_once", UserProperties>> = {};
|
private propertiesForNextEvent: Partial<Record<"$set" | "$set_once", UserProperties>> = {};
|
||||||
private userPropertyCache: UserProperties = {};
|
private userPropertyCache: UserProperties = {};
|
||||||
|
private authenticationType: Signup["authenticationType"] = "Other";
|
||||||
|
|
||||||
public static get instance(): PosthogAnalytics {
|
public static get instance(): PosthogAnalytics {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
|
@ -200,16 +206,20 @@ export class PosthogAnalytics {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private capture(eventName: string, properties: posthog.Properties) {
|
// eslint-disable-nextline no-unused-varsx
|
||||||
|
private capture(eventName: string, properties: posthog.Properties, options?: IPostHogEventOptions) {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { origin, hash, pathname } = window.location;
|
const { origin, hash, pathname } = window.location;
|
||||||
properties["redactedCurrentUrl"] = getRedactedCurrentLocation(origin, hash, pathname);
|
properties["redactedCurrentUrl"] = getRedactedCurrentLocation(origin, hash, pathname);
|
||||||
this.posthog.capture(eventName, {
|
this.posthog.capture(
|
||||||
...this.propertiesForNextEvent,
|
eventName,
|
||||||
...properties,
|
{ ...this.propertiesForNextEvent, ...properties },
|
||||||
});
|
// TODO: Uncomment below once https://github.com/PostHog/posthog-js/pull/391
|
||||||
|
// gets merged
|
||||||
|
/* options as any, */ // No proper type definition in the posthog library
|
||||||
|
);
|
||||||
this.propertiesForNextEvent = {};
|
this.propertiesForNextEvent = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,9 +282,12 @@ export class PosthogAnalytics {
|
||||||
this.setAnonymity(Anonymity.Disabled);
|
this.setAnonymity(Anonymity.Disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public trackEvent<E extends IPosthogEvent>({ eventName, ...properties }: E): void {
|
public trackEvent<E extends IPosthogEvent>(
|
||||||
|
{ eventName, ...properties }: E,
|
||||||
|
options?: IPostHogEventOptions,
|
||||||
|
): void {
|
||||||
if (this.anonymity == Anonymity.Disabled || this.anonymity == Anonymity.Anonymous) return;
|
if (this.anonymity == Anonymity.Disabled || this.anonymity == Anonymity.Anonymous) return;
|
||||||
this.capture(eventName, properties);
|
this.capture(eventName, properties, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setProperty<K extends keyof UserProperties>(key: K, value: UserProperties[K]): void {
|
public setProperty<K extends keyof UserProperties>(key: K, value: UserProperties[K]): void {
|
||||||
|
@ -313,6 +326,9 @@ export class PosthogAnalytics {
|
||||||
this.setAnonymity(anonymity);
|
this.setAnonymity(anonymity);
|
||||||
if (anonymity === Anonymity.Pseudonymous) {
|
if (anonymity === Anonymity.Pseudonymous) {
|
||||||
await this.identifyUser(MatrixClientPeg.get(), PosthogAnalytics.getRandomAnalyticsId);
|
await this.identifyUser(MatrixClientPeg.get(), PosthogAnalytics.getRandomAnalyticsId);
|
||||||
|
if (MatrixClientPeg.currentUserIsJustRegistered()) {
|
||||||
|
this.trackNewUserEvent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anonymity !== Anonymity.Disabled) {
|
if (anonymity !== Anonymity.Disabled) {
|
||||||
|
@ -334,4 +350,25 @@ export class PosthogAnalytics {
|
||||||
this.updateAnonymityFromSettings(!!newValue);
|
this.updateAnonymityFromSettings(!!newValue);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setAuthenticationType(authenticationType: Signup["authenticationType"]): void {
|
||||||
|
this.authenticationType = authenticationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private trackNewUserEvent(): void {
|
||||||
|
// This is the only event that could have occured before analytics opt-in
|
||||||
|
// that we want to accumulate before the user has given consent
|
||||||
|
// All other scenarios should not track a user before they have given
|
||||||
|
// explicit consent that they are ok with their analytics data being collected
|
||||||
|
const options: IPostHogEventOptions = {};
|
||||||
|
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time"), 10);
|
||||||
|
if (!isNaN(registrationTime)) {
|
||||||
|
options.timestamp = new Date(registrationTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.trackEvent<Signup>({
|
||||||
|
eventName: "Signup",
|
||||||
|
authenticationType: this.authenticationType,
|
||||||
|
}, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import Field from '../elements/Field';
|
||||||
import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog';
|
import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog';
|
||||||
import CountryDropdown from "./CountryDropdown";
|
import CountryDropdown from "./CountryDropdown";
|
||||||
import PassphraseConfirmField from "./PassphraseConfirmField";
|
import PassphraseConfirmField from "./PassphraseConfirmField";
|
||||||
|
import { PosthogAnalytics } from '../../../PosthogAnalytics';
|
||||||
|
|
||||||
enum RegistrationField {
|
enum RegistrationField {
|
||||||
Email = "field_email",
|
Email = "field_email",
|
||||||
|
@ -147,6 +148,8 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
|
||||||
};
|
};
|
||||||
|
|
||||||
private doSubmit(ev) {
|
private doSubmit(ev) {
|
||||||
|
PosthogAnalytics.instance.setAuthenticationType("Password");
|
||||||
|
|
||||||
const email = this.state.email.trim();
|
const email = this.state.email.trim();
|
||||||
|
|
||||||
const promise = this.props.onRegisterClick({
|
const promise = this.props.onRegisterClick({
|
||||||
|
|
|
@ -18,6 +18,7 @@ import React from "react";
|
||||||
import { chunk } from "lodash";
|
import { chunk } from "lodash";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
import { Signup } from "matrix-analytics-events/types/typescript/Signup";
|
||||||
|
|
||||||
import PlatformPeg from "../../../PlatformPeg";
|
import PlatformPeg from "../../../PlatformPeg";
|
||||||
import AccessibleButton from "./AccessibleButton";
|
import AccessibleButton from "./AccessibleButton";
|
||||||
|
@ -25,6 +26,7 @@ import { _t } from "../../../languageHandler";
|
||||||
import { IdentityProviderBrand, IIdentityProvider, ISSOFlow } from "../../../Login";
|
import { IdentityProviderBrand, IIdentityProvider, ISSOFlow } from "../../../Login";
|
||||||
import AccessibleTooltipButton from "./AccessibleTooltipButton";
|
import AccessibleTooltipButton from "./AccessibleTooltipButton";
|
||||||
import { mediaFromMxc } from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
|
import { PosthogAnalytics } from "../../../PosthogAnalytics";
|
||||||
|
|
||||||
interface ISSOButtonProps extends Omit<IProps, "flow"> {
|
interface ISSOButtonProps extends Omit<IProps, "flow"> {
|
||||||
idp: IIdentityProvider;
|
idp: IIdentityProvider;
|
||||||
|
@ -50,6 +52,26 @@ const getIcon = (brand: IdentityProviderBrand | string) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAuthenticationType = (brand: IdentityProviderBrand | string): Signup["authenticationType"] => {
|
||||||
|
switch (brand) {
|
||||||
|
case IdentityProviderBrand.Apple:
|
||||||
|
return "Apple";
|
||||||
|
case IdentityProviderBrand.Facebook:
|
||||||
|
return "Facebook";
|
||||||
|
case IdentityProviderBrand.Github:
|
||||||
|
return "GitHub";
|
||||||
|
case IdentityProviderBrand.Gitlab:
|
||||||
|
return "GitLab";
|
||||||
|
case IdentityProviderBrand.Google:
|
||||||
|
return "Google";
|
||||||
|
// Not supported on the analytics SDK at the moment.
|
||||||
|
// case IdentityProviderBrand.Twitter:
|
||||||
|
// return "Twitter";
|
||||||
|
default:
|
||||||
|
return "SSO";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const SSOButton: React.FC<ISSOButtonProps> = ({
|
const SSOButton: React.FC<ISSOButtonProps> = ({
|
||||||
matrixClient,
|
matrixClient,
|
||||||
loginType,
|
loginType,
|
||||||
|
@ -62,6 +84,8 @@ const SSOButton: React.FC<ISSOButtonProps> = ({
|
||||||
const label = idp ? _t("Continue with %(provider)s", { provider: idp.name }) : _t("Sign in with single sign-on");
|
const label = idp ? _t("Continue with %(provider)s", { provider: idp.name }) : _t("Sign in with single sign-on");
|
||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
|
const authenticationType = getAuthenticationType(idp.brand);
|
||||||
|
PosthogAnalytics.instance.setAuthenticationType(authenticationType);
|
||||||
PlatformPeg.get().startSingleSignOn(matrixClient, loginType, fragmentAfterLogin, idp?.id);
|
PlatformPeg.get().startSingleSignOn(matrixClient, loginType, fragmentAfterLogin, idp?.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6629,9 +6629,9 @@ mathml-tag-names@^2.1.3:
|
||||||
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
|
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
|
||||||
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
|
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
|
||||||
|
|
||||||
"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#4aef17b56798639906f26a8739043a3c5c5fde7e":
|
"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#761751d7a96c129f118f1e3a89f27e77bbfddf9e":
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/4aef17b56798639906f26a8739043a3c5c5fde7e"
|
resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/761751d7a96c129f118f1e3a89f27e77bbfddf9e"
|
||||||
|
|
||||||
matrix-encrypt-attachment@^1.0.3:
|
matrix-encrypt-attachment@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
|
|
Loading…
Reference in New Issue