diff --git a/packages/browser-utils/src/metrics/cls.ts b/packages/browser-utils/src/metrics/cls.ts
index 99f76c610226..d836ff315c06 100644
--- a/packages/browser-utils/src/metrics/cls.ts
+++ b/packages/browser-utils/src/metrics/cls.ts
@@ -9,6 +9,7 @@ import {
   SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE,
   SEMANTIC_ATTRIBUTE_SENTRY_OP,
   SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
+  timestampInSeconds,
 } from '@sentry/core';
 import { DEBUG_BUILD } from '../debug-build';
 import { addClsInstrumentationHandler } from './instrument';
@@ -42,12 +43,15 @@ export function trackClsAsStandaloneSpan(client: Client): void {
   }, true);
 
   listenForWebVitalReportEvents(client, (reportEvent, pageloadSpanId) => {
-    sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId, reportEvent);
+    _sendStandaloneClsSpan(standaloneCLsValue, standaloneClsEntry, pageloadSpanId, reportEvent);
     cleanupClsHandler();
   });
 }
 
-function sendStandaloneClsSpan(
+/**
+ * Exported only for testing!
+ */
+export function _sendStandaloneClsSpan(
   clsValue: number,
   entry: LayoutShift | undefined,
   pageloadSpanId: string,
@@ -55,7 +59,7 @@ function sendStandaloneClsSpan(
 ) {
   DEBUG_BUILD && debug.log(`Sending CLS span (${clsValue})`);
 
-  const startTime = msToSec((browserPerformanceTimeOrigin() || 0) + (entry?.startTime || 0));
+  const startTime = entry ? msToSec((browserPerformanceTimeOrigin() || 0) + entry.startTime) : timestampInSeconds();
   const routeName = getCurrentScope().getScopeData().transactionName;
 
   const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';
@@ -63,7 +67,7 @@ function sendStandaloneClsSpan(
   const attributes: SpanAttributes = {
     [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.cls',
     [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.webvital.cls',
-    [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: entry?.duration || 0,
+    [SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME]: 0,
     // attach the pageload span id to the CLS span so that we can link them in the UI
     'sentry.pageload.span_id': pageloadSpanId,
     // describes what triggered the web vital to be reported
diff --git a/packages/browser-utils/test/metrics/cls.test.ts b/packages/browser-utils/test/metrics/cls.test.ts
new file mode 100644
index 000000000000..55550d02f546
--- /dev/null
+++ b/packages/browser-utils/test/metrics/cls.test.ts
@@ -0,0 +1,231 @@
+import * as SentryCore from '@sentry/core';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+import { _sendStandaloneClsSpan } from '../../src/metrics/cls';
+import * as WebVitalUtils from '../../src/metrics/utils';
+
+// Mock all Sentry core dependencies
+vi.mock('@sentry/core', async () => {
+  const actual = await vi.importActual('@sentry/core');
+  return {
+    ...actual,
+    browserPerformanceTimeOrigin: vi.fn(),
+    timestampInSeconds: vi.fn(),
+    getCurrentScope: vi.fn(),
+    htmlTreeAsString: vi.fn(),
+  };
+});
+
+describe('_sendStandaloneClsSpan', () => {
+  const mockSpan = {
+    addEvent: vi.fn(),
+    end: vi.fn(),
+  };
+
+  const mockScope = {
+    getScopeData: vi.fn().mockReturnValue({
+      transactionName: 'test-transaction',
+    }),
+  };
+
+  afterEach(() => {
+    vi.clearAllMocks();
+  });
+
+  beforeEach(() => {
+    vi.mocked(SentryCore.getCurrentScope).mockReturnValue(mockScope as any);
+    vi.mocked(SentryCore.browserPerformanceTimeOrigin).mockReturnValue(1000);
+    vi.mocked(SentryCore.timestampInSeconds).mockReturnValue(1.5);
+    vi.mocked(SentryCore.htmlTreeAsString).mockImplementation((node: any) => `<${node?.tagName || 'div'}>`);
+    vi.spyOn(WebVitalUtils, 'startStandaloneWebVitalSpan').mockReturnValue(mockSpan as any);
+  });
+
+  it('sends a standalone CLS span with entry data', () => {
+    const clsValue = 0.1;
+    const mockEntry: LayoutShift = {
+      name: 'layout-shift',
+      entryType: 'layout-shift',
+      startTime: 100,
+      duration: 0,
+      value: clsValue,
+      hadRecentInput: false,
+      sources: [
+        // @ts-expect-error - other properties are irrelevant
+        {
+          node: { tagName: 'div' } as Element,
+        },
+      ],
+      toJSON: vi.fn(),
+    };
+    const pageloadSpanId = '123';
+    const reportEvent = 'navigation';
+
+    _sendStandaloneClsSpan(clsValue, mockEntry, pageloadSpanId, reportEvent);
+
+    expect(WebVitalUtils.startStandaloneWebVitalSpan).toHaveBeenCalledWith({
+      name: '
',
+      transaction: 'test-transaction',
+      attributes: {
+        'sentry.origin': 'auto.http.browser.cls',
+        'sentry.op': 'ui.webvital.cls',
+        'sentry.exclusive_time': 0,
+        'sentry.pageload.span_id': '123',
+        'sentry.report_event': 'navigation',
+        'cls.source.1': '
',
+      },
+      startTime: 1.1, // (1000 + 100) / 1000
+    });
+
+    expect(mockSpan.addEvent).toHaveBeenCalledWith('cls', {
+      'sentry.measurement_unit': '',
+      'sentry.measurement_value': 0.1,
+    });
+
+    expect(mockSpan.end).toHaveBeenCalledWith(1.1);
+  });
+
+  it('sends a standalone CLS span without entry data', () => {
+    const clsValue = 0;
+    const pageloadSpanId = '456';
+    const reportEvent = 'pagehide';
+
+    _sendStandaloneClsSpan(clsValue, undefined, pageloadSpanId, reportEvent);
+
+    expect(SentryCore.timestampInSeconds).toHaveBeenCalled();
+    expect(SentryCore.browserPerformanceTimeOrigin).not.toHaveBeenCalled();
+
+    expect(WebVitalUtils.startStandaloneWebVitalSpan).toHaveBeenCalledWith({
+      name: 'Layout shift',
+      transaction: 'test-transaction',
+      attributes: {
+        'sentry.origin': 'auto.http.browser.cls',
+        'sentry.op': 'ui.webvital.cls',
+        'sentry.exclusive_time': 0,
+        'sentry.pageload.span_id': pageloadSpanId,
+        'sentry.report_event': 'pagehide',
+      },
+      startTime: 1.5,
+    });
+
+    expect(mockSpan.end).toHaveBeenCalledWith(1.5);
+    expect(mockSpan.addEvent).toHaveBeenCalledWith('cls', {
+      'sentry.measurement_unit': '',
+      'sentry.measurement_value': 0,
+    });
+  });
+
+  it('handles entry with multiple sources', () => {
+    const clsValue = 0.15;
+    const mockEntry: LayoutShift = {
+      name: 'layout-shift',
+      entryType: 'layout-shift',
+      startTime: 200,
+      duration: 0,
+      value: clsValue,
+      hadRecentInput: false,
+      sources: [
+        // @ts-expect-error - other properties are irrelevant
+        {
+          node: { tagName: 'div' } as Element,
+        },
+        // @ts-expect-error - other properties are irrelevant
+        {
+          node: { tagName: 'span' } as Element,
+        },
+      ],
+      toJSON: vi.fn(),
+    };
+    const pageloadSpanId = '789';
+
+    vi.mocked(SentryCore.htmlTreeAsString)
+      .mockReturnValueOnce('
') // for the name
+      .mockReturnValueOnce('
') // for source 1
+      .mockReturnValueOnce('
'); // for source 2
+
+    _sendStandaloneClsSpan(clsValue, mockEntry, pageloadSpanId, 'navigation');
+
+    expect(SentryCore.htmlTreeAsString).toHaveBeenCalledTimes(3);
+    expect(WebVitalUtils.startStandaloneWebVitalSpan).toHaveBeenCalledWith({
+      name: '',
+      transaction: 'test-transaction',
+      attributes: {
+        'sentry.origin': 'auto.http.browser.cls',
+        'sentry.op': 'ui.webvital.cls',
+        'sentry.exclusive_time': 0,
+        'sentry.pageload.span_id': '789',
+        'sentry.report_event': 'navigation',
+        'cls.source.1': '
',
+        'cls.source.2': '
',
+      },
+      startTime: 1.2, // (1000 + 200) / 1000
+    });
+  });
+
+  it('handles entry without sources', () => {
+    const clsValue = 0.05;
+    const mockEntry: LayoutShift = {
+      name: 'layout-shift',
+      entryType: 'layout-shift',
+      startTime: 50,
+      duration: 0,
+      value: clsValue,
+      hadRecentInput: false,
+      sources: [],
+      toJSON: vi.fn(),
+    };
+    const pageloadSpanId = '101';
+
+    _sendStandaloneClsSpan(clsValue, mockEntry, pageloadSpanId, 'navigation');
+
+    expect(WebVitalUtils.startStandaloneWebVitalSpan).toHaveBeenCalledWith({
+      name: '',
+      transaction: 'test-transaction',
+      attributes: {
+        'sentry.origin': 'auto.http.browser.cls',
+        'sentry.op': 'ui.webvital.cls',
+        'sentry.exclusive_time': 0,
+        'sentry.pageload.span_id': '101',
+        'sentry.report_event': 'navigation',
+      },
+      startTime: 1.05, // (1000 + 50) / 1000
+    });
+  });
+
+  it('handles when startStandaloneWebVitalSpan returns undefined', () => {
+    vi.spyOn(WebVitalUtils, 'startStandaloneWebVitalSpan').mockReturnValue(undefined);
+
+    const clsValue = 0.1;
+    const pageloadSpanId = '123';
+
+    expect(() => {
+      _sendStandaloneClsSpan(clsValue, undefined, pageloadSpanId, 'navigation');
+    }).not.toThrow();
+
+    expect(mockSpan.addEvent).not.toHaveBeenCalled();
+    expect(mockSpan.end).not.toHaveBeenCalled();
+  });
+
+  it('handles when browserPerformanceTimeOrigin returns null', () => {
+    vi.mocked(SentryCore.browserPerformanceTimeOrigin).mockReturnValue(undefined);
+
+    const clsValue = 0.1;
+    const mockEntry: LayoutShift = {
+      name: 'layout-shift',
+      entryType: 'layout-shift',
+      startTime: 200,
+      duration: 0,
+      value: clsValue,
+      hadRecentInput: false,
+      sources: [],
+      toJSON: vi.fn(),
+    };
+    const pageloadSpanId = '123';
+
+    _sendStandaloneClsSpan(clsValue, mockEntry, pageloadSpanId, 'navigation');
+
+    expect(WebVitalUtils.startStandaloneWebVitalSpan).toHaveBeenCalledWith(
+      expect.objectContaining({
+        startTime: 0.2,
+      }),
+    );
+  });
+});