diff --git a/.cypress/integration/metrics_analytics_test/metrics_analytics.spec.js b/.cypress/integration/metrics_analytics_test/metrics_analytics.spec.js
index c00e2b7045..611753bf84 100644
--- a/.cypress/integration/metrics_analytics_test/metrics_analytics.spec.js
+++ b/.cypress/integration/metrics_analytics_test/metrics_analytics.spec.js
@@ -55,8 +55,22 @@ describe('Metrics Analytics', () => {
       suppressResizeObserverIssue();
     });
 
+    describe('Check data source picker', () => {
+      it('Index picker should be only available under Otel metric datasource', () => {
+        cy.get('[data-test-subj="metricsDataSourcePicker"]').click();
+        cy.get('[data-test-subj="prometheusOption"]').click();
+        cy.get('[data-test-subj="metricsIndexPicker"]').should('not.exist');
+
+        cy.get('[data-test-subj="metricsDataSourcePicker"]').click();
+        cy.get('[data-test-subj="openTelemetryOption"]').click();
+        cy.get('[data-test-subj="metricsIndexPicker"]').should('exist');
+      });
+    });
+
     describe('Search for metrics in search bar', () => {
       it('Search for metrics in search bar from available metrics', () => {
+        cy.get('[data-test-subj="metricsDataSourcePicker"]').click();
+        cy.get('[data-test-subj="prometheusOption"]').click();
         cy.get('[data-test-subj="metricsSearch"]').type('metric', { wait: 50 });
 
         cy.get('[data-test-subj="metricsListItems_availableMetrics"]')
@@ -76,6 +90,8 @@ describe('Metrics Analytics', () => {
 
     describe('Select and unselect metrics in sidebar', () => {
       it('Select and unselect metrics in sidebar', () => {
+        cy.get('[data-test-subj="metricsDataSourcePicker"]').click();
+        cy.get('[data-test-subj="prometheusOption"]').click();
         cy.get('[data-test-subj="metricsListItems_availableMetrics"]')
           .contains(PPL_METRICS_NAMES[0])
           .trigger('mouseover')
@@ -84,7 +100,7 @@ describe('Metrics Analytics', () => {
           .contains(PPL_METRICS_NAMES[1])
           .trigger('mouseover')
           .click();
-        cy.wait(50);
+        cy.wait(delay/2);
         cy.get('[data-test-subj="metricsListItems_selectedMetrics"]')
           .contains(PPL_METRICS_NAMES[0])
           .should('exist');
@@ -99,7 +115,7 @@ describe('Metrics Analytics', () => {
           .contains(PPL_METRICS_NAMES[1])
           .trigger('mouseover')
           .click();
-        cy.wait(50);
+        cy.wait(delay/2);
         cy.get('[data-test-subj="metricsListItems_availableMetrics"]')
           .contains(PPL_METRICS_NAMES[0])
           .trigger('mouseover')
@@ -113,57 +129,29 @@ describe('Metrics Analytics', () => {
 
     describe('Test Metric Visualizations', () => {
       beforeEach(() => {
+        cy.get('[data-test-subj="metricsDataSourcePicker"]').click();
+        cy.get('[data-test-subj="prometheusOption"]').click();
         cy.get('[data-test-subj="metricsListItems_availableMetrics"]')
           .contains(PPL_METRICS_NAMES[0])
           .trigger('mouseover')
           .click();
       });
 
-      it.only('Resize a Metric visualization in edit mode', () => {
-        cy.get('[data-test-subj="metrics__editView"]')
-          .contains('Edit view')
-          .trigger('mouseover')
-          .click();
-        cy.wait(delay);
-        cy.get('.react-resizable-handle-se')
-          // .eq(1)
-          .trigger('mousedown', { which: 1 })
-          .trigger('mousemove', { clientX: 2000, clientY: 800 })
-          .trigger('mouseup', { force: true });
-        cy.wait(delay);
-        cy.get('[data-test-subj="metrics__saveView"]').trigger('mouseover').click();
-        cy.wait(delay * 3);
-        cy.get('div.react-grid-layout>div').invoke('height').should('match', new RegExp('790'));
-        cy.wait(delay);
-      });
-
       it('Drag and drop a Metric visualization in edit mode', () => {
         cy.get('[data-test-subj="metricsListItems_availableMetrics"]')
           .contains(PPL_METRICS_NAMES[1])
           .trigger('mouseover')
           .click();
-        cy.get('[data-test-subj="metrics__editView"]')
-          .contains('Edit view')
-          .trigger('mouseover')
-          .click();
-        cy.wait(delay);
         cy.get('h5')
           .contains(PPL_METRICS_NAMES[0])
           .trigger('mousedown', { which: 1, force: true })
           .trigger('mousemove', { clientX: 415, clientY: 500 })
           .trigger('mouseup', { force: true });
-        cy.wait(delay);
-        cy.get('[data-test-subj="metrics__saveView"]')
-          .trigger('mouseover')
-          .click({ force: true })
-          .then(() => {
-            cy.wait(delay * 3);
-            cy.get('div.react-grid-layout>div')
-              .eq(1)
-              .invoke('attr', 'style')
-              .should('match', new RegExp('(.*)transform: translate((.*)10px)(.*)'));
-            cy.wait(delay);
-          });
+        cy.wait(delay * 3);
+        cy.get('div.react-grid-layout>div')
+          .eq(1)
+          .invoke('attr', 'style')
+          .should('match', new RegExp('(.*)transform: translate((.*)10px)(.*)'));
       });
 
       it('Change date filter of the Metrics home page', () => {
@@ -175,7 +163,6 @@ describe('Metrics Analytics', () => {
         cy.get('.euiSuperDatePicker__prettyFormat[data-test-subj="superDatePickerShowDatesButton"]')
           .contains('This year')
           .should('exist');
-        cy.wait(delay);
       });
 
       it('Saves metrics to an existing panel', () => {
@@ -228,7 +215,6 @@ const createCustomMetric = ({ testMetricIndex }) => {
     delay: 50,
   });
   cy.get('.euiButton__text').contains('Refresh').trigger('mouseover').click();
-  cy.wait(delay);
   suppressResizeObserverIssue();
   cy.get('button[id="main-content-vis"]').contains('Visualizations').trigger('mouseover').click();
   cy.wait(delay * 2);
@@ -239,11 +225,10 @@ const createCustomMetric = ({ testMetricIndex }) => {
     .focus()
     .type(PPL_METRICS_NAMES[metricIndex], { force: true });
   cy.get('[data-test-subj="eventExplorer__metricSaveName"]').click({ force: true });
-  cy.wait(1000);
+  cy.wait(delay * 10);
   cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]', {
     timeout: COMMAND_TIMEOUT_LONG,
   }).click();
-  cy.wait(delay);
   cy.get('.euiToastHeader__title').contains('successfully').should('exist');
 };
 
diff --git a/.cypress/integration/panels_test/panels.spec.ts b/.cypress/integration/panels_test/panels.spec.ts
index 94fc0ac0ca..7943101627 100644
--- a/.cypress/integration/panels_test/panels.spec.ts
+++ b/.cypress/integration/panels_test/panels.spec.ts
@@ -775,7 +775,6 @@ const createSavedObjectPanel = (newName = TEST_PANEL) => {
 };
 
 const addVisualizationsToPanel = (panel, additionalVisualizationIds: string[]) => {
-  console.log('addVisualizationsToPanel', additionalVisualizationIds);
   const additionalVisualizations = additionalVisualizationIds.map((id, idx) => {
     return {
       savedVisualizationId: `observability-visualization:${id}`,
@@ -791,7 +790,6 @@ const addVisualizationsToPanel = (panel, additionalVisualizationIds: string[]) =
     ...panel.attributes.visualizations,
     ...additionalVisualizations,
   ];
-  console.log(panel.attributes);
   cy.request({
     method: 'PUT',
     failOnStatusCode: false,
diff --git a/.cypress/utils/metrics_constants.js b/.cypress/utils/metrics_constants.js
index 63c5c18955..1698f5da55 100644
--- a/.cypress/utils/metrics_constants.js
+++ b/.cypress/utils/metrics_constants.js
@@ -21,3 +21,9 @@ export const PPL_METRICS = [
 
 export const VIS_TYPE_LINE = 'Time Series';
 export const TESTING_PANEL = 'Mock Testing Panels for Metrics';
+
+export const OTEL_METRICS_NAMES = [
+  '[Otel Metric] ss4o_metrics-otel-dp.duration',
+  '[Otel Metric] ss4o_metrics-otel-dp.http.client.duration',
+  '[Otel Metric] ss4o_metrics-otel-dp.rpc.client.duration',
+];
diff --git a/common/constants/metrics.ts b/common/constants/metrics.ts
index 7e92e6663b..ffef2b8aa1 100644
--- a/common/constants/metrics.ts
+++ b/common/constants/metrics.ts
@@ -14,6 +14,7 @@ export const PPL_DATASOURCES_REQUEST =
 // redux
 
 export const OBSERVABILITY_CUSTOM_METRIC = 'CUSTOM_METRICS';
+export const OPEN_TELEMETRY = 'OpenTelemetry';
 export const REDUX_SLICE_METRICS = 'metrics';
 
 export const resolutionOptions = [
@@ -33,3 +34,21 @@ export const AGGREGATION_OPTIONS = [
   { value: 'min', text: 'min()' },
   { value: 'max', text: 'max()' },
 ];
+
+export const DATASOURCE_OPTIONS = [
+  {
+    label: 'Prometheus',
+    'data-test-subj': 'prometheusOption',
+  },
+  {
+    label: 'OpenTelemetry',
+    'data-test-subj': 'openTelemetryOption',
+  },
+];
+export const DATA_PREPPER_INDEX_NAME = 'ss4o_metrics-*-*';
+export const METRICS_ANALYTICS_DATA_PREPPER_INDICES_ROUTE =
+  '/api/observability/metrics_analytics/data_prepper_indices';
+
+// Regex pattens
+export const INDEX_DOCUMENT_NAME_PATTERN = /\[Otel Metric\]\s(\S+?-\S+?)\.(\S+)/;
+export const SPAN_RESOLUTION_REGEX = /'(\d+)([smhdwMy])'/;
diff --git a/common/constants/shared.ts b/common/constants/shared.ts
index e6e84b37bd..4ec97d50fe 100644
--- a/common/constants/shared.ts
+++ b/common/constants/shared.ts
@@ -2,7 +2,6 @@
  * Copyright OpenSearch Contributors
  * SPDX-License-Identifier: Apache-2.0
  */
-import CSS from 'csstype';
 
 // Client route
 export const PPL_BASE = '/api/ppl';
@@ -77,9 +76,11 @@ export const PPL_PATTERNS_DOCUMENTATION_URL =
   'https://github.com/opensearch-project/sql/blob/2.x/docs/user/ppl/cmd/patterns.rst#description';
 export const UI_DATE_FORMAT = 'MM/DD/YYYY hh:mm A';
 export const PPL_DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSSSSS';
+export const OTEL_DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ss';
 export const SPAN_REGEX = /span/;
 
 export const PROMQL_METRIC_SUBTYPE = 'promqlmetric';
+export const OTEL_METRIC_SUBTYPE = 'openTelemetryMetric';
 export const PPL_METRIC_SUBTYPE = 'metric';
 
 export const PPL_SPAN_REGEX = /by\s*span/i;
@@ -131,6 +132,7 @@ export enum VIS_CHART_TYPES {
   Pie = 'pie',
   HeatMap = 'heatmap',
   Text = 'text',
+  Histogram = 'histogram',
 }
 
 export const NUMERICAL_FIELDS = ['short', 'integer', 'long', 'float', 'double'];
diff --git a/common/types/explorer.ts b/common/types/explorer.ts
index c46a652491..5b1e18304b 100644
--- a/common/types/explorer.ts
+++ b/common/types/explorer.ts
@@ -6,7 +6,7 @@
 import { History } from 'history';
 import Plotly from 'plotly.js-dist';
 import { QueryManager } from 'common/query_manager';
-import { VIS_CHART_TYPES } from '../../common/constants/shared';
+import { OTEL_METRIC_SUBTYPE, VIS_CHART_TYPES } from '../../common/constants/shared';
 import {
   AGGREGATIONS,
   AVAILABLE_FIELDS,
@@ -174,12 +174,13 @@ export interface SavedVisualization extends SavedObjectAttributes {
   selected_fields: { text: string; tokens: [] };
   selected_timestamp: IField;
   type: string;
-  subType?: 'metric' | 'visualization' | typeof PROMQL_METRIC_SUBTYPE; // exists if sub type is metric
+  subType?: 'metric' | 'visualization'; // exists if sub type is metric
   user_configs?: string;
   units_of_measure?: string;
   application_id?: string;
   dataSources: string; // list of type SelectedDataSources that is stringified
   queryLang: string;
+  metricType?: typeof PROMQL_METRIC_SUBTYPE | typeof OTEL_METRIC_SUBTYPE; // exists if sub type is metric
 }
 
 export interface ExplorerDataType {
diff --git a/common/types/metrics.ts b/common/types/metrics.ts
index 7cefde98b8..55a9470cae 100644
--- a/common/types/metrics.ts
+++ b/common/types/metrics.ts
@@ -4,6 +4,7 @@
  */
 
 import { VisualizationType } from './custom_panels';
+type MetricTypes = 'savedCustomMetric' | 'prometheusMetric' | 'openTelemetryMetric';
 
 export interface MetricType extends VisualizationType {
   id: string;
@@ -13,10 +14,15 @@ export interface MetricType extends VisualizationType {
   w: number;
   h: number;
   query: {
-    type: 'savedCustomMetric' | 'prometheusMetric';
+    type: MetricTypes;
     aggregation: string;
     attributesGroupBy: string[];
     catalog: string;
     availableAttributes?: string[];
   };
 }
+
+export interface OptionType {
+  label: string;
+  'data-test-subj': string;
+}
diff --git a/public/components/application_analytics/helpers/utils.tsx b/public/components/application_analytics/helpers/utils.tsx
index 67ac27fb7d..12516e5a58 100644
--- a/public/components/application_analytics/helpers/utils.tsx
+++ b/public/components/application_analytics/helpers/utils.tsx
@@ -216,7 +216,7 @@ export const calculateAvailability = async (
   for (let i = 0; i < savedVisualizationsIds.length; i++) {
     const visualizationId = savedVisualizationsIds[i];
     // Fetches data for visualization
-    const visData = await fetchVisualizationById(http, visualizationId, (value: string) =>
+    const visData = await fetchVisualizationById(visualizationId, (value: string) =>
       console.error(value)
     );
 
diff --git a/public/components/common/query_utils/__tests__/query_utils.test.tsx b/public/components/common/query_utils/__tests__/query_utils.test.tsx
index 4119da5604..c93e226b3c 100644
--- a/public/components/common/query_utils/__tests__/query_utils.test.tsx
+++ b/public/components/common/query_utils/__tests__/query_utils.test.tsx
@@ -108,6 +108,7 @@ describe('Query Utils', () => {
       span: '1',
       resolution: 'h',
     };
+
     describe('updateCatalogVisualizationQuery', () => {
       it('should build plain promQL series query', () => {
         const query = updateCatalogVisualizationQuery(defaultQueryMetaData);
@@ -125,12 +126,14 @@ describe('Query Utils', () => {
       it('should set timestamps and default resolution', () => {
         const [startDate, endDate] = ['2023-11-11', '2023-12-11'];
         const [start, end] = [1699660800, 1702252800]; // 2023-11-11 to 2023-12-11
-        const query = preprocessMetricQuery({
-          metaData: { queryMetaData: defaultQueryMetaData },
+        const currentQuery =
+          "source = test_catalog.query_range('count by(one,two) (metric)', 1699660800, 1702252800, '1d')";
+        const expectedQuery = preprocessMetricQuery({
+          metaData: { query: currentQuery, queryMetaData: defaultQueryMetaData },
           startTime: startDate,
           endTime: endDate,
         });
-        expect(query).toMatch(new RegExp(`, ${start}, ${end}, '1d'`));
+        expect(expectedQuery).toMatch(new RegExp(`, ${start}, ${end}, '1d'`));
       });
     });
   });
diff --git a/public/components/common/query_utils/index.ts b/public/components/common/query_utils/index.ts
index eccd6b9ddd..81eb3b3c92 100644
--- a/public/components/common/query_utils/index.ts
+++ b/public/components/common/query_utils/index.ts
@@ -5,7 +5,7 @@
 
 import dateMath from '@elastic/datemath';
 import { Moment } from 'moment-timezone';
-import { isEmpty } from 'lodash';
+import _, { isEmpty } from 'lodash';
 import { SearchMetaData } from '../../event_analytics/redux/slices/search_meta_data_slice';
 import {
   PPL_DEFAULT_PATTERN_REGEX_FILETER,
@@ -18,8 +18,12 @@ import {
   PPL_INDEX_INSERT_POINT_REGEX,
   PPL_INDEX_REGEX,
   PPL_NEWLINE_REGEX,
+  OTEL_DATE_FORMAT,
+  OTEL_METRIC_SUBTYPE,
+  PROMQL_METRIC_SUBTYPE,
 } from '../../../../common/constants/shared';
 import { IExplorerFields, IQuery } from '../../../../common/types/explorer';
+import { SPAN_RESOLUTION_REGEX } from '../../../../common/constants/metrics';
 
 /*
  * "Query Utils" This file contains different reused functions in operational panels
@@ -61,15 +65,24 @@ export const convertDateTime = (
   datetime: string,
   isStart = true,
   formatted = true,
-  isMetrics: boolean = false
+  metricType: string = ''
 ) => {
-  let returnTime: undefined | Moment;
+  let returnTime: Moment = '';
+
   if (isStart) {
     returnTime = dateMath.parse(datetime);
   } else {
     returnTime = dateMath.parse(datetime, { roundUp: true });
   }
-  if (isMetrics) {
+
+  if (metricType === OTEL_METRIC_SUBTYPE) {
+    const formattedDate = returnTime!.utc().format(OTEL_DATE_FORMAT);
+    const milliseconds = returnTime!.millisecond();
+    const formattedMilliseconds = String(milliseconds).padEnd(6, '0');
+    return `${formattedDate}.${formattedMilliseconds}Z`;
+  }
+
+  if (metricType === PROMQL_METRIC_SUBTYPE) {
     const myDate = new Date(returnTime._d); // Your timezone!
     const epochTime = myDate.getTime() / 1000.0;
     return Math.round(epochTime);
@@ -100,8 +113,8 @@ export const updateCatalogVisualizationQuery = ({
   resolution: string;
 }) => {
   const attributesGroupString = attributesGroupBy.join(',');
-  const startEpochTime = convertDateTime(start, true, false, true);
-  const endEpochTime = convertDateTime(end, false, false, true);
+  const startEpochTime = convertDateTime(start, true, false, PROMQL_METRIC_SUBTYPE);
+  const endEpochTime = convertDateTime(end, false, false, PROMQL_METRIC_SUBTYPE);
   const promQuery =
     attributesGroupBy.length === 0
       ? `${aggregation} (${catalogTableName})`
@@ -183,13 +196,14 @@ export const updatePromQLQueryFilters = (
   const { connection, metric, aggregation, attributesGroupBy } = parsePromQLIntoKeywords(
     promQLQuery
   );
+
   const promQLPart = buildPromQLFromMetricQuery({
     metric,
     attributesGroupBy: attributesGroupBy.split(','),
     aggregation,
   });
-  const start = convertDateTime(startTime, true, false, true);
-  const end = convertDateTime(endTime, false, false, true);
+  const start = convertDateTime(startTime, true, false, PROMQL_METRIC_SUBTYPE);
+  const end = convertDateTime(endTime, false, false, PROMQL_METRIC_SUBTYPE);
   return `source = ${connection}.query_range('${promQLPart}', ${start}, ${end}, '1h')`;
 };
 
@@ -205,19 +219,25 @@ export const getIndexPatternFromRawQuery = (query: string): string => {
   return getPromQLIndex(query) || getPPLIndex(query);
 };
 
+function extractSpanAndResolution(query: string) {
+  if (!query) return;
+
+  const match = query.match(SPAN_RESOLUTION_REGEX);
+  return match ? { span: parseInt(match[1], 10), resolution: match[2] } : null;
+}
+
 export const preprocessMetricQuery = ({ metaData, startTime, endTime }) => {
   // convert to moment
   const start = convertDateTime(startTime, true);
   const end = convertDateTime(endTime, false);
-
-  const resolution = findMinInterval(start, end);
+  const spanResolution = extractSpanAndResolution(metaData?.query);
 
   const visualizationQuery = updateCatalogVisualizationQuery({
     ...metaData.queryMetaData,
     start,
     end,
-    span: '1',
-    resolution,
+    span: spanResolution?.span || 1,
+    resolution: spanResolution?.resolution || 'h',
   });
 
   return visualizationQuery;
@@ -246,7 +266,6 @@ export const preprocessQuery = ({
   whereClause?: string;
 }) => {
   let finalQuery = '';
-
   if (isEmpty(rawQuery)) return finalQuery;
 
   // convert to moment
diff --git a/public/components/custom_panels/custom_panel_view.tsx b/public/components/custom_panels/custom_panel_view.tsx
index fd1b35d12b..f72dc73ae7 100644
--- a/public/components/custom_panels/custom_panel_view.tsx
+++ b/public/components/custom_panels/custom_panel_view.tsx
@@ -391,7 +391,6 @@ export const CustomPanelView = (props: CustomPanelViewProps) => {
       const visualizationId = panelVisualizations[i].savedVisualizationId;
       // TODO: create route to get list of visualizations in one call
       const visData: SavedVisualizationType = await fetchVisualizationById(
-        http,
         visualizationId,
         (error: VizContainerError) => setToast(error.errorMessage, 'danger')
       );
diff --git a/public/components/custom_panels/helpers/utils.tsx b/public/components/custom_panels/helpers/utils.tsx
index e06c795df7..d05b785eb7 100644
--- a/public/components/custom_panels/helpers/utils.tsx
+++ b/public/components/custom_panels/helpers/utils.tsx
@@ -9,8 +9,13 @@ import _, { forEach, isEmpty, min } from 'lodash';
 import { Moment } from 'moment-timezone';
 import React from 'react';
 import { Layout } from 'react-grid-layout';
-import { CoreStart } from '../../../../../../src/core/public';
-import { PPL_INDEX_REGEX, PPL_WHERE_CLAUSE_REGEX } from '../../../../common/constants/shared';
+import {
+  OBSERVABILITY_BASE,
+  OTEL_METRIC_SUBTYPE,
+  PPL_INDEX_REGEX,
+  PPL_METRIC_SUBTYPE,
+  PPL_WHERE_CLAUSE_REGEX,
+} from '../../../../common/constants/shared';
 import { QueryManager } from '../../../../common/query_manager';
 import {
   SavedVisualizationType,
@@ -18,7 +23,7 @@ import {
   VizContainerError,
 } from '../../../../common/types/custom_panels';
 import { SavedVisualization } from '../../../../common/types/explorer';
-import { removeBacktick } from '../../../../common/utils';
+import { removeBacktick, getOSDHttp } from '../../../../common/utils';
 import { getVizContainerProps } from '../../../components/visualizations/charts/helpers';
 import PPLService from '../../../services/requests/ppl';
 import { SavedObjectsActions } from '../../../services/saved_objects/saved_object_client/saved_objects_actions';
@@ -27,6 +32,7 @@ import { getDefaultVisConfig } from '../../event_analytics/utils';
 import { Visualization } from '../../visualizations/visualization';
 import { MetricType } from '../../../../common/types/metrics';
 import { convertDateTime, updateCatalogVisualizationQuery } from '../../common/query_utils';
+import { INDEX_DOCUMENT_NAME_PATTERN } from '../../../../common/constants/metrics';
 
 /*
  * "Utils" This file contains different reused functions in operational panels
@@ -130,7 +136,6 @@ const queryAccumulator = (
 
 // Fetched Saved Visualization By Id
 export const fetchVisualizationById = async (
-  http: CoreStart['http'],
   savedVisualizationId: string,
   setIsError: (error: VizContainerError) => void
 ) => {
@@ -264,6 +269,7 @@ const createCatalogVisualizationMetaData = ({
   query,
   type,
   subType,
+  metricType,
   timeField,
   queryData,
 }: {
@@ -271,6 +277,7 @@ const createCatalogVisualizationMetaData = ({
   query: string;
   type: string;
   subType: string;
+  metricType: string;
   timeField: string;
   queryData: object;
 }) => {
@@ -280,6 +287,7 @@ const createCatalogVisualizationMetaData = ({
     query,
     type,
     subType,
+    metricType,
     selected_date_range: {
       start: 'now/y',
       end: 'now',
@@ -301,7 +309,6 @@ const createCatalogVisualizationMetaData = ({
 
 // Creates a catalogVisualization for a runtime catalog based PPL query and runs getQueryResponse
 export const renderCatalogVisualization = async ({
-  http,
   pplService,
   catalogSource,
   startTime,
@@ -315,10 +322,8 @@ export const renderCatalogVisualization = async ({
   setVisualizationMetaData,
   setIsLoading,
   setIsError,
-  spanResolution,
   visualization,
 }: {
-  http: CoreStart['http'];
   pplService: PPLService;
   catalogSource: string;
   startTime: string;
@@ -332,7 +337,6 @@ export const renderCatalogVisualization = async ({
   setVisualizationMetaData: React.Dispatch<React.SetStateAction<undefined>>;
   setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
   setIsError: React.Dispatch<React.SetStateAction<VizContainerError>>;
-  spanResolution?: string;
   queryMetaData?: MetricType;
   visualization: SavedVisualizationType;
 }) => {
@@ -341,7 +345,6 @@ export const renderCatalogVisualization = async ({
 
   const visualizationType = 'line';
   const visualizationTimeField = '@timestamp';
-  const visualizationSubType = visualization.subType;
 
   const visualizationQuery = updateCatalogVisualizationQuery({
     ...visualization.queryMetaData,
@@ -372,6 +375,7 @@ export const renderCatalogVisualization = async ({
       query: visualizationQuery,
       type: visualizationType,
       subType: visualization.subType,
+      metricType: visualization.metricType,
       timeField: visualizationTimeField,
       queryData,
     });
@@ -384,6 +388,182 @@ export const renderCatalogVisualization = async ({
   setIsLoading(false);
 };
 
+const createOtelVisualizationMetaData = (
+  documentName: string,
+  visualizationType: string,
+  startTime: string,
+  endTime: string,
+  queryData: object
+) => {
+  return {
+    name: documentName,
+    description: '',
+    query: '',
+    type: visualizationType,
+    subType: PPL_METRIC_SUBTYPE,
+    metricType: OTEL_METRIC_SUBTYPE,
+    selected_date_range: {
+      start: startTime,
+      end: endTime,
+      text: '',
+    },
+    selected_fields: {
+      text: '',
+      tokens: [],
+    },
+    userConfigs: {
+      layout: dynamicLayoutFromQueryData(queryData),
+    },
+  };
+};
+
+export const fetchAggregatedBinCount = async (
+  minimumBound: string,
+  maximumBound: string,
+  startTime: string,
+  endTime: string,
+  documentName: string,
+  selectedOtelIndex: string,
+  setIsError: React.Dispatch<React.SetStateAction<VizContainerError>>,
+  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>
+) => {
+  const http = getOSDHttp();
+  try {
+    const response = await http.post(`${OBSERVABILITY_BASE}/metrics/otel/aggregatedBinCount`, {
+      body: JSON.stringify({
+        min: minimumBound,
+        max: maximumBound,
+        startTime,
+        endTime,
+        documentName,
+        index: selectedOtelIndex,
+      }),
+    });
+    return response;
+  } catch (error) {
+    const errorMessage = JSON.parse(error.body.message);
+    setIsError({
+      errorMessage: errorMessage.error.reason || 'Issue in fetching bucket count',
+      errorDetails: errorMessage.error.details,
+    });
+    console.error(error.body);
+  } finally {
+    setIsLoading(false);
+  }
+};
+
+export const fetchSampleOTDocument = async (selectedOtelIndex: string, documentName: string) => {
+  const http = getOSDHttp();
+  try {
+    const response = await http.get(
+      `${OBSERVABILITY_BASE}/metrics/otel/${selectedOtelIndex}/${documentName}`
+    );
+    return response;
+  } catch (error) {
+    console.error(error);
+    throw error;
+  }
+};
+
+export const extractIndexAndDocumentName = (metricString: string): [string, string] | null => {
+  const match = metricString.match(INDEX_DOCUMENT_NAME_PATTERN);
+
+  if (match) {
+    const index = match[1];
+    const documentName = match[2];
+    return [index, documentName];
+  } else {
+    return null;
+  }
+};
+
+export const renderOpenTelemetryVisualization = async ({
+  startTime,
+  endTime,
+  setVisualizationTitle,
+  setVisualizationType,
+  setVisualizationData,
+  setVisualizationMetaData,
+  setIsLoading,
+  setIsError,
+  visualization,
+  setToast,
+}: {
+  startTime: string;
+  endTime: string;
+  setVisualizationTitle: React.Dispatch<React.SetStateAction<string>>;
+  setVisualizationType: React.Dispatch<React.SetStateAction<string>>;
+  setVisualizationData: React.Dispatch<React.SetStateAction<Plotly.Data[]>>;
+  setVisualizationMetaData: React.Dispatch<React.SetStateAction<undefined>>;
+  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
+  setIsError: React.Dispatch<React.SetStateAction<VizContainerError>>;
+  visualization: any;
+  setToast: (
+    title: string,
+    color?: string,
+    text?: React.ReactChild | undefined,
+    side?: string | undefined
+  ) => void;
+}) => {
+  setIsLoading(true);
+  setIsError({} as VizContainerError);
+
+  const visualizationType = 'bar';
+  let index = visualization?.index;
+  let documentName = visualization?.name;
+
+  if (index === undefined) {
+    const indexAndDocumentName = extractIndexAndDocumentName(visualization.name);
+    index = indexAndDocumentName[0];
+    documentName = indexAndDocumentName[1];
+    if (documentName === undefined)
+      setToast('Document name is undefined', 'danger', undefined, 'right');
+  }
+
+  const fetchSampleDocument = await fetchSampleOTDocument(index, documentName);
+  const source = fetchSampleDocument.hits[0]._source;
+
+  setVisualizationType(visualizationType);
+  setVisualizationTitle(source.name);
+
+  const dataBinsPromises = source.buckets.map(async (bucket: any) => {
+    try {
+      const formattedStartTime = convertDateTime(startTime, false, false, OTEL_METRIC_SUBTYPE);
+      const formattedEndTime = convertDateTime(endTime, false, false, OTEL_METRIC_SUBTYPE);
+      const fetchingAggregatedBinCount = await fetchAggregatedBinCount(
+        bucket.min.toString(),
+        bucket.max.toString(),
+        formattedStartTime,
+        formattedEndTime,
+        documentName,
+        index,
+        setIsError,
+        setIsLoading
+      );
+
+      return {
+        xAxis: bucket.min + ' - ' + bucket.max,
+        'count()': fetchingAggregatedBinCount?.nested_buckets?.bucket_range?.bucket_count?.value,
+      };
+    } catch (error) {
+      console.error('Error processing bucket:', error);
+      return null;
+    }
+  });
+  const jsonData = await Promise.all(dataBinsPromises);
+  const formatedJsonData = { jsonData };
+
+  const visualizationMetaData = createOtelVisualizationMetaData(
+    documentName,
+    visualizationType,
+    startTime,
+    endTime,
+    formatedJsonData
+  );
+  setVisualizationData(formatedJsonData);
+  setVisualizationMetaData(visualizationMetaData);
+};
+
 // Function to store recently used time filters and set start and end time.
 export const prependRecentlyUsedRange = (
   start: ShortDate,
@@ -417,6 +597,9 @@ export const parseSavedVisualizations = (
     subType: visualization.savedVisualization.hasOwnProperty('subType')
       ? visualization.savedVisualization.subType
       : '',
+    metricType: visualization.savedVisualization.hasOwnProperty('metricType')
+      ? visualization.savedVisualization.metricType
+      : '',
     units_of_measure: visualization.savedVisualization.hasOwnProperty('units_of_measure')
       ? visualization.savedVisualization.units_of_measure
       : '',
@@ -476,18 +659,18 @@ export const isPPLFilterValid = (
   return true;
 };
 
-export const processMetricsData = (schema: any, dataConfig: any) => {
+export const processMetricsData = (schema: any) => {
   if (isEmpty(schema)) return {};
   if (
     schema.length === 3 &&
     schema.every((schemaField) => ['@labels', '@value', '@timestamp'].includes(schemaField.name))
   ) {
-    return prepareMetricsData(schema, dataConfig);
+    return prepareMetricsData(schema);
   }
   return {};
 };
 
-export const prepareMetricsData = (schema: any, dataConfig: any) => {
+export const prepareMetricsData = (schema: any) => {
   const metricBreakdown: any[] = [];
   const metricSeries: any[] = [];
   const metricDimension: any[] = [];
@@ -507,6 +690,20 @@ export const prepareMetricsData = (schema: any, dataConfig: any) => {
   };
 };
 
+export const constructOtelMetricsMetaData = () => {
+  const otelMetricSeries: any[] = [];
+  const otelMetricDimension: any[] = [];
+
+  otelMetricDimension.push({ name: 'xAxis', label: 'xAxis', customLabel: '' });
+  otelMetricSeries.push({ name: '', label: '', aggregation: 'count', customLabel: '' });
+
+  return {
+    series: otelMetricSeries,
+    dimensions: otelMetricDimension,
+    span: {},
+  };
+};
+
 // Renders visualization in the vizualization container component
 export const displayVisualization = (metaData: any, data: any, type: string) => {
   if (metaData === undefined || isEmpty(metaData)) {
@@ -536,7 +733,12 @@ export const displayVisualization = (metaData: any, data: any, type: string) =>
   };
 
   // add metric specific overriding
-  finalDataConfig = { ...finalDataConfig, ...processMetricsData(data.schema, finalDataConfig) };
+  finalDataConfig = { ...finalDataConfig, ...processMetricsData(data.schema) };
+
+  // add otel metric specific overriding
+  if (metaData?.metricType === OTEL_METRIC_SUBTYPE) {
+    finalDataConfig = { ...finalDataConfig, ...constructOtelMetricsMetaData() };
+  }
 
   const mixedUserConfigs = {
     availabilityConfig: {
diff --git a/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx b/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx
index f7d7de6720..63eab7bcc0 100644
--- a/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx
+++ b/public/components/custom_panels/panel_modules/panel_grid/panel_grid.tsx
@@ -6,7 +6,7 @@
 
 import _ from 'lodash';
 import React, { useEffect, useState } from 'react';
-import { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';
+import { Layout, Responsive, WidthProvider } from 'react-grid-layout';
 import useObservable from 'react-use/lib/useObservable';
 import { CoreStart } from '../../../../../../../src/core/public';
 import PPLService from '../../../../services/requests/ppl';
@@ -85,33 +85,31 @@ export const PanelGrid = (props: PanelGridProps) => {
   const isLocked = useObservable(chrome.getIsNavDrawerLocked$());
 
   // Reset Size of Visualizations when layout is changed
-  const layoutChanged = (currLayouts: Layout[], allLayouts: Layouts) => {
+  const layoutChanged = (currLayouts: Layout[]) => {
     window.dispatchEvent(new Event('resize'));
     setPostEditLayout(currLayouts);
   };
 
   const loadVizComponents = () => {
-    const gridDataComps = panelVisualizations.map(
-      (panelVisualization: VisualizationType, index) => (
-        <VisualizationContainer
-          key={panelVisualization.id}
-          http={http}
-          editMode={editMode}
-          visualizationId={panelVisualization.id}
-          savedVisualizationId={panelVisualization.savedVisualizationId}
-          pplService={pplService}
-          fromTime={startTime}
-          toTime={endTime}
-          onRefresh={onRefresh}
-          onEditClick={onEditClick}
-          cloneVisualization={cloneVisualization}
-          pplFilterValue={pplFilterValue}
-          showFlyout={showFlyout}
-          removeVisualization={removeVisualization}
-          contextMenuId="visualization"
-        />
-      )
-    );
+    const gridDataComps = panelVisualizations.map((panelVisualization: VisualizationType) => (
+      <VisualizationContainer
+        key={panelVisualization.id}
+        http={http}
+        editMode={editMode}
+        visualizationId={panelVisualization.id}
+        savedVisualizationId={panelVisualization.savedVisualizationId}
+        pplService={pplService}
+        fromTime={startTime}
+        toTime={endTime}
+        onRefresh={onRefresh}
+        onEditClick={onEditClick}
+        cloneVisualization={cloneVisualization}
+        pplFilterValue={pplFilterValue}
+        showFlyout={showFlyout}
+        removeVisualization={removeVisualization}
+        contextMenuId="visualization"
+      />
+    ));
     setGridData(gridDataComps);
   };
 
diff --git a/public/components/custom_panels/panel_modules/panel_grid/panel_grid_so.tsx b/public/components/custom_panels/panel_modules/panel_grid/panel_grid_so.tsx
index f2a1cff644..08b2e0cccb 100644
--- a/public/components/custom_panels/panel_modules/panel_grid/panel_grid_so.tsx
+++ b/public/components/custom_panels/panel_modules/panel_grid/panel_grid_so.tsx
@@ -5,9 +5,9 @@
 /* eslint-disable react-hooks/exhaustive-deps */
 
 import _, { forEach } from 'lodash';
-import React, { useCallback, useEffect, useState } from 'react';
+import React, { useEffect, useState } from 'react';
 import { useSelector } from 'react-redux';
-import { Layout, Layouts, Responsive, WidthProvider } from 'react-grid-layout';
+import { Layout, Responsive, WidthProvider } from 'react-grid-layout';
 import useObservable from 'react-use/lib/useObservable';
 import { CoreStart } from '../../../../../../../src/core/public';
 import { VisualizationContainer } from '../visualization_container';
@@ -82,33 +82,33 @@ export const PanelGridSO = (props: PanelGridProps) => {
   const isLocked = useObservable(chrome.getIsNavDrawerLocked$());
 
   // Reset Size of Visualizations when layout is changed
-  const layoutChanged = (currLayouts: Layout[], allLayouts: Layouts) => {
+  const layoutChanged = (currLayouts: Layout[]) => {
     window.dispatchEvent(new Event('resize'));
     setPostEditLayout(currLayouts);
   };
 
   const loadVizComponents = () => {
-    const gridDataComps = panelVisualizations.map(
-      (panelVisualization: VisualizationType, index) => (
-        <VisualizationContainer
-          key={panelVisualization.id}
-          http={coreRefs.http!}
-          editMode={editMode}
-          visualizationId={panelVisualization.id}
-          savedVisualizationId={panelVisualization.savedVisualizationId}
-          pplService={coreRefs.pplService!}
-          fromTime={startTime}
-          toTime={endTime}
-          onRefresh={onRefresh}
-          onEditClick={onEditClick}
-          cloneVisualization={cloneVisualization}
-          pplFilterValue={pplFilterValue}
-          showFlyout={showFlyout}
-          removeVisualization={removeVisualization}
-          contextMenuId="visualization"
-        />
-      )
-    );
+    const gridDataComps = panelVisualizations.map((panelVisualization: VisualizationType) => (
+      <VisualizationContainer
+        key={panelVisualization.id}
+        http={coreRefs.http!}
+        editMode={editMode}
+        visualizationId={panelVisualization.id}
+        savedVisualizationId={panelVisualization.savedVisualizationId}
+        pplService={coreRefs.pplService!}
+        fromTime={startTime}
+        toTime={endTime}
+        onRefresh={onRefresh}
+        onEditClick={onEditClick}
+        cloneVisualization={cloneVisualization}
+        pplFilterValue={pplFilterValue}
+        showFlyout={showFlyout}
+        removeVisualization={removeVisualization}
+        contextMenuId="visualization"
+        metricType={panelVisualization?.metricType || ''}
+        panelVisualization={panelVisualization}
+      />
+    ));
     setGridData(gridDataComps);
   };
 
diff --git a/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
index 6cc87f8e02..ca71d20b56 100644
--- a/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
+++ b/public/components/custom_panels/panel_modules/visualization_container/visualization_container.tsx
@@ -32,6 +32,7 @@ import {
   fetchVisualizationById,
   renderCatalogVisualization,
   renderSavedVisualization,
+  renderOpenTelemetryVisualization,
 } from '../../helpers/utils';
 import './visualization_container.scss';
 import { VizContainerError } from '../../../../../common/types/custom_panels';
@@ -40,7 +41,9 @@ import { coreRefs } from '../../../../framework/core_refs';
 import {
   PROMQL_METRIC_SUBTYPE,
   observabilityMetricsID,
+  OTEL_METRIC_SUBTYPE,
 } from '../../../../../common/constants/shared';
+import { useToast } from '../../../common/toast';
 
 /*
  * Visualization container - This module is a placeholder to add visualizations in react-grid-layout
@@ -114,6 +117,7 @@ export const VisualizationContainer = ({
   const onActionsMenuClick = () => setIsPopoverOpen((currPopoverOpen) => !currPopoverOpen);
   const closeActionsMenu = () => setIsPopoverOpen(false);
   const { http, pplService } = coreRefs;
+  const { setToast } = useToast();
 
   const [isModalVisible, setIsModalVisible] = useState(false);
   const [modalContent, setModalContent] = useState(<></>);
@@ -180,7 +184,7 @@ export const VisualizationContainer = ({
       disabled={editMode}
       onClick={() => {
         closeActionsMenu();
-        if (visualizationMetaData?.subType === PROMQL_METRIC_SUBTYPE) {
+        if (visualizationMetaData?.metricType === PROMQL_METRIC_SUBTYPE) {
           window.location.assign(`${observabilityMetricsID}#/${savedVisualizationId}`);
         } else {
           onEditClick(savedVisualizationId);
@@ -227,7 +231,7 @@ export const VisualizationContainer = ({
   ];
 
   if (
-    visualizationMetaData?.subType === PROMQL_METRIC_SUBTYPE &&
+    visualizationMetaData?.metricType === PROMQL_METRIC_SUBTYPE &&
     actionMenuType === 'metricsGrid'
   ) {
     popoverPanel = [showPPLQueryPanel];
@@ -237,7 +241,7 @@ export const VisualizationContainer = ({
 
   const fetchVisualization = async () => {
     return savedVisualizationId
-      ? await fetchVisualizationById(http, savedVisualizationId, setIsError)
+      ? await fetchVisualizationById(savedVisualizationId, setIsError)
       : inputMetaData;
   };
 
@@ -247,10 +251,22 @@ export const VisualizationContainer = ({
 
     if (!visualization && !savedVisualizationId) return;
 
-    if (visualization.subType === PROMQL_METRIC_SUBTYPE) {
+    if (visualization.metricType === OTEL_METRIC_SUBTYPE)
+      await renderOpenTelemetryVisualization({
+        visualization,
+        startTime: fromTime,
+        endTime: toTime,
+        setVisualizationTitle,
+        setVisualizationType,
+        setVisualizationData,
+        setVisualizationMetaData,
+        setIsLoading,
+        setIsError,
+        setToast,
+      });
+    else if (visualization.metricType === PROMQL_METRIC_SUBTYPE)
       renderCatalogVisualization({
         visualization,
-        http,
         pplService,
         catalogSource: visualizationId,
         startTime: fromTime,
@@ -266,7 +282,7 @@ export const VisualizationContainer = ({
         setIsError,
         queryMetaData,
       });
-    } else
+    else
       await renderSavedVisualization({
         visualization,
         http,
diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx
index 5ac6b0591a..fcb84df1ea 100644
--- a/public/components/event_analytics/explorer/explorer.tsx
+++ b/public/components/event_analytics/explorer/explorer.tsx
@@ -633,7 +633,7 @@ export const Explorer = ({
       indexFields: explorerFields,
       userConfigs: {
         ...visualizationSettings,
-        ...processMetricsData(explorerData.schema, visualizationSettings),
+        ...processMetricsData(explorerData.schema),
       },
       appData: { fromApp: appLogEvents },
       explorer: { explorerData, explorerFields, query, http, pplService },
diff --git a/public/components/event_analytics/home/__tests__/__snapshots__/saved_query_table.test.tsx.snap b/public/components/event_analytics/home/__tests__/__snapshots__/saved_query_table.test.tsx.snap
index d8e3f5fd06..b543738ae2 100644
--- a/public/components/event_analytics/home/__tests__/__snapshots__/saved_query_table.test.tsx.snap
+++ b/public/components/event_analytics/home/__tests__/__snapshots__/saved_query_table.test.tsx.snap
@@ -93,6 +93,7 @@ exports[`Saved query table component Renders saved query table 1`] = `
             "date_end": "now",
             "date_start": "now-15m",
             "fields": Array [],
+            "metricType": "customMetric",
             "name": "Mock Flight count by destination save to panel",
             "objectId": "Kocoln0BYMuJGDsOwDma",
             "objectType": "savedVisualization",
@@ -109,6 +110,7 @@ exports[`Saved query table component Renders saved query table 1`] = `
             "date_end": "now",
             "date_start": "now-15m",
             "fields": Array [],
+            "metricType": "customMetric",
             "name": "Mock Flight count by destination",
             "objectId": "KIcoln0BYMuJGDsOhDmk",
             "objectType": "savedVisualization",
@@ -603,6 +605,7 @@ exports[`Saved query table component Renders saved query table 1`] = `
                 "date_end": "now",
                 "date_start": "now-15m",
                 "fields": Array [],
+                "metricType": "customMetric",
                 "name": "Mock Flight count by destination save to panel",
                 "objectId": "Kocoln0BYMuJGDsOwDma",
                 "objectType": "savedVisualization",
@@ -619,6 +622,7 @@ exports[`Saved query table component Renders saved query table 1`] = `
                 "date_end": "now",
                 "date_start": "now-15m",
                 "fields": Array [],
+                "metricType": "customMetric",
                 "name": "Mock Flight count by destination",
                 "objectId": "KIcoln0BYMuJGDsOhDmk",
                 "objectType": "savedVisualization",
diff --git a/public/components/event_analytics/home/saved_objects_table.tsx b/public/components/event_analytics/home/saved_objects_table.tsx
index 4d42a0b071..dc4b01ff02 100644
--- a/public/components/event_analytics/home/saved_objects_table.tsx
+++ b/public/components/event_analytics/home/saved_objects_table.tsx
@@ -66,7 +66,7 @@ export function SavedQueryTable({
       sortable: true,
       truncateText: true,
       render: (item: any) => {
-        return item.subType === PROMQL_METRIC_SUBTYPE ? (
+        return item.metricType === PROMQL_METRIC_SUBTYPE ? (
           <EuiLink
             href={`${METRIC_EXPLORER_BASE_PATH}${item.objectId}`}
             data-test-subj="eventHome__savedQueryTableName"
@@ -108,6 +108,7 @@ export function SavedQueryTable({
       timestamp: savedObject.selected_timestamp?.name,
       fields: savedObject.selected_fields?.tokens || [],
       subType: savedObject.subType,
+      metricType: savedObject?.metricType || 'customMetric',
     };
     return {
       id: h.objectId,
diff --git a/public/components/event_analytics/utils/utils.tsx b/public/components/event_analytics/utils/utils.tsx
index b19f3ce022..2558ee9a6a 100644
--- a/public/components/event_analytics/utils/utils.tsx
+++ b/public/components/event_analytics/utils/utils.tsx
@@ -19,6 +19,7 @@ import {
   TIME_INTERVAL_OPTIONS,
 } from '../../../../common/constants/explorer';
 import {
+  OTEL_METRIC_SUBTYPE,
   PPL_DATE_FORMAT,
   PPL_INDEX_INSERT_POINT_REGEX,
   PPL_INDEX_REGEX,
@@ -38,6 +39,13 @@ import {
   StatsAggregationChunk,
   statsChunk,
 } from '../../../../common/query_manager/ast/types';
+import {
+  extractIndexAndDocumentName,
+  fetchSampleOTDocument,
+  fetchAggregatedBinCount,
+} from '../../custom_panels/helpers/utils';
+import { convertDateTime } from '../../common/query_utils';
+import { VizContainerError } from '../../../../common/types/custom_panels';
 
 /* Builds Final Query for the surrounding events
  * -> Final Query is as follows:
@@ -267,6 +275,7 @@ export const getMetricVisConfig = (metric) => {
     [BREAKDOWNS]: [],
     queryMetaData: metric.queryMetaData,
     subType: metric.subType,
+    metricType: metric.metricType,
     legend: { showLegend: 'hidden' }, // force no-legend in dashboard displays
   };
 };
@@ -301,6 +310,65 @@ export const getDefaultVisConfig = (statsToken: statsChunk) => {
   };
 };
 
+export const fetchOtelMetric = async ({
+  visualizationName,
+  startTime,
+  endTime,
+  setIsError,
+  setIsLoading,
+  setToast,
+}: {
+  visualizationName: string;
+  startTime: string;
+  endTime: string;
+  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
+  setIsError: React.Dispatch<React.SetStateAction<VizContainerError>>;
+  setToast: (
+    title: string,
+    color?: string,
+    text?: React.ReactChild | undefined,
+    side?: string | undefined
+  ) => void;
+}) => {
+  const indexAndDocumentName = extractIndexAndDocumentName(visualizationName);
+  const index = indexAndDocumentName[0];
+  const documentName = indexAndDocumentName[1];
+  if (documentName === undefined)
+    setToast('Document name is undefined', 'danger', undefined, 'right');
+
+  const fetchSampleDocument = await fetchSampleOTDocument(index, documentName);
+  const source = fetchSampleDocument.hits[0]._source;
+
+  const dataBinsPromises = source.buckets.map(async (bucket: any) => {
+    try {
+      const formattedStartTime = convertDateTime(startTime, false, false, OTEL_METRIC_SUBTYPE);
+      const formattedEndTime = convertDateTime(endTime, false, false, OTEL_METRIC_SUBTYPE);
+      const fetchingAggregatedBinCount = await fetchAggregatedBinCount(
+        bucket.min.toString(),
+        bucket.max.toString(),
+        formattedStartTime,
+        formattedEndTime,
+        documentName,
+        index,
+        setIsError,
+        setIsLoading
+      );
+
+      return {
+        xAxis: bucket.min + ' - ' + bucket.max,
+        'count()': fetchingAggregatedBinCount?.nested_buckets?.bucket_range?.bucket_count?.value,
+      };
+    } catch (error) {
+      console.error('Error processing bucket:', error);
+      return null;
+    }
+  });
+  const jsonData = await Promise.all(dataBinsPromises);
+  const formatedJsonData = { jsonData };
+
+  return formatedJsonData;
+};
+
 const getSpanValue = (groupByToken: GroupByChunk) => {
   const timeUnitValue = TIME_INTERVAL_OPTIONS.find(
     (timeUnit) => timeUnit.value === groupByToken?.span?.span_expression.time_unit
diff --git a/public/components/metrics/helpers/utils.tsx b/public/components/metrics/helpers/utils.tsx
index 4cd1440d5b..e6478cfc97 100644
--- a/public/components/metrics/helpers/utils.tsx
+++ b/public/components/metrics/helpers/utils.tsx
@@ -8,7 +8,11 @@ import { DurationRange } from '@elastic/eui/src/components/date_picker/types';
 import React from 'react';
 import { Layout } from 'react-grid-layout';
 import { VISUALIZATION } from '../../../../common/constants/metrics';
-import { PROMQL_METRIC_SUBTYPE } from '../../../../common/constants/shared';
+import {
+  OTEL_METRIC_SUBTYPE,
+  PROMQL_METRIC_SUBTYPE,
+  PPL_METRIC_SUBTYPE,
+} from '../../../../common/constants/shared';
 import PPLService from '../../../services/requests/ppl';
 import { MetricType } from '../../../../common/types/metrics';
 import { VisualizationType } from '../../../../common/types/custom_panels';
@@ -74,7 +78,11 @@ export const sortMetricLayout = (metricsLayout: MetricType[]) => {
   });
 };
 
-export const visualizationFromMetric = (metric, span, resolution): SavedVisualizationType => {
+export const visualizationFromPrometheusMetric = (
+  metric,
+  span,
+  resolution
+): SavedVisualizationType => {
   const userConfigs = JSON.stringify({
     dataConfig: {
       chartStyles: {
@@ -95,7 +103,41 @@ export const visualizationFromMetric = (metric, span, resolution): SavedVisualiz
       resolution,
     },
     type: 'line',
-    subType: PROMQL_METRIC_SUBTYPE,
+    subType: PPL_METRIC_SUBTYPE,
+    metricType: PROMQL_METRIC_SUBTYPE,
     userConfigs: JSON.stringify(userConfigs),
   };
 };
+
+export const createOtelMetric = (metric: any) => {
+  return {
+    name: '[Otel Metric] ' + metric.index + '.' + metric.name,
+    index: metric.index,
+    documentName: metric.name,
+    description: '',
+    query: '',
+    type: 'bar',
+    selected_fields: {
+      text: '',
+      tokens: [],
+    },
+    sub_type: 'metric',
+    metric_type: OTEL_METRIC_SUBTYPE,
+    user_configs: {},
+  };
+};
+
+export const visualizationFromOtelMetric = (metric: any) => {
+  return {
+    query: '',
+    index: metric.index,
+    documentName: metric.documentName,
+    dateRange: ['now-1d', 'now'],
+    name: '[Otel Metric] ' + metric.index + '.' + metric.name,
+    description: metric.description,
+    type: 'bar',
+    subType: PPL_METRIC_SUBTYPE,
+    metricType: OTEL_METRIC_SUBTYPE,
+    userConfigs: JSON.stringify(metric.user_configs),
+  };
+};
diff --git a/public/components/metrics/index.tsx b/public/components/metrics/index.tsx
index 2e7f7a1cf8..08df0c8e1f 100644
--- a/public/components/metrics/index.tsx
+++ b/public/components/metrics/index.tsx
@@ -5,12 +5,13 @@
 
 import './index.scss';
 import { EuiPage, EuiPageBody, EuiResizableContainer } from '@elastic/eui';
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
 import { HashRouter, Route, RouteComponentProps, StaticContext } from 'react-router-dom';
 import { ChromeBreadcrumb } from '../../../../../src/core/public';
 import { Sidebar } from './sidebar/sidebar';
 import PPLService from '../../services/requests/ppl';
 import { TopMenu } from './top_menu/top_menu';
+import { OptionType } from '../../../common/types/metrics';
 import { MetricsGrid } from './view/metrics_grid';
 import SavedObjects from '../../services/saved_objects/event_analytics/saved_objects';
 
@@ -23,6 +24,10 @@ interface MetricsProps {
 }
 
 export const Home = ({ chrome, parentBreadcrumb }: MetricsProps) => {
+  // Side bar constants
+  const [selectedDataSource, setSelectedDataSource] = useState<OptionType[]>([]);
+  const [selectedOTIndex, setSelectedOTIndex] = useState([]);
+
   useEffect(() => {
     chrome.setBreadcrumbs([
       parentBreadcrumb,
@@ -49,7 +54,13 @@ export const Home = ({ chrome, parentBreadcrumb }: MetricsProps) => {
                       {(EuiResizablePanel, EuiResizableButton) => (
                         <>
                           <EuiResizablePanel mode="collapsible" initialSize={20} minSize="10%">
-                            <Sidebar additionalSelectedMetricId={routerProps.match.params.id} />
+                            <Sidebar
+                              additionalSelectedMetricId={routerProps.match.params.id}
+                              selectedDataSource={selectedDataSource}
+                              setSelectedDataSource={setSelectedDataSource}
+                              selectedOTIndex={selectedOTIndex}
+                              setSelectedOTIndex={setSelectedOTIndex}
+                            />
                           </EuiResizablePanel>
 
                           <EuiResizableButton />
diff --git a/public/components/metrics/redux/slices/__tests__/metric_slice.test.tsx b/public/components/metrics/redux/slices/__tests__/metric_slice.test.tsx
index 17f3681519..80afa4f60f 100644
--- a/public/components/metrics/redux/slices/__tests__/metric_slice.test.tsx
+++ b/public/components/metrics/redux/slices/__tests__/metric_slice.test.tsx
@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-import React, { PropsWithChildren } from 'react';
+import React from 'react';
 import { render, screen, fireEvent } from '@testing-library/react';
 import type { RenderOptions } from '@testing-library/react';
 import '@testing-library/jest-dom';
@@ -11,14 +11,7 @@ import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 
 import { OBSERVABILITY_CUSTOM_METRIC } from '../../../../../../common/constants/metrics';
-import { PROMQL_METRIC_SUBTYPE } from '../../../../../../common/constants/shared';
-import {
-  metricsReducers,
-  mergeMetrics,
-  clearSelectedMetrics,
-  addSelectedMetric,
-  metricSlice,
-} from '../metrics_slice';
+import { metricsReducers, mergeMetrics, clearSelectedMetrics, metricSlice } from '../metrics_slice';
 import { sampleSavedMetric } from '../../../../../../test/metrics_constants';
 import httpClientMock from '../../../../../../test/__mocks__/httpClientMock';
 import { Sidebar } from '../../../sidebar/sidebar';
@@ -43,7 +36,9 @@ const defaultInitialState = {
     resolution: 'h',
     recentlyUsedRanges: [],
   },
-  refresh: 0, // set to new Date() to trigger
+  refresh: 0,
+  otelIndices: [],
+  otelDocumentNames: [], // set to new Date() to trigger
 };
 
 // This type interface extends the default options for render from RTL, as well
@@ -60,6 +55,7 @@ function configureMetricStore(additionalState = {}) {
   return configureStore({ reducer: { metrics: metricsReducers }, preloadedState });
 }
 
+// eslint-disable-next-line jest/no-export
 export function renderWithMetricsProviders(
   ui: React.ReactElement,
   {
@@ -69,10 +65,6 @@ export function renderWithMetricsProviders(
     ...renderOptions
   }: ExtendedRenderOptions = {}
 ) {
-  function Wrapper({ children }: PropsWithChildren<{}>): JSX.Element {
-    return <Provider store={store}>{children}</Provider>;
-  }
-
   // Return an object with the store and all of RTL's query functions
   return { store, ...render(<Provider store={store}>{ui}</Provider>, { ...renderOptions }) };
 }
@@ -108,6 +100,9 @@ describe('Add and Remove Selected Metrics', () => {
         ...defaultInitialState,
       },
     };
+    const selectedDataSource = [{ label: 'Prometheus', 'data-test-subj': 'prometheusOption' }];
+    const setSelectedDataSource = jest.fn();
+    const setSelectedOTIndex = jest.fn();
 
     setPPLService(new PPLService(httpClientMock));
 
@@ -123,7 +118,15 @@ describe('Add and Remove Selected Metrics', () => {
     });
 
     // Act
-    renderWithMetricsProviders(<Sidebar />, { preloadedState });
+    renderWithMetricsProviders(
+      <Sidebar
+        selectedDataSource={selectedDataSource}
+        setSelectedDataSource={setSelectedDataSource}
+        selectedOTIndex={''}
+        setSelectedOTIndex={setSelectedOTIndex}
+      />,
+      { preloadedState }
+    );
 
     // Assert
 
@@ -142,6 +145,7 @@ describe('Add and Remove Selected Metrics', () => {
     expect(await screen.findByText(/Selected Metrics 1 of 1/)).toBeInTheDocument();
   });
 });
+
 describe('Metrics redux state tests', () => {
   it('Should initially set metrics state', () => {
     const store = configureMetricStore();
@@ -177,26 +181,6 @@ describe('metricsSlice actions and reducers', () => {
     expect(newState.selectedIds).toEqual([]);
   });
 
-  it('should handle updateMetricQuery', () => {
-    const metricsState = {
-      ...defaultInitialState,
-      metrics: { metric1: { name: 'metricName' }, metric2: { name: 'metric2' } },
-    };
-    // const store = configureStore( { metrics: metricsReducers },
-    //   preloadedState: { metrics: metricsState },
-    // });
-
-    // const dispatchedAction = store.dispatch(
-    //   updateMetricQuery('metric1', { availableAttributes: ['label1'] })
-    // );
-    // expect(dispatchedAction.type).toEqual('metrics/setMetric');
-    // expect(dispatchedAction.payload).toMatchObject({
-    //   aggregation: 'avg',
-    //   attributesGroupBy: [],
-    //   availableAttributes: ['label1'],
-    // });
-  });
-
   describe('loadMetrics', () => {
     it('should handle setSortedIds', async () => {
       const store = configureMetricStore();
diff --git a/public/components/metrics/redux/slices/metrics_slice.ts b/public/components/metrics/redux/slices/metrics_slice.ts
index f623585c37..acb68479c1 100644
--- a/public/components/metrics/redux/slices/metrics_slice.ts
+++ b/public/components/metrics/redux/slices/metrics_slice.ts
@@ -17,8 +17,12 @@ import { SavedObjectsActions } from '../../../../services/saved_objects/saved_ob
 import { ObservabilitySavedVisualization } from '../../../../services/saved_objects/saved_object_client/types';
 import { pplServiceRequestor } from '../../helpers/utils';
 import { coreRefs } from '../../../../framework/core_refs';
-import { PPL_METRIC_SUBTYPE, PROMQL_METRIC_SUBTYPE } from '../../../../../common/constants/shared';
-import { getPPLService } from '../../../../../common/utils';
+import {
+  PPL_METRIC_SUBTYPE,
+  PROMQL_METRIC_SUBTYPE,
+  OBSERVABILITY_BASE,
+} from '../../../../../common/constants/shared';
+import { getOSDHttp, getPPLService } from '../../../../../common/utils';
 
 export interface IconAttributes {
   color: string;
@@ -48,8 +52,8 @@ export interface DateSpanFilter {
 
 const initialState = {
   metrics: {},
-  selectedIds: [],
-  sortedIds: [],
+  selectedIds: [], // selected IDs
+  sortedIds: [], // all avaliable metrics
   search: '',
   metricsLayout: [],
   dataSources: [OBSERVABILITY_CUSTOM_METRIC],
@@ -63,6 +67,9 @@ const initialState = {
     recentlyUsedRanges: [],
   },
   refresh: 0, // set to new Date() to trigger
+  selectedDataSource: '',
+  otelIndices: [],
+  otelDocumentNames: [],
 };
 
 const mergeMetricCustomizer = function (objValue, srcValue) {
@@ -87,22 +94,27 @@ export const loadMetrics = () => async (dispatch) => {
   const customDataRequest = fetchCustomMetrics();
   const remoteDataSourcesResponse = await pplServiceRequestor(pplService!, PPL_DATASOURCES_REQUEST);
   const remoteDataSources = remoteDataSourcesResponse.data.DATASOURCE_NAME;
-
   dispatch(setDataSources(remoteDataSources));
   dispatch(setDataSourceTitles(remoteDataSources));
   dispatch(
-    setDataSourceIcons(coloredIconsFrom([OBSERVABILITY_CUSTOM_METRIC, ...remoteDataSources]))
+    setDataSourceIcons(
+      coloredIconsFrom([OBSERVABILITY_CUSTOM_METRIC, ...remoteDataSources, 'OpenTelemetry'])
+    )
   );
 
   const remoteDataRequests = await fetchRemoteMetrics(remoteDataSources);
   const metricsResultSet = await Promise.all([customDataRequest, ...remoteDataRequests]);
   const metricsResult = metricsResultSet.flat();
-
   const metricsMapById = keyBy(metricsResult.flat(), 'id');
   dispatch(mergeMetrics(metricsMapById));
 
   const sortedIds = sortBy(metricsResult, 'catalog', 'id').map((m) => m.id);
-  dispatch(setSortedIds(sortedIds));
+  await dispatch(setSortedIds(sortedIds));
+};
+
+export const loadOTIndices = () => async (dispatch) => {
+  const fetchOTindices = await fetchOpenTelemetryIndices();
+  dispatch(setOtelIndices(fetchOTindices));
 };
 
 const fetchCustomMetrics = async () => {
@@ -112,7 +124,6 @@ const fetchCustomMetrics = async () => {
   const savedMetrics = dataSet.observabilityObjectList.filter((obj) =>
     [PROMQL_METRIC_SUBTYPE, PPL_METRIC_SUBTYPE].includes(obj.savedVisualization?.subType)
   );
-
   return savedMetrics.map((obj: any) => ({
     id: obj.objectId,
     savedVisualizationId: obj.objectId,
@@ -121,6 +132,7 @@ const fetchCustomMetrics = async () => {
     catalog: OBSERVABILITY_CUSTOM_METRIC,
     type: obj.savedVisualization.type,
     subType: obj.savedVisualization.subType,
+    metricType: 'customMetric',
     aggregation: obj.savedVisualization.queryMetaData?.aggregation ?? 'avg',
     availableAttributes: [],
     attributesGroupBy: obj.savedVisualization.queryMetaData?.attributesGroupBy ?? [],
@@ -153,12 +165,31 @@ const fetchRemoteMetrics = (remoteDataSources: string[]) =>
         attributesGroupBy: [],
         availableAttributes: [],
         type: 'line',
-        subType: PROMQL_METRIC_SUBTYPE,
+        subType: PPL_METRIC_SUBTYPE,
+        metricType: PROMQL_METRIC_SUBTYPE,
         recentlyCreated: false,
       }))
     )
   );
 
+export const fetchOpenTelemetryIndices = async () => {
+  const http = getOSDHttp();
+  return http
+    .get(`${OBSERVABILITY_BASE}/search/indices`, {
+      query: {
+        format: 'json',
+      },
+    })
+    .catch((error) => console.error(error));
+};
+
+export const fetchOpenTelemetryDocumentNames = (selectedOtelIndex: string) => async () => {
+  const http = getOSDHttp();
+  return http
+    .get(`${OBSERVABILITY_BASE}/metrics/otel/${selectedOtelIndex}/documentNames`)
+    .catch((error) => console.error(error));
+};
+
 export const metricSlice = createSlice({
   name: REDUX_SLICE_METRICS,
   initialState,
@@ -213,6 +244,15 @@ export const metricSlice = createSlice({
     setRefresh: (state) => {
       state.refresh = Date.now();
     },
+    setSelectedDataSource: (state, { payload }) => {
+      state.selectedDataSource = payload;
+    },
+    setOtelIndices: (state, { payload }) => {
+      state.otelIndices = payload;
+    },
+    setOtelDocumentNames: (state, { payload }) => {
+      state.otelDocumentNames = payload;
+    },
   },
 });
 
@@ -227,13 +267,16 @@ export const {
   setDataSourceTitles,
   setDataSourceIcons,
   updateMetric,
+  setSelectedDataSource,
+  setOtelIndices,
+  setOtelDocumentNames,
 } = metricSlice.actions;
 
 /** private actions */
 
-const { setMetrics, setMetric, setSortedIds } = metricSlice.actions;
+export const { setMetrics, setMetric, setSortedIds } = metricSlice.actions;
 
-const getAvailableAttributes = (id, metricIndex) => async (dispatch, getState) => {
+const getAvailableAttributes = (id, metricIndex) => async (dispatch) => {
   const { toasts } = coreRefs;
   const pplService = getPPLService();
 
@@ -257,13 +300,13 @@ export const addSelectedMetric = (metric: MetricType) => async (dispatch, getSta
   const currentSelectedIds = getState().metrics.selectedIds;
   if (currentSelectedIds.includes(metric.id)) return;
 
-  if (metric.subType === PROMQL_METRIC_SUBTYPE) {
+  if (metric.metricType === PROMQL_METRIC_SUBTYPE) {
     await dispatch(getAvailableAttributes(metric.id, metric.index));
   }
   await dispatch(selectMetric(metric));
 };
 
-export const removeSelectedMetric = ({ id }) => async (dispatch, getState) => {
+export const removeSelectedMetric = ({ id }) => async (dispatch) => {
   dispatch(deSelectMetric(id));
 };
 
@@ -271,7 +314,6 @@ export const updateMetricQuery = (id, { availableAttributes, aggregation, attrib
   dispatch,
   getState
 ) => {
-  const state = getState();
   const staticMetric = getState().metrics.metrics[id];
   const metric = {
     ...staticMetric,
@@ -321,4 +363,10 @@ export const metricQuerySelector = (id) => (state) =>
     availableAttributes: [],
   };
 
+export const selectedDataSourcesSelector = (state) => state.metrics.selectedDataSource;
+
+export const otelIndexSelector = (state) => state.metrics.otelIndices;
+
+export const otelDocumentNamesSelector = (state) => state.metrics.otelDocumentNames;
+
 export const metricsReducers = metricSlice.reducer;
diff --git a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap
index a22e4729ce..64f504bf9c 100644
--- a/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap
+++ b/public/components/metrics/sidebar/__tests__/__snapshots__/sidebar.test.tsx.snap
@@ -12,7 +12,12 @@ exports[`Side Bar Component renders Side Bar Component 1`] = `
     }
   }
 >
-  <Sidebar>
+  <Sidebar
+    selectedDataSource=""
+    selectedOTIndex=""
+    setSelectedDataSource={[MockFunction]}
+    setSelectedOTIndex={[MockFunction]}
+  >
     <I18nProvider>
       <IntlProvider
         defaultLocale="en"
@@ -102,6 +107,260 @@ exports[`Side Bar Component renders Side Bar Component 1`] = `
           <div
             id="sidebar"
           >
+            <DataSourcePicker
+              selectedDataSource=""
+              setSelectedDataSource={[MockFunction]}
+            >
+              <div
+                className="metrics-data-source-picker"
+              >
+                <EuiTitle
+                  size="xxxs"
+                >
+                  <h5
+                    className="euiTitle euiTitle--xxxsmall"
+                  >
+                    Data source
+                  </h5>
+                </EuiTitle>
+                <EuiComboBox
+                  async={false}
+                  compressed={false}
+                  data-test-subj="metricsDataSourcePicker"
+                  fullWidth={false}
+                  isClearable={true}
+                  onChange={[Function]}
+                  options={
+                    Array [
+                      Object {
+                        "data-test-subj": "prometheusOption",
+                        "label": "Prometheus",
+                      },
+                      Object {
+                        "data-test-subj": "openTelemetryOption",
+                        "label": "OpenTelemetry",
+                      },
+                    ]
+                  }
+                  placeholder="Select a data source"
+                  selectedOptions={Array []}
+                  singleSelection={
+                    Object {
+                      "asPlainText": true,
+                    }
+                  }
+                  sortMatchesBy="none"
+                >
+                  <div
+                    aria-expanded={false}
+                    aria-haspopup="listbox"
+                    className="euiComboBox"
+                    data-test-subj="metricsDataSourcePicker"
+                    onKeyDown={[Function]}
+                    role="combobox"
+                  >
+                    <EuiComboBoxInput
+                      autoSizeInputRef={[Function]}
+                      compressed={false}
+                      fullWidth={false}
+                      hasSelectedOptions={false}
+                      inputRef={[Function]}
+                      isListOpen={false}
+                      noIcon={false}
+                      onChange={[Function]}
+                      onClear={[Function]}
+                      onClick={[Function]}
+                      onCloseListClick={[Function]}
+                      onFocus={[Function]}
+                      onOpenListClick={[Function]}
+                      onRemoveOption={[Function]}
+                      placeholder="Select a data source"
+                      rootId={[Function]}
+                      searchValue=""
+                      selectedOptions={Array []}
+                      singleSelection={
+                        Object {
+                          "asPlainText": true,
+                        }
+                      }
+                      toggleButtonRef={[Function]}
+                      updatePosition={[Function]}
+                      value=""
+                    >
+                      <EuiFormControlLayout
+                        compressed={false}
+                        fullWidth={false}
+                        icon={
+                          Object {
+                            "aria-label": "Open list of options",
+                            "data-test-subj": "comboBoxToggleListButton",
+                            "disabled": undefined,
+                            "onClick": [Function],
+                            "ref": [Function],
+                            "side": "right",
+                            "type": "arrowDown",
+                          }
+                        }
+                      >
+                        <div
+                          className="euiFormControlLayout"
+                        >
+                          <div
+                            className="euiFormControlLayout__childrenWrapper"
+                          >
+                            <div
+                              className="euiComboBox__inputWrap euiComboBox__inputWrap--noWrap euiComboBox__inputWrap-isClearable"
+                              data-test-subj="comboBoxInput"
+                              onClick={[Function]}
+                              tabIndex={-1}
+                            >
+                              <p
+                                className="euiComboBoxPlaceholder"
+                              >
+                                Select a data source
+                              </p>
+                              <AutosizeInput
+                                aria-controls=""
+                                className="euiComboBox__input"
+                                data-test-subj="comboBoxSearchInput"
+                                injectStyles={true}
+                                inputRef={[Function]}
+                                minWidth={1}
+                                onBlur={[Function]}
+                                onChange={[Function]}
+                                onFocus={[Function]}
+                                role="textbox"
+                                style={
+                                  Object {
+                                    "fontSize": 14,
+                                  }
+                                }
+                                value=""
+                              >
+                                <div
+                                  className="euiComboBox__input"
+                                  style={
+                                    Object {
+                                      "display": "inline-block",
+                                      "fontSize": 14,
+                                    }
+                                  }
+                                >
+                                  <input
+                                    aria-controls=""
+                                    data-test-subj="comboBoxSearchInput"
+                                    onBlur={[Function]}
+                                    onChange={[Function]}
+                                    onFocus={[Function]}
+                                    role="textbox"
+                                    style={
+                                      Object {
+                                        "boxSizing": "content-box",
+                                        "width": "2px",
+                                      }
+                                    }
+                                    value=""
+                                  />
+                                  <div
+                                    style={
+                                      Object {
+                                        "height": 0,
+                                        "left": 0,
+                                        "overflow": "scroll",
+                                        "position": "absolute",
+                                        "top": 0,
+                                        "visibility": "hidden",
+                                        "whiteSpace": "pre",
+                                      }
+                                    }
+                                  />
+                                </div>
+                              </AutosizeInput>
+                            </div>
+                            <EuiFormControlLayoutIcons
+                              compressed={false}
+                              icon={
+                                Object {
+                                  "aria-label": "Open list of options",
+                                  "data-test-subj": "comboBoxToggleListButton",
+                                  "disabled": undefined,
+                                  "onClick": [Function],
+                                  "ref": [Function],
+                                  "side": "right",
+                                  "type": "arrowDown",
+                                }
+                              }
+                            >
+                              <div
+                                className="euiFormControlLayoutIcons euiFormControlLayoutIcons--right"
+                              >
+                                <EuiFormControlLayoutCustomIcon
+                                  aria-label="Open list of options"
+                                  data-test-subj="comboBoxToggleListButton"
+                                  iconRef={[Function]}
+                                  onClick={[Function]}
+                                  size="m"
+                                  type="arrowDown"
+                                >
+                                  <button
+                                    aria-label="Open list of options"
+                                    className="euiFormControlLayoutCustomIcon euiFormControlLayoutCustomIcon--clickable"
+                                    data-test-subj="comboBoxToggleListButton"
+                                    onClick={[Function]}
+                                    type="button"
+                                  >
+                                    <EuiIcon
+                                      aria-hidden="true"
+                                      className="euiFormControlLayoutCustomIcon__icon"
+                                      size="m"
+                                      type="arrowDown"
+                                    >
+                                      <EuiIconEmpty
+                                        aria-hidden={true}
+                                        className="euiIcon euiIcon--medium euiIcon-isLoading euiFormControlLayoutCustomIcon__icon"
+                                        focusable="false"
+                                        role="img"
+                                        style={null}
+                                      >
+                                        <svg
+                                          aria-hidden={true}
+                                          className="euiIcon euiIcon--medium euiIcon-isLoading euiFormControlLayoutCustomIcon__icon"
+                                          focusable="false"
+                                          height={16}
+                                          role="img"
+                                          style={null}
+                                          viewBox="0 0 16 16"
+                                          width={16}
+                                          xmlns="http://www.w3.org/2000/svg"
+                                        />
+                                      </EuiIconEmpty>
+                                    </EuiIcon>
+                                  </button>
+                                </EuiFormControlLayoutCustomIcon>
+                              </div>
+                            </EuiFormControlLayoutIcons>
+                          </div>
+                        </div>
+                      </EuiFormControlLayout>
+                    </EuiComboBoxInput>
+                  </div>
+                </EuiComboBox>
+              </div>
+            </DataSourcePicker>
+            <EuiSpacer
+              size="s"
+            >
+              <div
+                className="euiSpacer euiSpacer--s"
+              />
+            </EuiSpacer>
+            <EuiSpacer
+              size="s"
+            >
+              <div
+                className="euiSpacer euiSpacer--s"
+              />
+            </EuiSpacer>
             <SearchBar>
               <div
                 className="metrics-search-bar-input"
diff --git a/public/components/metrics/sidebar/__tests__/sidebar.test.tsx b/public/components/metrics/sidebar/__tests__/sidebar.test.tsx
index 79dab9ad89..2a088b4827 100644
--- a/public/components/metrics/sidebar/__tests__/sidebar.test.tsx
+++ b/public/components/metrics/sidebar/__tests__/sidebar.test.tsx
@@ -19,9 +19,22 @@ import { sampleSavedMetric } from '../../../../../test/metrics_constants';
 
 jest.mock('../../../../services/requests/ppl');
 
+// Mocked http object
+const mockHttpObject = {
+  get: jest.fn().mockResolvedValue({}),
+};
+
+// Mocked coreRefs object with the mocked http
+const mockCoreRefs = {
+  http: mockHttpObject,
+  pplService: new PPLService(mockHttpObject),
+};
+
 describe('Side Bar Component', () => {
   configure({ adapter: new Adapter() });
   const store = createStore(rootReducer, applyMiddleware(thunk));
+  const setSelectedDataSource = jest.fn();
+  const setSelectedOTIndex = jest.fn();
 
   beforeAll(() => {
     PPLService.mockImplementation(() => {
@@ -50,7 +63,12 @@ describe('Side Bar Component', () => {
 
     const wrapper = mount(
       <Provider store={store}>
-        <Sidebar />
+        <Sidebar
+          selectedDataSource={''}
+          setSelectedDataSource={setSelectedDataSource}
+          selectedOTIndex={''}
+          setSelectedOTIndex={setSelectedOTIndex}
+        />
       </Provider>
     );
 
diff --git a/public/components/metrics/sidebar/data_source_picker.tsx b/public/components/metrics/sidebar/data_source_picker.tsx
new file mode 100644
index 0000000000..e5cf7758c8
--- /dev/null
+++ b/public/components/metrics/sidebar/data_source_picker.tsx
@@ -0,0 +1,39 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiComboBox, EuiTitle } from '@elastic/eui';
+import React from 'react';
+import { DATASOURCE_OPTIONS } from '../../../../common/constants/metrics';
+import { OptionType } from '../../../../common/types/metrics';
+
+interface DataSourcePickerMenuProps {
+  selectedDataSource: OptionType[];
+  setSelectedDataSource: (sources: OptionType[]) => void;
+}
+
+export const DataSourcePicker = ({
+  selectedDataSource,
+  setSelectedDataSource,
+}: DataSourcePickerMenuProps) => {
+  const onChange = (selectedDataSource) => {
+    setSelectedDataSource(selectedDataSource);
+  };
+
+  return (
+    <div className="metrics-data-source-picker">
+      <EuiTitle size="xxxs">
+        <h5>Data source</h5>
+      </EuiTitle>
+      <EuiComboBox
+        placeholder="Select a data source"
+        singleSelection={{ asPlainText: true }}
+        options={DATASOURCE_OPTIONS}
+        selectedOptions={selectedDataSource || []}
+        onChange={onChange}
+        data-test-subj="metricsDataSourcePicker"
+      />
+    </div>
+  );
+};
diff --git a/public/components/metrics/sidebar/index_picker.tsx b/public/components/metrics/sidebar/index_picker.tsx
new file mode 100644
index 0000000000..86d4c1afeb
--- /dev/null
+++ b/public/components/metrics/sidebar/index_picker.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiComboBox, EuiTitle } from '@elastic/eui';
+import React, { useState } from 'react';
+
+export const IndexPicker = (props: { otelIndices: unknown; setSelectedOTIndex: unknown }) => {
+  const { otelIndices, setSelectedOTIndex } = props;
+  const otelIndex = otelIndices.map((item: any) => {
+    return { label: item.index };
+  });
+  const [selectedIndex, setSelectedIndex] = useState([]);
+
+  const onChange = (selectedIndex) => {
+    setSelectedIndex(selectedIndex);
+    setSelectedOTIndex(selectedIndex);
+  };
+
+  return (
+    <div className="metrics-index-picker">
+      <EuiTitle size="xxxs">
+        <h5>Otel Index</h5>
+      </EuiTitle>
+      <EuiComboBox
+        placeholder="Select an index"
+        singleSelection={{ asPlainText: true }}
+        options={otelIndex}
+        selectedOptions={selectedIndex}
+        onChange={onChange}
+        data-test-subj="metricsIndexPicker"
+      />
+    </div>
+  );
+};
diff --git a/public/components/metrics/sidebar/metric_name.tsx b/public/components/metrics/sidebar/metric_name.tsx
index ce25c8f405..5c8bc65261 100644
--- a/public/components/metrics/sidebar/metric_name.tsx
+++ b/public/components/metrics/sidebar/metric_name.tsx
@@ -4,17 +4,14 @@
  */
 
 import React from 'react';
-import { EuiAvatar, EuiFacetButton, EuiIcon } from '@elastic/eui';
-import { useSelector } from 'react-redux';
-import { metricIconsSelector } from '../redux/slices/metrics_slice';
-import { OBSERVABILITY_CUSTOM_METRIC } from '../../../../common/constants/metrics';
+import { EuiFacetButton, EuiIcon } from '@elastic/eui';
+import { OBSERVABILITY_CUSTOM_METRIC, OPEN_TELEMETRY } from '../../../../common/constants/metrics';
 
 const MetricIcon = ({ metric }) => {
-  const metricIcons = useSelector(metricIconsSelector);
-  const iconMeta = metricIcons[metric.catalog];
-  if (metric.catalog === OBSERVABILITY_CUSTOM_METRIC)
+  const metricCatalog = metric?.catalog;
+  if ([OBSERVABILITY_CUSTOM_METRIC, OPEN_TELEMETRY].includes(metricCatalog)) {
     return <EuiIcon title="OpenSearch" type="logoOpenSearch" size="l" />;
-  else return <EuiAvatar name={metric.catalog} size="s" type="space" {...iconMeta} />;
+  } else return <EuiIcon title="OpenSearch" type="logoOpenSearch" size="l" />;
 };
 
 interface IMetricNameProps {
@@ -25,15 +22,19 @@ interface IMetricNameProps {
 export const MetricName = (props: IMetricNameProps) => {
   const { metric, handleClick } = props;
 
-  const name = () => {
-    if (metric.catalog === 'CUSTOM_METRICS') return metric.name;
-    else return metric.name.split('.')[1].replace(/^prometheus_/, 'p.._');
+  const name = (metricDetails: any) => {
+    if (
+      metricDetails?.catalog === OBSERVABILITY_CUSTOM_METRIC ||
+      metricDetails?.catalog === OPEN_TELEMETRY
+    )
+      return metricDetails?.name;
+    else return metricDetails?.name.split('.')[1].replace(/^prometheus_/, 'p.._');
   };
 
   return (
     <EuiFacetButton
       className="obsMetric-Name eui-textTruncate"
-      title={metric.name}
+      title={metric?.name}
       onClick={() => handleClick(metric)}
       icon={<MetricIcon metric={metric} />}
     >
diff --git a/public/components/metrics/sidebar/metrics_accordion.tsx b/public/components/metrics/sidebar/metrics_accordion.tsx
index d3168e7102..2579d6ecaf 100644
--- a/public/components/metrics/sidebar/metrics_accordion.tsx
+++ b/public/components/metrics/sidebar/metrics_accordion.tsx
@@ -9,7 +9,7 @@ import { min } from 'lodash';
 import { MetricName } from './metric_name';
 
 interface IMetricNameProps {
-  metricsList: [];
+  metricsList: any;
   headerName: string;
   handleClick: (props: any) => void;
   dataTestSubj: string;
diff --git a/public/components/metrics/sidebar/sidebar.tsx b/public/components/metrics/sidebar/sidebar.tsx
index ac93037fc5..1a0adffa08 100644
--- a/public/components/metrics/sidebar/sidebar.tsx
+++ b/public/components/metrics/sidebar/sidebar.tsx
@@ -5,10 +5,11 @@
 
 import './sidebar.scss';
 
-import React, { useEffect, useMemo } from 'react';
+import React, { useEffect, useRef, useState, useMemo } from 'react';
 import { EuiSpacer } from '@elastic/eui';
 import { I18nProvider } from '@osd/i18n/react';
 import { batch, useDispatch, useSelector } from 'react-redux';
+import { keyBy, sortBy } from 'lodash';
 import {
   addSelectedMetric,
   availableMetricsSelector,
@@ -18,28 +19,57 @@ import {
   selectedMetricsIdsSelector,
   selectedMetricsSelector,
   selectMetricByIdSelector,
+  otelIndexSelector,
+  setDataSourceIcons,
+  coloredIconsFrom,
+  loadOTIndices,
+  fetchOpenTelemetryDocumentNames,
+  mergeMetrics,
+  setSortedIds,
 } from '../redux/slices/metrics_slice';
 import { MetricsAccordion } from './metrics_accordion';
 import { SearchBar } from './search_bar';
+import { DataSourcePicker } from './data_source_picker';
+import { IndexPicker } from './index_picker';
+import { OptionType } from '../../../../common/types/metrics';
+import { OTEL_METRIC_SUBTYPE, PPL_METRIC_SUBTYPE } from '../../../../common/constants/shared';
 
+interface SideBarMenuProps {
+  selectedDataSource: OptionType[];
+  setSelectedDataSource: (sources: OptionType[]) => void;
+  selectedOTIndex: React.SetStateAction<Array<{}>>;
+  setSelectedOTIndex: React.Dispatch<React.SetStateAction<unknown>>;
+  additionalSelectedMetricId?: string;
+}
 export const Sidebar = ({
+  selectedDataSource,
+  setSelectedDataSource,
+  selectedOTIndex,
+  setSelectedOTIndex,
   additionalSelectedMetricId,
-}: {
-  additionalSelectedMetricId?: string;
-}) => {
+}: SideBarMenuProps) => {
   const dispatch = useDispatch();
-
-  const availableMetrics = useSelector(availableMetricsSelector);
+  const [availableOTDocuments, setAvailableOTDocuments] = useState([]);
+  const availableOTDocumentsRef = useRef();
+  availableOTDocumentsRef.current = availableOTDocuments;
+  const promethuesMetrics = useSelector(availableMetricsSelector);
   const selectedMetrics = useSelector(selectedMetricsSelector);
   const selectedMetricsIds = useSelector(selectedMetricsIdsSelector);
 
   const additionalMetric = useSelector(selectMetricByIdSelector(additionalSelectedMetricId));
+  const otelIndices = useSelector(otelIndexSelector);
 
   useEffect(() => {
     batch(() => {
       dispatch(loadMetrics());
     });
-  }, [dispatch]);
+  }, [dispatch, selectedDataSource]);
+
+  useEffect(() => {
+    batch(() => {
+      dispatch(loadOTIndices());
+    });
+  }, [dispatch, selectedDataSource]);
 
   useEffect(() => {
     if (additionalMetric) {
@@ -54,7 +84,57 @@ export const Sidebar = ({
     return selectedMetricsIds.map((id) => selectedMetrics[id]).filter((m) => m); // filter away null entries
   }, [selectedMetrics, selectedMetricsIds]);
 
-  const handleAddMetric = (metric: any) => dispatch(addSelectedMetric(metric));
+  useEffect(() => {
+    if (selectedOTIndex.length > 0 && selectedDataSource[0]?.label === 'OpenTelemetry') {
+      const fetchOtelDocuments = async () => {
+        try {
+          const documentNames = await fetchOpenTelemetryDocumentNames(selectedOTIndex[0]?.label)();
+          const availableOtelDocuments = documentNames?.aggregations?.distinct_names?.buckets.map(
+            (item: any) => {
+              return {
+                id: item.key,
+                name: item.key,
+                catalog: 'OpenTelemetry',
+                subType: PPL_METRIC_SUBTYPE,
+                metricType: OTEL_METRIC_SUBTYPE,
+                type: 'Histogram',
+                index: selectedOTIndex[0]?.label,
+              };
+            }
+          );
+          setAvailableOTDocuments(availableOtelDocuments);
+          const metricsMapById = keyBy(availableOtelDocuments, 'id');
+
+          dispatch(mergeMetrics(metricsMapById));
+
+          const sortedIds = sortBy(availableOtelDocuments, 'catalog', 'id').map((m) => m.id);
+          dispatch(setSortedIds(sortedIds));
+          dispatch(setDataSourceIcons(coloredIconsFrom(['OpenTelemetry'])));
+        } catch (error) {
+          console.error('Error fetching OpenTelemetry documents:', error);
+        }
+      };
+      fetchOtelDocuments();
+    }
+  }, [dispatch, selectedDataSource, selectedOTIndex]);
+
+  const indexPicker = useMemo(() => {
+    const isOpenTelemetry = selectedDataSource[0]?.label === 'OpenTelemetry' ? true : false;
+    if (isOpenTelemetry) {
+      return <IndexPicker otelIndices={otelIndices} setSelectedOTIndex={setSelectedOTIndex} />;
+    }
+  }, [selectedDataSource]);
+
+  const availableMetrics = useMemo(() => {
+    if (selectedDataSource[0]?.label === 'OpenTelemetry' && selectedOTIndex.length > 0)
+      return promethuesMetrics;
+    else if (selectedDataSource[0]?.label === 'Prometheus') return promethuesMetrics;
+    else return [];
+  }, [promethuesMetrics, selectedDataSource, availableOTDocuments, selectedOTIndex]);
+
+  const handleAddMetric = (metric: any) => {
+    dispatch(addSelectedMetric(metric));
+  };
 
   const handleRemoveMetric = (metric: any) => {
     dispatch(removeSelectedMetric(metric));
@@ -63,9 +143,15 @@ export const Sidebar = ({
   return (
     <I18nProvider>
       <div id="sidebar">
+        <DataSourcePicker
+          selectedDataSource={selectedDataSource}
+          setSelectedDataSource={setSelectedDataSource}
+        />
+        <EuiSpacer size="s" />
+        {indexPicker}
+        <EuiSpacer size="s" />
         <SearchBar />
         <EuiSpacer size="s" />
-
         <section className="sidebar">
           <MetricsAccordion
             metricsList={selectedMetricsList}
diff --git a/public/components/metrics/top_menu/metrics_export.tsx b/public/components/metrics/top_menu/metrics_export.tsx
index f23f0543dd..dee03fc1a2 100644
--- a/public/components/metrics/top_menu/metrics_export.tsx
+++ b/public/components/metrics/top_menu/metrics_export.tsx
@@ -21,7 +21,11 @@ import { I18nProvider } from '@osd/i18n/react';
 import { MetricsExportPanel } from './metrics_export_panel';
 import { OSDSavedVisualizationClient } from '../../../services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization';
 import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory';
-import { addMultipleVizToPanels, isUuid } from '../../custom_panels/redux/panel_slice';
+import {
+  addMultipleVizToPanels,
+  isUuid,
+  selectPanelList,
+} from '../../custom_panels/redux/panel_slice';
 import { MetricType } from '../../../../common/types/metrics';
 import {
   dateSpanFilterSelector,
@@ -29,11 +33,14 @@ import {
   selectedMetricsSelector,
 } from '../redux/slices/metrics_slice';
 import { coreRefs } from '../../../framework/core_refs';
-import { selectPanelList } from '../../../../public/components/custom_panels/redux/panel_slice';
 import { SavedVisualization } from '../../../../common/types/explorer';
-import { visualizationFromMetric } from '../helpers/utils';
+import { visualizationFromPrometheusMetric, visualizationFromOtelMetric } from '../helpers/utils';
 import { updateCatalogVisualizationQuery } from '../../common/query_utils';
-import { PROMQL_METRIC_SUBTYPE } from '../../../../common/constants/shared';
+import {
+  OTEL_METRIC_SUBTYPE,
+  PROMQL_METRIC_SUBTYPE,
+  PPL_METRIC_SUBTYPE,
+} from '../../../../common/constants/shared';
 import { SavedObjectLoader } from '../../../../../../src/plugins/saved_objects/public';
 import { MountPoint } from '../../../../../../src/core/public';
 
@@ -140,30 +147,43 @@ const MetricsExportPopOver = () => {
     ]);
 
   const createSavedVisualization = async (metric): Promise<any> => {
-    const [ds, index] = metric.index.split('.');
-    const queryMetaData = {
-      catalogSourceName: ds,
-      catalogTableName: index,
-      aggregation: metric.aggregation,
-      attributesGroupBy: metric.attributesGroupBy,
-    };
-    const visMetaData = visualizationFromMetric(
-      {
+    let visMetaData;
+    if (metric.metricType === OTEL_METRIC_SUBTYPE) {
+      visMetaData = visualizationFromOtelMetric({
         ...metric,
-        dataSources: datasourceMetaFrom(metric.catalog),
-        query: updateCatalogVisualizationQuery({
-          ...queryMetaData,
-          ...dateSpanFilter,
-        }),
-        queryMetaData,
-        subType: PROMQL_METRIC_SUBTYPE,
+        query: '',
+        subType: PPL_METRIC_SUBTYPE,
+        metricType: OTEL_METRIC_SUBTYPE,
         dateRange: ['now-1d', 'now'],
-        fields: ['@value'],
         timestamp: '@timestamp',
-      },
-      dateSpanFilter.span,
-      dateSpanFilter.reoslution
-    );
+      });
+    } else {
+      const [ds, index] = metric.index.split('.');
+      const queryMetaData = {
+        catalogSourceName: ds,
+        catalogTableName: index,
+        aggregation: metric.aggregation,
+        attributesGroupBy: metric.attributesGroupBy,
+      };
+      visMetaData = visualizationFromPrometheusMetric(
+        {
+          ...metric,
+          dataSources: datasourceMetaFrom(metric.catalog),
+          query: updateCatalogVisualizationQuery({
+            ...queryMetaData,
+            ...dateSpanFilter,
+          }),
+          queryMetaData,
+          subType: PPL_METRIC_SUBTYPE,
+          metricType: PROMQL_METRIC_SUBTYPE,
+          dateRange: ['now-1d', 'now'],
+          fields: ['@value'],
+          timestamp: '@timestamp',
+        },
+        dateSpanFilter.span,
+        dateSpanFilter.reoslution
+      );
+    }
 
     const savedObject = await OSDSavedVisualizationClient.getInstance().create(visMetaData);
     return savedObject;
@@ -225,7 +245,7 @@ const MetricsExportPopOver = () => {
     const client = dashboardsLoader.savedObjectsClient;
 
     Promise.all(
-      osdCoreSelectedDashboards.map(async ({ panel: dashboard }, index) => {
+      osdCoreSelectedDashboards.map(async ({ panel: dashboard }) => {
         const referenceCount = dashboard.references.length;
         const maxPanelY = dashboard.panelConfig.reduce(panelXYorGreaterThanValue, 0);
         const maxPanelVersion = dashboard.panelConfig.reduce(
@@ -247,6 +267,7 @@ const MetricsExportPopOver = () => {
 
         const panelsJSON = JSON.stringify(dashboard.panelConfig);
 
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
         const updateRes = await client.update(
           dashboard.type,
           dashboard.id,
@@ -301,7 +322,7 @@ const MetricsExportPopOver = () => {
 
     try {
       savedMetrics = await Promise.all(
-        metricsToExport.map(async (metric, index) => {
+        metricsToExport.map(async (metric) => {
           if (metric.savedVisualizationId === undefined) {
             return createSavedVisualization(metric);
           } else {
diff --git a/public/components/metrics/view/metrics_grid.tsx b/public/components/metrics/view/metrics_grid.tsx
index 161431918d..7daa0908b7 100644
--- a/public/components/metrics/view/metrics_grid.tsx
+++ b/public/components/metrics/view/metrics_grid.tsx
@@ -4,7 +4,7 @@
  */
 
 import React, { useEffect, useMemo } from 'react';
-import { EuiContextMenuItem, EuiDragDropContext, EuiDraggable, EuiDroppable } from '@elastic/eui';
+import { EuiDragDropContext, EuiDraggable, EuiDroppable } from '@elastic/eui';
 import { useObservable } from 'react-use';
 import { connect } from 'react-redux';
 import { CoreStart } from '../../../../../../src/core/public';
@@ -21,7 +21,11 @@ import {
 
 import './metrics_grid.scss';
 import { coreRefs } from '../../../framework/core_refs';
-import { PROMQL_METRIC_SUBTYPE } from '../../../../common/constants/shared';
+import {
+  PROMQL_METRIC_SUBTYPE,
+  OTEL_METRIC_SUBTYPE,
+  observabilityLogsID,
+} from '../../../../common/constants/shared';
 import { MetricsEditInline } from '../sidebar/metrics_edit_inline';
 import { EmptyMetricsView } from './empty_view';
 
@@ -32,9 +36,10 @@ interface MetricsGridProps {
   moveToEvents: (savedVisualizationId: string) => any;
 }
 
-const visualizationFromMetric = (metric, dateSpanFilter): SavedVisualizationType => ({
+const visualizationFromPromethesMetric = (metric, dateSpanFilter): SavedVisualizationType => ({
   ...metric,
   query: updateCatalogVisualizationQuery({ ...metric, ...dateSpanFilter }),
+  metricType: PROMQL_METRIC_SUBTYPE,
   queryMetaData: {
     catalogSourceName: metric.catalogSourceName,
     catalogTableName: metric.catalogTableName,
@@ -53,18 +58,30 @@ const visualizationFromMetric = (metric, dateSpanFilter): SavedVisualizationType
   },
 });
 
-const promQLActionMenu = [
-  <EuiContextMenuItem
-    data-test-subj="showCatalogPPLQuery"
-    key="view_query"
-    onClick={() => {
-      closeActionsMenu();
-      showModal('catalogModal');
-    }}
-  >
-    View query
-  </EuiContextMenuItem>,
-];
+const visualizationFromOtelMetric = (metric, dateSpanFilter): SavedVisualizationType => ({
+  ...metric,
+  name: metric.name,
+  description: '',
+  query: '',
+  type: 'bar',
+  metricType: OTEL_METRIC_SUBTYPE,
+  selected_date_range: {
+    start: dateSpanFilter.start,
+    end: dateSpanFilter.end,
+    text: '',
+  },
+  userConfigs: {
+    dataConfig: {
+      type: 'bar',
+    },
+  },
+});
+
+const visualizationFromMetric = (metric: any, dateSpanFilter: any) => {
+  if (metric.metricType === OTEL_METRIC_SUBTYPE)
+    return visualizationFromOtelMetric(metric, dateSpanFilter);
+  return visualizationFromPromethesMetric(metric, dateSpanFilter);
+};
 
 const navigateToEventExplorerVisualization = (savedVisualizationId: string) => {
   window.location.assign(`${observabilityLogsID}#/explorer/${savedVisualizationId}`);
@@ -72,7 +89,6 @@ const navigateToEventExplorerVisualization = (savedVisualizationId: string) => {
 
 export const InnerGridVisualization = ({ id, idx, dateSpanFilter, metric, refresh }) => {
   if (!metric) return <></>;
-
   return (
     <EuiDraggable key={id} index={idx} draggableId={id}>
       <VisualizationContainer
@@ -91,9 +107,13 @@ export const InnerGridVisualization = ({ id, idx, dateSpanFilter, metric, refres
         resolution={dateSpanFilter.resolution}
         contextMenuId="metrics"
         inlineEditor={
-          metric.subType === PROMQL_METRIC_SUBTYPE && <MetricsEditInline visualization={metric} />
+          metric.metricType === PROMQL_METRIC_SUBTYPE && (
+            <MetricsEditInline visualization={metric} />
+          )
         }
         actionMenuType="metricsGrid"
+        metricType={metric.subType}
+        panelVisualization={metric}
       />
     </EuiDraggable>
   );
diff --git a/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap b/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap
index 944dcc5f6b..0b52d72224 100644
--- a/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap
+++ b/public/components/visualizations/charts/__tests__/__snapshots__/histogram.test.tsx.snap
@@ -694,7 +694,7 @@ exports[`Histogram component Renders histogram component 1`] = `
             },
           },
           "name": "count()",
-          "type": undefined,
+          "type": "histogram",
           "x": Array [
             154,
             1753,
@@ -747,7 +747,7 @@ exports[`Histogram component Renders histogram component 1`] = `
               },
             },
             "name": "count()",
-            "type": undefined,
+            "type": "histogram",
             "x": Array [
               154,
               1753,
diff --git a/public/components/visualizations/charts/lines/line.tsx b/public/components/visualizations/charts/lines/line.tsx
index 539240eb83..d474f98d1a 100644
--- a/public/components/visualizations/charts/lines/line.tsx
+++ b/public/components/visualizations/charts/lines/line.tsx
@@ -4,7 +4,7 @@
  */
 
 import { isEmpty, last } from 'lodash';
-import React, { useEffect, useMemo } from 'react';
+import React, { useMemo } from 'react';
 import _ from 'lodash';
 import { AGGREGATIONS, GROUPBY } from '../../../../../common/constants/explorer';
 import {
@@ -57,7 +57,7 @@ export const Line = ({ visualizations, layout, config }: any) => {
         availabilityConfig = {},
       } = {},
     },
-    vis: { icontype, name },
+    vis: { name },
   }: IVisualizationContainerProps = visualizations;
 
   const tooltipMode =
@@ -160,7 +160,7 @@ export const Line = ({ visualizations, layout, config }: any) => {
 
     visConfig = {
       ...visConfig,
-      ...processMetricsData(schema, visConfig),
+      ...processMetricsData(schema),
     };
 
     const traceStyles = {
diff --git a/public/components/visualizations/saved_object_visualization.tsx b/public/components/visualizations/saved_object_visualization.tsx
index 8fbad59118..5eeeb6010c 100644
--- a/public/components/visualizations/saved_object_visualization.tsx
+++ b/public/components/visualizations/saved_object_visualization.tsx
@@ -2,6 +2,7 @@
  * Copyright OpenSearch Contributors
  * SPDX-License-Identifier: Apache-2.0
  */
+/* eslint-disable @typescript-eslint/no-unused-vars */
 
 import _ from 'lodash';
 import React, { useEffect, useState } from 'react';
@@ -13,9 +14,11 @@ import { getPPLService, preprocessQuery, removeBacktick } from '../../../common/
 import { getDefaultVisConfig } from '../event_analytics/utils';
 import { getVizContainerProps } from './charts/helpers';
 import { Visualization } from './visualization';
-import { PROMQL_METRIC_SUBTYPE } from '../../../common/constants/shared';
-import { getMetricVisConfig } from '../event_analytics/utils/utils';
+import { OTEL_METRIC_SUBTYPE, PROMQL_METRIC_SUBTYPE } from '../../../common/constants/shared';
+import { fetchOtelMetric, getMetricVisConfig } from '../event_analytics/utils/utils';
 import { preprocessMetricQuery } from '../common/query_utils';
+import { constructOtelMetricsMetaData } from '../custom_panels/helpers/utils';
+import { useToast } from '../common/toast';
 
 interface SavedObjectVisualizationProps {
   savedVisualization: SavedVisualization;
@@ -30,20 +33,24 @@ interface SavedObjectVisualizationProps {
  */
 export const SavedObjectVisualization: React.FC<SavedObjectVisualizationProps> = (props) => {
   const [visContainerProps, setVisContainerProps] = useState<IVisualizationContainerProps>();
+  const [isError, setIsError] = useState([]);
+  const [isLoading, setIsLoading] = useState(false);
+  const { setToast } = useToast();
 
   useEffect(() => {
     const pplService = getPPLService();
-    const isMetric = props.savedVisualization?.subType === PROMQL_METRIC_SUBTYPE;
+    const isPromqlMetric = props.savedVisualization?.metricType === PROMQL_METRIC_SUBTYPE;
+    const isOtelMetric = props.savedVisualization?.metricType === OTEL_METRIC_SUBTYPE;
     const metaData = {
       ...props.savedVisualization,
       query: props.savedVisualization.query,
       queryMetaData: props.savedVisualization.queryMetaData,
-      isMetric,
+      isPromqlMetric,
     };
     const userConfigs = getUserConfigFrom(metaData);
     const dataConfig = { ...(userConfigs.dataConfig || {}) };
     const hasBreakdowns = !_.isEmpty(dataConfig.breakdowns);
-    const realTimeParsedStats = isMetric
+    const realTimeParsedStats = isPromqlMetric
       ? getMetricVisConfig(metaData)
       : {
           ...getDefaultVisConfig(new QueryManager().queryParser().parse(metaData.query).getStats()),
@@ -59,13 +66,17 @@ export const SavedObjectVisualization: React.FC<SavedObjectVisualizationProps> =
       );
     }
 
-    const finalDataConfig = {
+    let finalDataConfig = {
       ...dataConfig,
       ...realTimeParsedStats,
       dimensions: finalDimensions,
       breakdowns,
     };
 
+    if (isOtelMetric) {
+      finalDataConfig = { ...finalDataConfig, ...constructOtelMetricsMetaData() };
+    }
+
     const mixedUserConfigs = {
       availabilityConfig: {
         ...(userConfigs.availabilityConfig || {}),
@@ -81,12 +92,14 @@ export const SavedObjectVisualization: React.FC<SavedObjectVisualizationProps> =
     let query = metaData.query;
 
     if (props.timeRange) {
-      if (isMetric) {
+      if (isPromqlMetric) {
         query = preprocessMetricQuery({
           metaData,
           startTime: props.timeRange.from,
           endTime: props.timeRange.to,
         });
+      } else if (isOtelMetric) {
+        query = '';
       } else {
         query = preprocessQuery({
           rawQuery: metaData.query,
@@ -99,22 +112,50 @@ export const SavedObjectVisualization: React.FC<SavedObjectVisualizationProps> =
       }
     }
 
-    pplService
-      .fetch({ query, format: 'jdbc' })
-      .then((data) => {
-        const container = getVizContainerProps({
-          vizId: props.savedVisualization.type,
-          rawVizData: data,
-          query: { rawQuery: metaData.query },
-          indexFields: {},
-          userConfigs: mixedUserConfigs,
-          explorer: { explorerData: data, explorerFields: data.schema },
-        });
-        setVisContainerProps(container);
+    if (isOtelMetric) {
+      const visualizationName = props.savedVisualization?.name;
+      const startTime = props.timeRange?.from;
+      const endTime = props.timeRange?.to;
+      const data = fetchOtelMetric({
+        visualizationName,
+        startTime,
+        endTime,
+        setIsError,
+        setIsLoading,
+        setToast,
       })
-      .catch((error: Error) => {
-        console.error(error);
-      });
+        .then((jsonData) => {
+          const container = getVizContainerProps({
+            vizId: props.savedVisualization.type,
+            rawVizData: data,
+            query: { rawQuery: metaData.query },
+            indexFields: {},
+            userConfigs: mixedUserConfigs,
+            explorer: { explorerData: jsonData },
+          });
+          setVisContainerProps(container);
+        })
+        .catch((error: Error) => {
+          console.error(error);
+        });
+    } else {
+      pplService
+        .fetch({ query, format: 'jdbc' })
+        .then((data) => {
+          const container = getVizContainerProps({
+            vizId: props.savedVisualization.type,
+            rawVizData: data,
+            query: { rawQuery: metaData.query },
+            indexFields: {},
+            userConfigs: mixedUserConfigs,
+            explorer: { explorerData: data, explorerFields: data.schema },
+          });
+          setVisContainerProps(container);
+        })
+        .catch((error: Error) => {
+          console.error(error);
+        });
+    }
   }, [props]);
 
   return visContainerProps ? <Visualization visualizations={visContainerProps} /> : null;
diff --git a/public/components/visualizations/visualization.tsx b/public/components/visualizations/visualization.tsx
index 25e7bbf363..14c25e8ea5 100644
--- a/public/components/visualizations/visualization.tsx
+++ b/public/components/visualizations/visualization.tsx
@@ -29,14 +29,14 @@ export const Visualization = ({
             [GROUPBY]: dimensions = [],
             [AGGREGATIONS]: series = [],
             queryMetaData = {},
-            subType = '',
+            metricType = '',
           } = {},
         } = {},
       },
       vis = {},
     }: IVisualizationContainerProps = vs;
 
-    if (subType === PROMQL_METRIC_SUBTYPE) {
+    if (metricType === PROMQL_METRIC_SUBTYPE) {
       if (isEmpty(queryMetaData)) return [false, VISUALIZATION_ERROR.NO_METRIC];
 
       // Metric checks OK.
@@ -55,7 +55,6 @@ export const Visualization = ({
   };
 
   const [isValid, erroInfo] = isVisDataValid(visualizations);
-
   return (
     <>
       {isValid ? (
diff --git a/public/components/visualizations/visualization_chart.tsx b/public/components/visualizations/visualization_chart.tsx
index 7f84619785..3700f758db 100644
--- a/public/components/visualizations/visualization_chart.tsx
+++ b/public/components/visualizations/visualization_chart.tsx
@@ -9,7 +9,6 @@ export const VisualizationChart = ({ visualizations }) => {
   const { vis } = visualizations;
   const { layout = {}, config = {} } = visualizations?.data?.userConfigs;
   const Visualization = visualizations?.vis?.component;
-
   const finalFigureConfig = useMemo(() => {
     return {
       ...vis.visconfig?.config,
diff --git a/public/embeddable/observability_embeddable.tsx b/public/embeddable/observability_embeddable.tsx
index 3cf75f404d..f21299fab7 100644
--- a/public/embeddable/observability_embeddable.tsx
+++ b/public/embeddable/observability_embeddable.tsx
@@ -18,7 +18,11 @@ import {
   VisualizationSavedObjectAttributes,
 } from '../../common/types/observability_saved_object_attributes';
 import { ObservabilityEmbeddableComponent } from './observability_embeddable_component';
-import { observabilityMetricsID, PROMQL_METRIC_SUBTYPE } from '../../common/constants/shared';
+import {
+  observabilityMetricsID,
+  PROMQL_METRIC_SUBTYPE,
+  OTEL_METRIC_SUBTYPE,
+} from '../../common/constants/shared';
 
 // this needs to match the saved object type for the clone and replace panel actions to work
 export const OBSERVABILITY_EMBEDDABLE = VISUALIZATION_SAVED_OBJECT;
@@ -80,8 +84,9 @@ export class ObservabilityEmbeddable extends Embeddable<
 
   public async reload() {
     this.attributes = await this.attributeService.unwrapAttributes(this.input);
-
-    const isMetric = this.attributes?.savedVisualization?.subType === PROMQL_METRIC_SUBTYPE;
+    const isMetric =
+      this.attributes?.savedVisualization?.metricType ===
+      (PROMQL_METRIC_SUBTYPE || OTEL_METRIC_SUBTYPE);
     if (isMetric) {
       const editPath = `#/${VISUALIZATION_SAVED_OBJECT}:${this.savedObjectId}`;
       const editUrl = `/app/${observabilityMetricsID}${editPath}`;
diff --git a/public/services/saved_objects/event_analytics/saved_objects.ts b/public/services/saved_objects/event_analytics/saved_objects.ts
index cb423f657f..22267611ae 100644
--- a/public/services/saved_objects/event_analytics/saved_objects.ts
+++ b/public/services/saved_objects/event_analytics/saved_objects.ts
@@ -2,9 +2,10 @@
  * Copyright OpenSearch Contributors
  * SPDX-License-Identifier: Apache-2.0
  */
+/* eslint-disable no-unused-vars */
 
 import { has, isArray, isEmpty } from 'lodash';
-import { IField } from 'common/types/explorer';
+import { IField } from '../../../../common/types/explorer';
 import {
   EVENT_ANALYTICS,
   OBSERVABILITY_BASE,
@@ -58,6 +59,7 @@ export default class SavedObjects {
     applicationId = '',
     userConfigs = '',
     subType = '',
+    metricType = '',
     unitsOfMeasure = '',
     selectedLabels,
   }: any) {
@@ -98,6 +100,10 @@ export default class SavedObjects {
       objRequest.object.subType = subType;
     }
 
+    if (!isEmpty(metricType)) {
+      objRequest.object.metricType = metricType;
+    }
+
     if (!isEmpty(unitsOfMeasure)) {
       objRequest.object.units_of_measure = unitsOfMeasure;
     }
@@ -161,6 +167,7 @@ export default class SavedObjects {
       userConfigs: params.userConfigs,
       description: params.description,
       subType: params.subType,
+      metricType: params.metricType,
       unitsOfMeasure: params.unitsOfMeasure,
       selectedLabels: params.selectedLabels,
     });
@@ -224,6 +231,7 @@ export default class SavedObjects {
       userConfigs: params.userConfigs,
       description: params.description,
       subType: params.subType,
+      metricType: params.metricType,
       unitsOfMeasure: params.unitsOfMeasure,
       selectedLabels: params.selectedLabels,
     });
diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts
index 323242eb07..57bf9cf183 100644
--- a/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts
+++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/osd_saved_object_client.ts
@@ -74,6 +74,7 @@ export abstract class OSDSavedObjectClient extends SavedObjectClientBase {
     applicationId = '',
     userConfigs = '',
     subType = '',
+    metricType = '',
     unitsOfMeasure = '',
     selectedLabels,
     objectId = '',
@@ -118,6 +119,10 @@ export abstract class OSDSavedObjectClient extends SavedObjectClientBase {
       objRequest.object.subType = subType;
     }
 
+    if (!isEmpty(metricType)) {
+      objRequest.object.metricType = metricType;
+    }
+
     if (!isEmpty(unitsOfMeasure)) {
       objRequest.object.units_of_measure = unitsOfMeasure;
     }
diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_searches.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_searches.ts
index 45b5e3de4f..be17739f45 100644
--- a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_searches.ts
+++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_searches.ts
@@ -32,6 +32,7 @@ interface CommonParams {
   userConfigs: any;
   description: string;
   subType: string;
+  metricType: string;
   unitsOfMeasure: string;
   selectedLabels: string;
   dataSources: string; // list of type SelectedDataSources that is stringified
diff --git a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts
index 045fa3e507..c09d35ced1 100644
--- a/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts
+++ b/public/services/saved_objects/saved_object_client/osd_saved_objects/saved_visualization.ts
@@ -33,6 +33,7 @@ interface CommonParams {
   userConfigs: any;
   description: string;
   subType: string;
+  metricType: string;
   unitsOfMeasure: string;
   selectedLabels: string;
   dataSources: string; // list of type SelectedDataSources that is stringified
@@ -64,6 +65,7 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient {
       userConfigs: params.userConfigs,
       description: params.description,
       subType: params.subType,
+      metricType: params.metricType,
       unitsOfMeasure: params.unitsOfMeasure,
       selectedLabels: params.selectedLabels,
       dataSources: params.dataSources,
@@ -104,6 +106,7 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient {
       userConfigs: params.userConfigs,
       description: params.description,
       subType: params.subType,
+      metricType: params.metricType,
       unitsOfMeasure: params.unitsOfMeasure,
       selectedLabels: params.selectedLabels,
       dataSources: params.dataSources,
@@ -160,6 +163,7 @@ export class OSDSavedVisualizationClient extends OSDSavedObjectClient {
           createdTimeMs: o.attributes.createdTimeMs,
           lastUpdatedTimeMs: OSDSavedObjectClient.convertToLastUpdatedMs(o.updated_at),
           savedVisualization: o.attributes.savedVisualization,
+          metricType: o.attributes.metricType,
         }))
       );
     return { totalHits: observabilityObjectList.length, observabilityObjectList };
diff --git a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts
index e7573820d8..32aa843d4d 100644
--- a/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts
+++ b/public/services/saved_objects/saved_object_client/ppl/ppl_client.ts
@@ -82,6 +82,7 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave
     applicationId = '',
     userConfigs = '',
     subType = '',
+    metricType = '',
     unitsOfMeasure = '',
     selectedLabels,
     objectId = '',
@@ -123,6 +124,10 @@ export class PPLSavedObjectClient extends SavedObjectClientBase implements ISave
       objRequest.object.subType = subType;
     }
 
+    if (!isEmpty(metricType)) {
+      objRequest.object.metricType = metricType;
+    }
+
     if (!isEmpty(unitsOfMeasure)) {
       objRequest.object.units_of_measure = unitsOfMeasure;
     }
diff --git a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts
index 5540412940..38116698f9 100644
--- a/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts
+++ b/public/services/saved_objects/saved_object_client/ppl/saved_visualization.ts
@@ -25,6 +25,7 @@ interface CommonParams {
   userConfigs: any;
   description: string;
   subType: string;
+  metricType: string;
   unitsOfMeasure: string;
   selectedLabels: string;
 }
@@ -51,6 +52,7 @@ export class PPLSavedVisualizationClient extends PPLSavedObjectClient {
             userConfigs: params.userConfigs,
             description: params.description,
             subType: params.subType,
+            metricType: params.metricType,
             unitsOfMeasure: params.unitsOfMeasure,
             selectedLabels: params.selectedLabels,
           })
@@ -74,6 +76,7 @@ export class PPLSavedVisualizationClient extends PPLSavedObjectClient {
             userConfigs: params.userConfigs,
             description: params.description,
             subType: params.subType,
+            metricType: params.metricType,
             unitsOfMeasure: params.unitsOfMeasure,
             selectedLabels: params.selectedLabels,
             objectId: params.objectId,
diff --git a/public/services/saved_objects/saved_object_client/saved_objects_actions.ts b/public/services/saved_objects/saved_object_client/saved_objects_actions.ts
index 3a1fc5a664..55ae3225ec 100644
--- a/public/services/saved_objects/saved_object_client/saved_objects_actions.ts
+++ b/public/services/saved_objects/saved_object_client/saved_objects_actions.ts
@@ -46,16 +46,19 @@ export class SavedObjectsActions {
   static async getBulk<T extends ObservabilitySavedObject>(
     params: ISavedObjectRequestParams
   ): Promise<SavedObjectsGetResponse<T>> {
-    const objects = await PPLSavedQueryClient.getInstance().getBulk(params);
+    let objects = await PPLSavedQueryClient.getInstance().getBulk(params);
     if (params.objectType?.includes('savedVisualization')) {
       const osdVisualizationObjects = await OSDSavedVisualizationClient.getInstance().getBulk();
       if (objects.totalHits && osdVisualizationObjects.totalHits) {
         objects.totalHits += osdVisualizationObjects.totalHits;
       }
-      objects.observabilityObjectList = [
-        ...objects.observabilityObjectList,
-        ...osdVisualizationObjects.observabilityObjectList,
-      ];
+      objects = {
+        ...objects,
+        observabilityObjectList: [
+          ...objects.observabilityObjectList,
+          ...osdVisualizationObjects.observabilityObjectList,
+        ],
+      };
     }
 
     if (params.objectType?.includes('savedQuery')) {
@@ -63,10 +66,13 @@ export class SavedObjectsActions {
       if (objects.totalHits && osdSearchObjects.totalHits) {
         objects.totalHits += osdSearchObjects.totalHits;
       }
-      objects.observabilityObjectList = [
-        ...objects.observabilityObjectList,
-        ...osdSearchObjects.observabilityObjectList,
-      ];
+      objects = {
+        ...objects,
+        observabilityObjectList: [
+          ...objects.observabilityObjectList,
+          ...osdSearchObjects.observabilityObjectList,
+        ],
+      };
     }
 
     if (params.sortOrder === 'asc') {
diff --git a/server/adaptors/custom_panels/custom_panel_adaptor.ts b/server/adaptors/custom_panels/custom_panel_adaptor.ts
index d82251ab96..d7ce214625 100644
--- a/server/adaptors/custom_panels/custom_panel_adaptor.ts
+++ b/server/adaptors/custom_panels/custom_panel_adaptor.ts
@@ -228,6 +228,9 @@ export class CustomPanelsAdaptor {
       subType: visualization.savedVisualization.hasOwnProperty('subType')
         ? visualization.savedVisualization.subType
         : '',
+      metricType: visualization.savedVisualization.hasOwnProperty('metricType')
+        ? visualization.savedVisualization.metricType
+        : '',
       units_of_measure: visualization.savedVisualization.hasOwnProperty('units_of_measure')
         ? visualization.savedVisualization.units_of_measure
         : '',
diff --git a/server/adaptors/metrics/metrics_analytics_adaptor.ts b/server/adaptors/metrics/metrics_analytics_adaptor.ts
new file mode 100644
index 0000000000..1fde1e3956
--- /dev/null
+++ b/server/adaptors/metrics/metrics_analytics_adaptor.ts
@@ -0,0 +1,150 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { ILegacyScopedClusterClient } from '../../../../../src/core/server';
+
+export class MetricsAnalyticsAdaptor {
+  fetch = async function (client: ILegacyScopedClusterClient, query: any, index: string) {
+    try {
+      const response = await client.callAsCurrentUser('search', {
+        body: query,
+        index,
+      });
+      return response;
+    } catch (error) {
+      throw new Error('Fetch Otel Metrics Error:' + error);
+    }
+  };
+
+  queryToFetchBinCount = async (
+    client: ILegacyScopedClusterClient,
+    min: string,
+    max: string,
+    startTime: string,
+    endTime: string,
+    documentName: string,
+    index: string
+  ) => {
+    const metricsQuery = {
+      size: 0,
+      query: {
+        bool: {
+          must: [
+            {
+              term: {
+                'name.keyword': {
+                  value: documentName,
+                },
+              },
+            },
+            {
+              range: {
+                time: {
+                  gte: startTime,
+                  lte: endTime,
+                },
+              },
+            },
+          ],
+        },
+      },
+      aggs: {
+        nested_buckets: {
+          nested: {
+            path: 'buckets',
+          },
+          aggs: {
+            bucket_range: {
+              filter: {
+                range: {
+                  'buckets.max': {
+                    gt: min,
+                    lte: max,
+                  },
+                },
+              },
+              aggs: {
+                bucket_count: {
+                  sum: {
+                    field: 'buckets.count',
+                  },
+                },
+              },
+            },
+          },
+        },
+      },
+    };
+
+    try {
+      const response = await this.fetch(client, metricsQuery, index);
+      return response.aggregations;
+    } catch (error) {
+      throw new Error('Fetch Bin count Error:' + error);
+    }
+  };
+
+  queryToFetchSampleDocument = async (
+    client: ILegacyScopedClusterClient,
+    documentName: string,
+    index: string
+  ) => {
+    const metricsQuery = {
+      size: 1,
+      query: {
+        bool: {
+          must: [
+            {
+              term: {
+                'name.keyword': {
+                  value: documentName,
+                },
+              },
+            },
+          ],
+        },
+      },
+    };
+
+    try {
+      const response = await this.fetch(client, metricsQuery, index);
+      return response;
+    } catch (error) {
+      throw new Error('Fetch Sample Document Error:' + error);
+    }
+  };
+
+  queryToFetchDocumentNames = async (client: ILegacyScopedClusterClient, index: string) => {
+    const metricsQuery = {
+      size: 0,
+      query: {
+        bool: {
+          filter: [
+            {
+              term: {
+                kind: 'HISTOGRAM',
+              },
+            },
+          ],
+        },
+      },
+      aggs: {
+        distinct_names: {
+          terms: {
+            field: 'name.keyword',
+            size: 500,
+          },
+        },
+      },
+    };
+
+    try {
+      const response = await this.fetch(client, metricsQuery, index);
+      return response;
+    } catch (error) {
+      throw new Error('Fetch Document Names Error:' + error);
+    }
+  };
+}
diff --git a/server/routes/event_analytics/event_analytics_router.ts b/server/routes/event_analytics/event_analytics_router.ts
index b23cfc181f..57ed898dd0 100644
--- a/server/routes/event_analytics/event_analytics_router.ts
+++ b/server/routes/event_analytics/event_analytics_router.ts
@@ -139,6 +139,7 @@ export const registerEventAnalyticsRouter = ({
             application_id: schema.maybe(schema.string()),
             userConfigs: schema.maybe(schema.string()),
             subType: schema.maybe(schema.string()),
+            metricType: schema.maybe(schema.string()),
             units_of_measure: schema.maybe(schema.string()),
             selected_labels: schema.maybe(
               schema.object({
@@ -233,6 +234,7 @@ export const registerEventAnalyticsRouter = ({
             application_id: schema.maybe(schema.string()),
             userConfigs: schema.maybe(schema.string()),
             subType: schema.maybe(schema.string()),
+            metricType: schema.maybe(schema.string()),
             units_of_measure: schema.maybe(schema.string()),
             selected_labels: schema.maybe(
               schema.object({
diff --git a/server/routes/metrics/metrics_rounter.ts b/server/routes/metrics/metrics_rounter.ts
index e207701f07..3891d392d7 100644
--- a/server/routes/metrics/metrics_rounter.ts
+++ b/server/routes/metrics/metrics_rounter.ts
@@ -5,11 +5,19 @@
 
 import { ResponseError } from '@opensearch-project/opensearch/lib/errors';
 import { schema } from '@osd/config-schema';
-import { IOpenSearchDashboardsResponse, IRouter } from '../../../../../src/core/server';
+import {
+  ILegacyScopedClusterClient,
+  IOpenSearchDashboardsResponse,
+  IRouter,
+} from '../../../../../src/core/server';
 import { OBSERVABILITY_BASE } from '../../../common/constants/shared';
 import { addClickToMetric, getMetrics } from '../../common/metrics/metrics_helper';
+import { MetricsAnalyticsAdaptor } from '../../adaptors/metrics/metrics_analytics_adaptor';
+import { DATA_PREPPER_INDEX_NAME } from '../../../common/constants/metrics';
 
 export function registerMetricsRoute(router: IRouter) {
+  const metricsAnalyticsBackend = new MetricsAnalyticsAdaptor();
+
   router.get(
     {
       path: `${OBSERVABILITY_BASE}/stats`,
@@ -62,4 +70,152 @@ export function registerMetricsRoute(router: IRouter) {
       }
     }
   );
+
+  router.get(
+    {
+      path: `${OBSERVABILITY_BASE}/search/indices`,
+      validate: {},
+    },
+    async (context, request, response) => {
+      const params = {
+        format: 'json',
+        index: DATA_PREPPER_INDEX_NAME,
+      };
+      try {
+        const resp = await context.core.opensearch.legacy.client.callAsCurrentUser(
+          'cat.indices',
+          params
+        );
+        return response.ok({
+          body: resp,
+        });
+      } catch (error) {
+        if (error.statusCode !== 404) console.error(error);
+        return response.custom({
+          statusCode: error.statusCode || 500,
+          body: error.message,
+        });
+      }
+    }
+  );
+
+  router.get(
+    {
+      path: `${OBSERVABILITY_BASE}/metrics/otel/{index}/documentNames`,
+      validate: {
+        params: schema.object({
+          index: schema.string(),
+        }),
+      },
+    },
+    async (
+      context,
+      request,
+      response
+    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
+      const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+        request
+      );
+
+      try {
+        const resp = await metricsAnalyticsBackend.queryToFetchDocumentNames(
+          opensearchNotebooksClient,
+          request.params.index
+        );
+        return response.ok({
+          body: resp,
+        });
+      } catch (error) {
+        if (error.statusCode !== 404) console.error(error);
+        return response.custom({
+          statusCode: error.statusCode || 500,
+          body: error.message,
+        });
+      }
+    }
+  );
+
+  router.get(
+    {
+      path: `${OBSERVABILITY_BASE}/metrics/otel/{index}/{histogramSampleDocument}`,
+      validate: {
+        params: schema.object({
+          histogramSampleDocument: schema.string(),
+          index: schema.string(),
+        }),
+      },
+    },
+    async (
+      context,
+      request,
+      response
+    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
+      const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+        request
+      );
+
+      try {
+        const resp = await metricsAnalyticsBackend.queryToFetchSampleDocument(
+          opensearchNotebooksClient,
+          request.params.histogramSampleDocument,
+          request.params.index
+        );
+        return response.ok({
+          body: resp.hits,
+        });
+      } catch (error) {
+        if (error.statusCode !== 404) console.error(error);
+        return response.custom({
+          statusCode: error.statusCode || 500,
+          body: error.message,
+        });
+      }
+    }
+  );
+
+  router.post(
+    {
+      path: `${OBSERVABILITY_BASE}/metrics/otel/aggregatedBinCount`,
+      validate: {
+        body: schema.object({
+          min: schema.string(),
+          max: schema.string(),
+          startTime: schema.string(),
+          endTime: schema.string(),
+          documentName: schema.string(),
+          index: schema.string(),
+        }),
+      },
+    },
+    async (
+      context,
+      request,
+      response
+    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
+      const opensearchNotebooksClient: ILegacyScopedClusterClient = context.observability_plugin.observabilityClient.asScoped(
+        request
+      );
+
+      try {
+        const resp = await metricsAnalyticsBackend.queryToFetchBinCount(
+          opensearchNotebooksClient,
+          request.body.min,
+          request.body.max,
+          request.body.startTime,
+          request.body.endTime,
+          request.body.documentName,
+          request.body.index
+        );
+        return response.ok({
+          body: resp,
+        });
+      } catch (error) {
+        if (error.statusCode !== 404) console.error(error);
+        return response.custom({
+          statusCode: error.statusCode || 500,
+          body: error.message,
+        });
+      }
+    }
+  );
 }