diff --git a/apps/studio/lib/telemetry.test.tsx b/apps/studio/lib/telemetry.test.tsx
index 4d2d1656a78..5fba56af9bf 100644
--- a/apps/studio/lib/telemetry.test.tsx
+++ b/apps/studio/lib/telemetry.test.tsx
@@ -7,6 +7,7 @@ const mocks = vi.hoisted(() => ({
identify: vi.fn(),
useUser: vi.fn(),
useOrganizationsQuery: vi.fn(),
+ setUser: vi.fn(),
}))
vi.mock('common', async (importOriginal) => {
@@ -34,7 +35,7 @@ vi.mock('@/hooks/misc/useSelectedOrganization', () => ({
}))
vi.mock('@sentry/nextjs', () => ({
- setUser: vi.fn(),
+ setUser: (...args: unknown[]) => mocks.setUser(...args),
}))
const USER_ID = 'user-abc-123'
@@ -48,6 +49,7 @@ describe('Telemetry — posthog identify mirroring', () => {
mocks.identify.mockReset()
mocks.useUser.mockReset()
mocks.useOrganizationsQuery.mockReset()
+ mocks.setUser.mockReset()
})
it('fires identify with both org_count and signup_timestamp when user and orgs are loaded', async () => {
@@ -146,3 +148,32 @@ describe('Telemetry — posthog identify mirroring', () => {
expect(mocks.identify).not.toHaveBeenCalled()
})
})
+
+describe('Telemetry — Sentry user identification', () => {
+ beforeEach(() => {
+ mocks.identify.mockReset()
+ mocks.useUser.mockReset()
+ mocks.useOrganizationsQuery.mockReset()
+ mocks.setUser.mockReset()
+ })
+
+ it('sets the raw (un-hashed) user id on Sentry', async () => {
+ mocks.useUser.mockReturnValue({ id: USER_ID, created_at: CREATED_AT })
+ mocks.useOrganizationsQuery.mockReturnValue({ data: orgs(1) })
+
+ render()
+
+ await waitFor(() => {
+ expect(mocks.setUser).toHaveBeenCalledWith({ id: USER_ID })
+ })
+ })
+
+ it('does not set a Sentry user when the user is not logged in', async () => {
+ mocks.useUser.mockReturnValue(null)
+ mocks.useOrganizationsQuery.mockReturnValue({ data: orgs(1) })
+
+ render()
+ await new Promise((r) => setTimeout(r, 10))
+ expect(mocks.setUser).not.toHaveBeenCalled()
+ })
+})
diff --git a/apps/studio/lib/telemetry.tsx b/apps/studio/lib/telemetry.tsx
index 0b0cbb9358b..ebad3e51def 100644
--- a/apps/studio/lib/telemetry.tsx
+++ b/apps/studio/lib/telemetry.tsx
@@ -1,5 +1,5 @@
import * as Sentry from '@sentry/nextjs'
-import { LOCAL_STORAGE_KEYS, PageTelemetry, posthogClient, safeLocalStorage, useUser } from 'common'
+import { PageTelemetry, posthogClient, useUser } from 'common'
import { useEffect, useRef } from 'react'
import { useConsentToast } from 'ui-patterns/consent'
@@ -7,16 +7,6 @@ import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { API_URL, IS_PLATFORM } from '@/lib/constants'
-const getAnonId = async (id: string) => {
- const encoder = new TextEncoder()
- const data = encoder.encode(id)
- const hashBuffer = await crypto.subtle.digest('SHA-256', data as BufferSource)
- const hashArray = Array.from(new Uint8Array(hashBuffer))
- const base64String = btoa(hashArray.map((byte) => String.fromCharCode(byte)).join(''))
-
- return base64String
-}
-
export function Telemetry() {
// Although this is "technically" breaking the rules of hooks
// IS_PLATFORM never changes within a session, so this won't cause any issues
@@ -64,17 +54,7 @@ export function Telemetry() {
return
}
- const setSentryId = async () => {
- let sentryUserId = safeLocalStorage.getItem(LOCAL_STORAGE_KEYS.SENTRY_USER_ID)
- if (!sentryUserId) {
- sentryUserId = await getAnonId(user?.id)
- safeLocalStorage.setItem(LOCAL_STORAGE_KEYS.SENTRY_USER_ID, sentryUserId)
- }
- Sentry.setUser({ id: sentryUserId })
- }
-
- // if an error happens, continue without setting a sentry id
- setSentryId().catch((e) => console.error(e))
+ Sentry.setUser({ id: user.id })
}, [user?.id])
return (
diff --git a/packages/common/constants/local-storage.ts b/packages/common/constants/local-storage.ts
index 40ac85123ab..b31810f31eb 100644
--- a/packages/common/constants/local-storage.ts
+++ b/packages/common/constants/local-storage.ts
@@ -58,8 +58,6 @@ export const LOCAL_STORAGE_KEYS = {
LINTER_SHOW_FOOTER: 'supabase-linter-show-footer',
// Key to track account deletion requests
ACCOUNT_DELETION_REQUEST: 'supabase-account-deletion-request',
- // Used for storing a user id when sending reports to Sentry. The id is hashed for anonymity.
- SENTRY_USER_ID: 'supabase-sentry-user-id',
// Used for storing the last sign in method used by the user
LAST_SIGN_IN_METHOD: 'supabase-last-sign-in-method',
// Key to track the last selected schema. The project ref is intentionally put at the end for easier search in the browser console.