mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat(cli): associate signed-in HeyGen account with telemetry (#2020)
* feat(cli): associate signed-in HeyGen account with telemetry Sign-in telemetry currently attributes everything to the anonymous install id, so the sign-in funnel can be counted but a completed sign-in can't be tied to the account it produced. This associates the two. - On a completed sign-in, emit a PostHog `$identify` alias whose `$anon_distinct_id` is the install's anonymousId, so events recorded before sign-in stitch to the same person, and tag `auth_login_completed` with the account identity (the pre-plumbed `distinctId`). - `/v3/users/me` exposes no opaque user_id, so the identity key is the account email, falling back to username (single `identityKey` helper). - Both no-op under the `telemetry disable` opt-out and only fire after the user chooses to sign in. Privacy disclosure updated in lockstep, since this is the first PII the CLI attaches: the first-run telemetry notice and the telemetry section of docs/packages/cli.mdx now state that signing in links your account email to your usage. Tests: identifyUser payload + no-op, completion attribution incl. username fallback and no-identity-on-reject/empty. Verified end-to-end against the built CLI: pre-auth events anonymous, $identify carries $anon_distinct_id, completion carries the account email. * docs(cli): disclose the username identity fallback Review gating item: identityKey is `email ?? username`, but the first-run notice and cli.mdx said only "email", so an emailless account's username would reach PostHog undisclosed. `/v3/users/me` treats email as optional (pickString), so the fallback is live code, not dead — disclose it rather than assert an unverifiable email guarantee. Both surfaces now say "email, or username if the account has no email". Also soften the identityKey comment: it implied username is "less identifying", but HeyGen usernames are often email-shaped, so the note now states username is a fallback, not a privacy win.
This commit is contained in:
@@ -191,7 +191,10 @@ export function showTelemetryNotice(): boolean {
|
||||
|
||||
console.log();
|
||||
console.log(` ${c.dim("Hyperframes collects anonymous usage data to improve the tool.")}`);
|
||||
console.log(` ${c.dim("No personal info, file paths, or content is collected.")}`);
|
||||
console.log(` ${c.dim("File paths and composition content are never collected.")}`);
|
||||
console.log(
|
||||
` ${c.dim("If you sign in to HeyGen, your account (email, or username) is linked to your usage.")}`,
|
||||
);
|
||||
console.log();
|
||||
console.log(` ${c.dim("Disable anytime:")} ${c.accent("hyperframes telemetry disable")}`);
|
||||
console.log();
|
||||
|
||||
@@ -5,6 +5,12 @@ vi.mock("./client.js", () => ({
|
||||
trackEvent: (...args: unknown[]) => trackEvent(...args),
|
||||
}));
|
||||
|
||||
// identifyUser reads the install anonymousId; pin it so the $identify alias is
|
||||
// deterministic and the test never touches disk.
|
||||
vi.mock("./config.js", () => ({
|
||||
readConfig: () => ({ anonymousId: "anon-test-123", telemetryEnabled: true }),
|
||||
}));
|
||||
|
||||
const {
|
||||
trackRenderComplete,
|
||||
trackRenderError,
|
||||
@@ -17,6 +23,7 @@ const {
|
||||
trackAuthLoginStarted,
|
||||
trackAuthLoginCompleted,
|
||||
trackAuthLoginFailed,
|
||||
identifyUser,
|
||||
} = await import("./events.js");
|
||||
|
||||
describe("render telemetry events", () => {
|
||||
@@ -285,12 +292,26 @@ describe("auth login telemetry events", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards an explicit distinctId to trackEvent for future user-level attribution", () => {
|
||||
trackAuthLoginCompleted("oauth", "heygen-user-123");
|
||||
it("forwards an explicit distinctId to trackEvent for user-level attribution", () => {
|
||||
trackAuthLoginCompleted("oauth", "alice@example.com");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"auth_login_completed",
|
||||
{ method: "oauth" },
|
||||
"heygen-user-123",
|
||||
"alice@example.com",
|
||||
);
|
||||
});
|
||||
|
||||
it("identifyUser emits a $identify alias linking the anon install to the identity", () => {
|
||||
identifyUser("alice@example.com");
|
||||
expect(trackEvent).toHaveBeenCalledWith(
|
||||
"$identify",
|
||||
{ $anon_distinct_id: "anon-test-123" },
|
||||
"alice@example.com",
|
||||
);
|
||||
});
|
||||
|
||||
it("identifyUser is a no-op when there is no identity to attach", () => {
|
||||
identifyUser("");
|
||||
expect(trackEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { redactTelemetryString, type OutputResolutionIssueKind } from "@hyperframes/core";
|
||||
import { trackEvent } from "./client.js";
|
||||
import { readConfig } from "./config.js";
|
||||
|
||||
export interface RenderObservabilityTelemetryPayload {
|
||||
observabilityRenderJobId?: string;
|
||||
@@ -387,6 +388,18 @@ export function trackAuthLoginFailed(
|
||||
trackEvent("auth_login_failed", { method, reason }, distinctId);
|
||||
}
|
||||
|
||||
// Associate this install with the signed-in HeyGen account after a completed
|
||||
// sign-in. Emits a PostHog `$identify` alias whose `$anon_distinct_id` is the
|
||||
// install's anonymousId, so events recorded before sign-in stitch to the same
|
||||
// person instead of stranding as a separate anonymous profile. Routed through
|
||||
// trackEvent so it shares the opt-out gate and flush path — a no-op when
|
||||
// telemetry is disabled. `distinctId` is the account email (else username);
|
||||
// see the privacy notice in showTelemetryNotice and docs/packages/cli.mdx.
|
||||
export function identifyUser(distinctId: string): void {
|
||||
if (!distinctId) return;
|
||||
trackEvent("$identify", { $anon_distinct_id: readConfig().anonymousId }, distinctId);
|
||||
}
|
||||
|
||||
// A render was rejected by the output-resolution/alpha/HDR pre-flight (P1-3)
|
||||
// before any browser/ffmpeg work. Counts the "caught early" saves on dashboard
|
||||
// 1783183, distinct from deep render failures. `kind` is the low-cardinality
|
||||
|
||||
@@ -12,5 +12,6 @@ export {
|
||||
trackAuthLoginStarted,
|
||||
trackAuthLoginCompleted,
|
||||
trackAuthLoginFailed,
|
||||
identifyUser,
|
||||
} from "./events.js";
|
||||
export { getSystemMeta, getShmSizeMb, getFreeDiskMb, bytesToMb } from "./system.js";
|
||||
|
||||
Reference in New Issue
Block a user