diff --git a/app/assets/javascripts/reports/constants.js b/app/assets/javascripts/reports/constants.js
index acd90ebf1b1bf7b7a971b4fd14dd34a505704057..7f7ea2adc0e46457419600c56b5e9cf680f658ab 100644
--- a/app/assets/javascripts/reports/constants.js
+++ b/app/assets/javascripts/reports/constants.js
@@ -16,6 +16,7 @@ export const STATUS_NEUTRAL = 'neutral';
 export const ICON_WARNING = 'warning';
 export const ICON_SUCCESS = 'success';
 export const ICON_NOTFOUND = 'notfound';
+export const ICON_PENDING = 'pending';
 
 export const status = {
   LOADING,
diff --git a/ee/app/assets/javascripts/reports/components/issue_body.js b/ee/app/assets/javascripts/reports/components/issue_body.js
index 86a5a1d3305faa18f663677dc641dc1103ca9545..bcaf11779c960e8a566467d9599e32e4029f658c 100644
--- a/ee/app/assets/javascripts/reports/components/issue_body.js
+++ b/ee/app/assets/javascripts/reports/components/issue_body.js
@@ -1,5 +1,6 @@
 import BlockingMergeRequestsBody from 'ee/vue_merge_request_widget/components/blocking_merge_requests/blocking_merge_request_body.vue';
 import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
+import StatusCheckIssueBody from 'ee/vue_merge_request_widget/components/status_check_issue_body.vue';
 import LicenseIssueBody from 'ee/vue_shared/license_compliance/components/license_issue_body.vue';
 import MetricsReportsIssueBody from 'ee/vue_shared/metrics_reports/components/metrics_reports_issue_body.vue';
 import SecurityIssueBody from 'ee/vue_shared/security_reports/components/security_issue_body.vue';
@@ -10,6 +11,7 @@ import {
 
 export const components = {
   ...componentsCE,
+  StatusCheckIssueBody,
   PerformanceIssueBody,
   LicenseIssueBody,
   SecurityIssueBody,
@@ -19,6 +21,7 @@ export const components = {
 
 export const componentNames = {
   ...componentNamesCE,
+  StatusCheckIssueBody: StatusCheckIssueBody.name,
   PerformanceIssueBody: PerformanceIssueBody.name,
   LicenseIssueBody: LicenseIssueBody.name,
   SecurityIssueBody: SecurityIssueBody.name,
diff --git a/ee/app/assets/javascripts/reports/status_checks_report/constants.js b/ee/app/assets/javascripts/reports/status_checks_report/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b2294222d4989ab33a08485c60a49b46c2cf971
--- /dev/null
+++ b/ee/app/assets/javascripts/reports/status_checks_report/constants.js
@@ -0,0 +1,3 @@
+export const APPROVED = 'approved';
+
+export const PENDING = 'pending';
diff --git a/ee/app/assets/javascripts/reports/status_checks_report/status_checks_reports_app.vue b/ee/app/assets/javascripts/reports/status_checks_report/status_checks_reports_app.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ddc21692dd37488f686348dc2ac2374afa5b8f17
--- /dev/null
+++ b/ee/app/assets/javascripts/reports/status_checks_report/status_checks_reports_app.vue
@@ -0,0 +1,113 @@
+<script>
+import { GlLink, GlSprintf } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
+import { componentNames } from 'ee/reports/components/issue_body';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import axios from '~/lib/utils/axios_utils';
+import { sprintf, s__ } from '~/locale';
+import ReportSection from '~/reports/components/report_section.vue';
+import { status } from '~/reports/constants';
+import { APPROVED, PENDING } from './constants';
+
+export default {
+  name: 'StatusChecksReportsApp',
+  components: {
+    GlLink,
+    GlSprintf,
+    ReportSection,
+  },
+  componentNames,
+  props: {
+    endpoint: {
+      type: String,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      reportStatus: status.LOADING,
+      statusChecks: [],
+    };
+  },
+  computed: {
+    approvedStatusChecks() {
+      return this.statusChecks.filter((s) => s.status === APPROVED);
+    },
+    pendingStatusChecks() {
+      return this.statusChecks.filter((s) => s.status === PENDING);
+    },
+    hasStatusChecks() {
+      return this.statusChecks.length > 0;
+    },
+    headingReportText() {
+      if (this.pendingStatusChecks.length > 0) {
+        return sprintf(s__('StatusCheck|%{pending} pending'), {
+          pending: this.pendingStatusChecks.length,
+        });
+      }
+      return s__('StatusCheck|All passed');
+    },
+  },
+  mounted() {
+    this.fetchStatusChecks();
+  },
+  methods: {
+    fetchStatusChecks() {
+      axios
+        .get(this.endpoint)
+        .then(({ data }) => {
+          this.statusChecks = data;
+          this.reportStatus = status.SUCCESS;
+        })
+        .catch((error) => {
+          this.reportStatus = status.ERROR;
+          Sentry.captureException(error);
+        });
+    },
+  },
+  i18n: {
+    heading: s__('StatusCheck|Status checks'),
+    subHeading: s__(
+      'StatusCheck|When this merge request is updated, a call is sent to the following APIs to confirm their status. %{linkStart}Learn more%{linkEnd}.',
+    ),
+    errorText: s__('StatusCheck|Failed to load status checks.'),
+  },
+  docsLink: helpPagePath('user/project/merge_requests/approvals/index.md', {
+    anchor: 'notify-external-services',
+  }),
+};
+</script>
+
+<template>
+  <report-section
+    :status="reportStatus"
+    :loading-text="$options.i18n.heading"
+    :error-text="$options.i18n.errorText"
+    :has-issues="hasStatusChecks"
+    :resolved-issues="approvedStatusChecks"
+    :neutral-issues="pendingStatusChecks"
+    :component="$options.componentNames.StatusCheckIssueBody"
+    :show-report-section-status-icon="false"
+    issues-list-container-class="gl-p-0 gl-border-top-0"
+    issues-ul-element-class="gl-p-0"
+    data-test-id="mr-status-checks"
+    class="mr-widget-section mr-report"
+  >
+    <template #success>
+      <p class="gl-line-height-normal gl-m-0">
+        {{ $options.i18n.heading }}
+        <strong class="gl-p-1">{{ headingReportText }}</strong>
+      </p>
+    </template>
+
+    <template #sub-heading>
+      <span class="gl-text-gray-500 gl-font-sm">
+        <gl-sprintf :message="$options.i18n.subHeading">
+          <template #link="{ content }">
+            <gl-link class="gl-font-sm" :href="$options.docsLink">{{ content }}</gl-link>
+          </template>
+        </gl-sprintf>
+      </span>
+    </template>
+  </report-section>
+</template>
diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/components/status_check_issue_body.vue b/ee/app/assets/javascripts/vue_merge_request_widget/components/status_check_issue_body.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b575b0576e0492458876192e132b66c73730c31c
--- /dev/null
+++ b/ee/app/assets/javascripts/vue_merge_request_widget/components/status_check_issue_body.vue
@@ -0,0 +1,36 @@
+<script>
+import SummaryRow from '~/reports/components/summary_row.vue';
+import { ICON_SUCCESS, ICON_PENDING } from '~/reports/constants';
+import { APPROVED } from '../../reports/status_checks_report/constants';
+
+export default {
+  name: 'StatusCheckIssueBody',
+  components: {
+    SummaryRow,
+  },
+  props: {
+    issue: {
+      type: Object,
+      required: true,
+    },
+  },
+  computed: {
+    statusIcon() {
+      if (this.issue.status === APPROVED) {
+        return ICON_SUCCESS;
+      }
+      return ICON_PENDING;
+    },
+  },
+};
+</script>
+
+<template>
+  <div class="gl-w-full" :data-testid="`mr-status-check-issue-${issue.id}`">
+    <summary-row :status-icon="statusIcon" nested-summary>
+      <template #summary>
+        <span>{{ issue.name }}, {{ issue.external_url }}</span>
+      </template>
+    </summary-row>
+  </div>
+</template>
diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 5f30d87669689c6fd9b60a0399d3e5311428ffb0..f84e63ff5a3c398155c2640f5eff41e1efc45331 100644
--- a/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -3,6 +3,7 @@ import { GlSafeHtmlDirective } from '@gitlab/ui';
 import GroupedBrowserPerformanceReportsApp from 'ee/reports/browser_performance_report/grouped_browser_performance_reports_app.vue';
 import { componentNames } from 'ee/reports/components/issue_body';
 import GroupedLoadPerformanceReportsApp from 'ee/reports/load_performance_report/grouped_load_performance_reports_app.vue';
+import StatusChecksReportsApp from 'ee/reports/status_checks_report/status_checks_reports_app.vue';
 import MrWidgetLicenses from 'ee/vue_shared/license_compliance/mr_widget_license_report.vue';
 import GroupedMetricsReportsApp from 'ee/vue_shared/metrics_reports/grouped_metrics_reports_app.vue';
 import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin';
@@ -20,6 +21,7 @@ export default {
     MrWidgetGeoSecondaryNode,
     MrWidgetPolicyViolation,
     MrWidgetJiraAssociationMissing,
+    StatusChecksReportsApp,
     BlockingMergeRequestsReport,
     GroupedSecurityReportsApp: () =>
       import('ee/vue_shared/security_reports/grouped_security_reports_app.vue'),
@@ -101,6 +103,9 @@ export default {
         this.$options.securityReportTypes.some((reportType) => enabledReports[reportType])
       );
     },
+    shouldRenderStatusReport() {
+      return this.mr.apiStatusChecksPath && !this.mr.isNothingToMergeState;
+    },
 
     browserPerformanceText() {
       const { improved, degraded, same } = this.mr.browserPerformanceMetrics;
@@ -417,6 +422,11 @@ export default {
         :endpoint="mr.accessibilityReportPath"
       />
 
+      <status-checks-reports-app
+        v-if="shouldRenderStatusReport"
+        :endpoint="mr.apiStatusChecksPath"
+      />
+
       <div class="mr-widget-section">
         <component :is="componentName" :mr="mr" :service="service" />
         <div class="mr-widget-info">
diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index af5e01eb161a9aa7585f429c864ca65444a36b0b..2035aa1165da8bfbb042aabcafb9a330ca16e04a 100644
--- a/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -56,6 +56,7 @@ export default class MergeRequestStore extends CEMergeRequestStore {
     super.setPaths(data);
 
     this.discoverProjectSecurityPath = data.discover_project_security_path;
+    this.apiStatusChecksPath = data.api_status_checks_path;
 
     // Security scan diff paths
     this.containerScanningComparisonPath = data.container_scanning_comparison_path;
diff --git a/ee/app/presenters/ee/merge_request_presenter.rb b/ee/app/presenters/ee/merge_request_presenter.rb
index 9af6caee12c70d82de98dd8e4202787347ac38a5..75b92b400413fdd17d61e6ddd25890b768f17ff1 100644
--- a/ee/app/presenters/ee/merge_request_presenter.rb
+++ b/ee/app/presenters/ee/merge_request_presenter.rb
@@ -19,6 +19,12 @@ def api_project_approval_settings_path
       end
     end
 
+    def api_status_checks_path
+      if expose_mr_status_checks?
+        expose_path(api_v4_projects_merge_requests_status_checks_path(id: project.id, merge_request_iid: merge_request.iid))
+      end
+    end
+
     def merge_train_when_pipeline_succeeds_docs_path
       help_page_path('ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md', anchor: 'add-a-merge-request-to-a-merge-train')
     end
@@ -62,6 +68,12 @@ def issue_keys
 
     private
 
+    def expose_mr_status_checks?
+      ::Feature.enabled?(:ff_compliance_approval_gates, project, default_enabled: :yaml) &&
+        current_user.present? &&
+        project.external_status_checks.any?
+    end
+
     def expose_mr_approval_path?
       approval_feature_available? && merge_request.iid
     end
diff --git a/ee/app/serializers/ee/merge_request_poll_cached_widget_entity.rb b/ee/app/serializers/ee/merge_request_poll_cached_widget_entity.rb
index e3e696d78a5189244b16543cf2f60560bc534d8c..8b51c23eca8c6d81e926b3095a5e63b8e5dba327 100644
--- a/ee/app/serializers/ee/merge_request_poll_cached_widget_entity.rb
+++ b/ee/app/serializers/ee/merge_request_poll_cached_widget_entity.rb
@@ -17,6 +17,10 @@ module MergeRequestPollCachedWidgetEntity
         presenter(merge_request).missing_security_scan_types
       end
 
+      expose :api_status_checks_path do |merge_request|
+        presenter(merge_request).api_status_checks_path
+      end
+
       expose :jira_associations, if: -> (mr) { mr.project.jira_issue_association_required_to_merge_enabled? } do
         expose :enforced do |merge_request|
           presenter(merge_request).project.prevent_merge_without_jira_issue
diff --git a/ee/spec/features/merge_request/user_sees_status_checks_widget_spec.rb b/ee/spec/features/merge_request/user_sees_status_checks_widget_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e349bbc1444069d72812a984e5660047f983a31d
--- /dev/null
+++ b/ee/spec/features/merge_request/user_sees_status_checks_widget_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > User sees status checks widget', :js do
+  let_it_be(:user) { create(:user) }
+  let_it_be(:project) { create(:project, :repository) }
+  let_it_be(:check1) { create(:external_status_check, project: project) }
+  let_it_be(:check2) { create(:external_status_check, project: project) }
+
+  let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+  let_it_be(:status_check_response) { create(:status_check_response, external_status_check: check1, merge_request: merge_request, sha: merge_request.source_branch_sha) }
+
+  shared_examples 'no status checks widget' do
+    it 'does not show the widget' do
+      expect(page).not_to have_selector('[data-test-id="mr-status-checks"]')
+    end
+  end
+
+  before do
+    stub_licensed_features(compliance_approval_gates: true)
+  end
+
+  context 'user is authorized' do
+    before do
+      project.add_maintainer(user)
+      sign_in(user)
+
+      visit project_merge_request_path(project, merge_request)
+    end
+
+    context 'feature flag is enabled' do
+      before do
+        stub_feature_flags(ff_compliance_approval_gates: true)
+      end
+
+      it 'shows the widget' do
+        expect(page).to have_content('Status checks 1 pending')
+      end
+
+      it 'shows the status check issues', :aggregate_failures do
+        within '[data-test-id="mr-status-checks"]' do
+          click_button 'Expand'
+        end
+
+        [check1, check2].each do |rule|
+          within "[data-testid='mr-status-check-issue-#{rule.id}']" do
+            icon_type = rule.approved?(merge_request, merge_request.source_branch_sha) ? 'success' : 'pending'
+            expect(page).to have_css(".ci-status-icon-#{icon_type}")
+            expect(page).to have_content("#{rule.name}, #{rule.external_url}")
+          end
+        end
+      end
+    end
+
+    context 'feature flag is disabled' do
+      before do
+        stub_feature_flags(ff_compliance_approval_gates: false)
+      end
+
+      it_behaves_like 'no status checks widget'
+    end
+  end
+
+  context 'user is not logged in' do
+    before do
+      visit project_merge_request_path(project, merge_request)
+    end
+
+    it_behaves_like 'no status checks widget'
+  end
+end
diff --git a/ee/spec/frontend/reports/status_checks_report/__snapshots__/status_checks_reports_app_spec.js.snap b/ee/spec/frontend/reports/status_checks_report/__snapshots__/status_checks_reports_app_spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3cea1a397cd9738ba33620f4843e6bd59b070bce
--- /dev/null
+++ b/ee/spec/frontend/reports/status_checks_report/__snapshots__/status_checks_reports_app_spec.js.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Grouped test reports app when mounted matches the default state component snapshot 1`] = `
+"<section class=\\"media-section mr-widget-section mr-report\\" data-test-id=\\"mr-status-checks\\">
+  <div class=\\"media\\">
+    <status-icon-stub status=\\"loading\\" size=\\"24\\" class=\\"align-self-center\\"></status-icon-stub>
+    <div class=\\"media-body d-flex flex-align-self-center align-items-center\\">
+      <div data-testid=\\"report-section-code-text\\" class=\\"js-code-text code-text\\">
+        <div class=\\"gl-display-flex gl-align-items-center\\">
+          <p class=\\"gl-line-height-normal gl-m-0\\">Status checks</p>
+          <!---->
+        </div> <span class=\\"gl-text-gray-500 gl-font-sm\\">When this merge request is updated, a call is sent to the following APIs to confirm their status. <gl-link-stub href=\\"/help/user/project/merge_requests/approvals/index.md#notify-external-services\\" class=\\"gl-font-sm\\">Learn more</gl-link-stub>.</span>
+      </div>
+      <!---->
+    </div>
+  </div>
+  <!---->
+</section>"
+`;
diff --git a/ee/spec/frontend/reports/status_checks_report/mock_data.js b/ee/spec/frontend/reports/status_checks_report/mock_data.js
new file mode 100644
index 0000000000000000000000000000000000000000..490d24ea984e6086a7fb582feaa39e726ef9a926
--- /dev/null
+++ b/ee/spec/frontend/reports/status_checks_report/mock_data.js
@@ -0,0 +1,19 @@
+export const approvedChecks = [
+  {
+    id: 1,
+    name: 'Foo',
+    external_url: 'http://foo',
+    status: 'approved',
+  },
+];
+
+export const pendingChecks = [
+  {
+    id: 2,
+    name: 'Foo Bar',
+    external_url: 'http://foobar',
+    status: 'pending',
+  },
+];
+
+export const mixedChecks = [...approvedChecks, ...pendingChecks];
diff --git a/ee/spec/frontend/reports/status_checks_report/status_checks_reports_app_spec.js b/ee/spec/frontend/reports/status_checks_report/status_checks_reports_app_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb8c81af05b3f52507841d2ff262d215b71ccea1
--- /dev/null
+++ b/ee/spec/frontend/reports/status_checks_report/status_checks_reports_app_spec.js
@@ -0,0 +1,120 @@
+import { GlSprintf } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import StatusChecksReportApp from 'ee/reports/status_checks_report/status_checks_reports_app.vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+import httpStatus from '~/lib/utils/http_status';
+import ReportSection from '~/reports/components/report_section.vue';
+import { status as reportStatus } from '~/reports/constants';
+import { approvedChecks, pendingChecks, mixedChecks } from './mock_data';
+
+jest.mock('~/flash');
+
+describe('Grouped test reports app', () => {
+  let wrapper;
+  let mock;
+
+  const endpoint = 'http://test';
+
+  const findReport = () => wrapper.findComponent(ReportSection);
+
+  const mountComponent = () => {
+    wrapper = shallowMount(StatusChecksReportApp, {
+      propsData: {
+        endpoint,
+      },
+      stubs: {
+        ReportSection,
+        GlSprintf,
+      },
+    });
+  };
+
+  beforeEach(() => {
+    mock = new MockAdapter(axios);
+  });
+
+  afterEach(() => {
+    wrapper.destroy();
+    mock.restore();
+  });
+
+  describe('when mounted', () => {
+    beforeEach(() => {
+      mock.onGet(endpoint).reply(() => new Promise(() => {}));
+      mountComponent();
+    });
+
+    it('configures the report section', () => {
+      expect(findReport().props()).toEqual(
+        expect.objectContaining({
+          status: reportStatus.LOADING,
+          component: 'StatusCheckIssueBody',
+          showReportSectionStatusIcon: false,
+          resolvedIssues: [],
+          neutralIssues: [],
+          hasIssues: false,
+        }),
+      );
+    });
+
+    it('matches the default state component snapshot', () => {
+      expect(wrapper.html()).toMatchSnapshot();
+    });
+  });
+
+  describe('when the status checks have been fetched', () => {
+    const mountWithResponse = (statusCode, data) => {
+      mock.onGet(endpoint).reply(statusCode, data);
+      mountComponent();
+      return waitForPromises();
+    };
+
+    describe.each`
+      state         | response          | text            | resolvedIssues    | neutralIssues
+      ${'approved'} | ${approvedChecks} | ${'All passed'} | ${approvedChecks} | ${[]}
+      ${'pending'}  | ${pendingChecks}  | ${'1 pending'}  | ${[]}             | ${pendingChecks}
+      ${'mixed'}    | ${mixedChecks}    | ${'1 pending'}  | ${approvedChecks} | ${pendingChecks}
+    `('and the status checks are $state', ({ response, text, resolvedIssues, neutralIssues }) => {
+      beforeEach(() => {
+        return mountWithResponse(httpStatus.OK, response);
+      });
+
+      it('sets the report status to success', () => {
+        expect(findReport().props('status')).toBe(reportStatus.SUCCESS);
+      });
+
+      it('sets the issues on the report', () => {
+        expect(findReport().props('hasIssues')).toBe(true);
+        expect(findReport().props('resolvedIssues')).toStrictEqual(resolvedIssues);
+        expect(findReport().props('neutralIssues')).toStrictEqual(neutralIssues);
+      });
+
+      it(`renders '${text}' in the report section`, () => {
+        expect(findReport().text()).toContain(text);
+      });
+    });
+
+    describe('and an error occurred', () => {
+      beforeEach(() => {
+        jest.spyOn(Sentry, 'captureException');
+
+        return mountWithResponse(httpStatus.NOT_FOUND);
+      });
+
+      it('sets the report status to error', () => {
+        expect(findReport().props('status')).toBe(reportStatus.ERROR);
+      });
+
+      it('shows the error text', () => {
+        expect(findReport().text()).toContain('Failed to load status checks.');
+      });
+
+      it('captures the error', () => {
+        expect(Sentry.captureException.mock.calls[0]).toEqual([expect.any(Error)]);
+      });
+    });
+  });
+});
diff --git a/ee/spec/frontend/vue_mr_widget/components/status_check_issue_body_spec.js b/ee/spec/frontend/vue_mr_widget/components/status_check_issue_body_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..cf957a6d322e02f1747ba44098133a372079ca15
--- /dev/null
+++ b/ee/spec/frontend/vue_mr_widget/components/status_check_issue_body_spec.js
@@ -0,0 +1,46 @@
+import { mount } from '@vue/test-utils';
+import component from 'ee/vue_merge_request_widget/components/status_check_issue_body.vue';
+import SummaryRow from '~/reports/components/summary_row.vue';
+import { approvedChecks } from '../../reports/status_checks_report/mock_data';
+
+describe('status check issue body', () => {
+  let wrapper;
+
+  const findSummaryRow = () => wrapper.findComponent(SummaryRow);
+
+  const [defaultStatusCheck] = approvedChecks;
+
+  const createComponent = (statusCheck = {}) => {
+    wrapper = mount(component, {
+      propsData: {
+        issue: {
+          ...defaultStatusCheck,
+          ...statusCheck,
+        },
+      },
+    });
+  };
+
+  beforeEach(() => {
+    createComponent();
+  });
+
+  afterEach(() => {
+    wrapper.destroy();
+    wrapper = null;
+  });
+
+  it('renders the status check name and external URL', () => {
+    expect(wrapper.text()).toBe(`${defaultStatusCheck.name}, ${defaultStatusCheck.external_url}`);
+  });
+
+  it.each`
+    status        | icon
+    ${'approved'} | ${'success'}
+    ${'pending'}  | ${'pending'}
+  `('sets the status-icon to $icon when the check status is $status', ({ status, icon }) => {
+    createComponent({ status });
+
+    expect(findSummaryRow().props('statusIcon')).toBe(icon);
+  });
+});
diff --git a/ee/spec/frontend/vue_mr_widget/ee_mr_widget_options_spec.js b/ee/spec/frontend/vue_mr_widget/ee_mr_widget_options_spec.js
index dbe874b5f11d65a1a8dae4d04d9f134c6263a7cd..cfbe11b10371bbe1e1104e423dfd909c3b6b4133 100644
--- a/ee/spec/frontend/vue_mr_widget/ee_mr_widget_options_spec.js
+++ b/ee/spec/frontend/vue_mr_widget/ee_mr_widget_options_spec.js
@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
 import MockAdapter from 'axios-mock-adapter';
 import Vue, { nextTick } from 'vue';
 import VueApollo from 'vue-apollo';
+import StatusChecksReportsApp from 'ee/reports/status_checks_report/status_checks_reports_app.vue';
 import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
 import MrWidgetOptions from 'ee/vue_merge_request_widget/mr_widget_options.vue';
 // Force Jest to transpile and cache
@@ -98,6 +99,7 @@ describe('ee merge request widget options', () => {
   const findLoadPerformanceWidget = () => wrapper.find('.js-load-performance-widget');
   const findExtendedSecurityWidget = () => wrapper.find('.js-security-widget');
   const findBaseSecurityWidget = () => wrapper.find('[data-testid="security-mr-widget"]');
+  const findStatusChecksReport = () => wrapper.findComponent(StatusChecksReportsApp);
 
   const setBrowserPerformance = (data = {}) => {
     const browserPerformance = { ...DEFAULT_BROWSER_PERFORMANCE, ...data };
@@ -1263,4 +1265,30 @@ describe('ee merge request widget options', () => {
       expect(findExtendedSecurityWidget().exists()).toBe(false);
     });
   });
+
+  describe.each`
+    path             | mergeState          | shouldRender
+    ${'http://test'} | ${'readyToMerge'}   | ${true}
+    ${'http://test'} | ${'nothingToMerge'} | ${false}
+    ${undefined}     | ${'readyToMerge'}   | ${false}
+    ${undefined}     | ${'nothingToMerge'} | ${false}
+  `('status checks widget', ({ path, mergeState, shouldRender }) => {
+    beforeEach(() => {
+      createComponent({
+        propsData: {
+          mrData: {
+            ...mockData,
+            api_status_checks_path: path,
+          },
+        },
+      });
+      wrapper.vm.mr.state = mergeState;
+    });
+
+    it(`${
+      shouldRender ? 'renders' : 'does not render'
+    } when the path is '${path}' and the merge state is '${mergeState}'`, () => {
+      expect(findStatusChecksReport().exists()).toBe(shouldRender);
+    });
+  });
 });
diff --git a/ee/spec/presenters/merge_request_presenter_spec.rb b/ee/spec/presenters/merge_request_presenter_spec.rb
index b49d8e8a1e4443836f99cefdeb0bf54f938fce7e..2705df0713b3fdb8bdef540e039e6cae383e846a 100644
--- a/ee/spec/presenters/merge_request_presenter_spec.rb
+++ b/ee/spec/presenters/merge_request_presenter_spec.rb
@@ -180,4 +180,31 @@
       it { is_expected.to be_empty }
     end
   end
+
+  describe '#api_status_checks_path' do
+    subject { presenter.api_status_checks_path }
+
+    where(:feature_flag_enabled?, :authenticated?, :has_status_checks?, :exposes_path?) do
+      false | false | false | false
+      false | false | true  | false
+      false | true  | true  | false
+      false | true  | false | false
+      true  | false | false | false
+      true  | true  | false | false
+      true  | false | true  | false
+      true  | true  | true  | true
+    end
+
+    with_them do
+      let(:presenter) { described_class.new(merge_request, current_user: authenticated? ? user : nil) }
+      let(:path) { exposes_path? ? expose_path("/api/v4/projects/#{merge_request.project.id}/merge_requests/#{merge_request.iid}/status_checks") : nil }
+
+      before do
+        stub_feature_flags(ff_compliance_approval_gates: feature_flag_enabled?)
+        allow(project.external_status_checks).to receive(:any?).and_return(has_status_checks?)
+      end
+
+      it { is_expected.to eq(path) }
+    end
+  end
 end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d0d24dfeb2e4bc748452ae0affc5f35719b28694..af53385a17290c643221325fac19baddf7450a76 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -31089,12 +31089,18 @@ msgstr ""
 msgid "Status: %{title}"
 msgstr ""
 
+msgid "StatusCheck|%{pending} pending"
+msgstr ""
+
 msgid "StatusCheck|API to check"
 msgstr ""
 
 msgid "StatusCheck|Add status check"
 msgstr ""
 
+msgid "StatusCheck|All passed"
+msgstr ""
+
 msgid "StatusCheck|An error occurred deleting the %{name} status check."
 msgstr ""
 
@@ -31113,6 +31119,9 @@ msgstr ""
 msgid "StatusCheck|External API is already in use by another status check."
 msgstr ""
 
+msgid "StatusCheck|Failed to load status checks."
+msgstr ""
+
 msgid "StatusCheck|Invoke an external API as part of the pipeline process."
 msgstr ""
 
@@ -31140,6 +31149,9 @@ msgstr ""
 msgid "StatusCheck|Update status check"
 msgstr ""
 
+msgid "StatusCheck|When this merge request is updated, a call is sent to the following APIs to confirm their status. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
 msgid "StatusCheck|You are about to remove the %{name} status check."
 msgstr ""