diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index cef3cc7548b4d..a056f49ff58db 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -973,6 +973,16 @@ _BANNED_CPP_FUNCTIONS = (
         r'^base/tracing/.*',
       ),
     ),
+    (
+      r'/\bbase::debug::DumpWithoutCrashingUnthrottled[(][)]',
+      (
+          'base::debug::DumpWithoutCrashingUnthrottled() does not throttle',
+          'dumps and may spam crash reports. Consider if the throttled',
+          'variants suffice instead.',
+      ),
+      False,
+      (),
+    ),
     (
       'RoInitialize',
       (
diff --git a/base/BUILD.gn b/base/BUILD.gn
index f9d11f01bf476..aa7b3441bc9e8 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3089,6 +3089,7 @@ test("base_unittests") {
     "debug/alias_unittest.cc",
     "debug/crash_logging_unittest.cc",
     "debug/debugger_unittest.cc",
+    "debug/dump_without_crashing_unittest.cc",
     "debug/stack_trace_unittest.cc",
     "debug/task_trace_unittest.cc",
     "environment_unittest.cc",
diff --git a/base/debug/dump_without_crashing.cc b/base/debug/dump_without_crashing.cc
index b7ce35349e3c1..b9858dc0a7a33 100644
--- a/base/debug/dump_without_crashing.cc
+++ b/base/debug/dump_without_crashing.cc
@@ -5,22 +5,66 @@
 #include "base/debug/dump_without_crashing.h"
 
 #include "base/check.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
 #include "base/trace_event/base_tracing.h"
 
 namespace {
 
-// Pointer to the function that's called by DumpWithoutCrashing() to dump the
+// Pointer to the function that's called by DumpWithoutCrashing* to dump the
 // process's memory.
 void(CDECL* dump_without_crashing_function_)() = nullptr;
 
+template <typename Map, typename Key>
+bool ShouldDump(Map& map, Key& key, base::TimeDelta time_between_dumps) {
+  static base::NoDestructor<base::Lock> lock;
+  base::AutoLock auto_lock(*lock);
+  base::TimeTicks now = base::TimeTicks::Now();
+  auto [it, inserted] = map.emplace(key, now);
+  if (inserted) {
+    return true;
+  }
+
+  if (now - it->second >= time_between_dumps) {
+    it->second = now;
+    return true;
+  }
+  return false;
+}
+
+// This function takes `location` and `time_between_dumps` as an input
+// and checks if DumpWithoutCrashing() meets the requirements to take the dump
+// or not.
+bool ShouldDumpWithoutCrashWithLocation(const base::Location& location,
+                                        base::TimeDelta time_between_dumps) {
+  static base::NoDestructor<std::map<base::Location, base::TimeTicks>>
+      location_to_timestamp;
+  return ShouldDump(*location_to_timestamp, location, time_between_dumps);
+}
+
+// Pair of `location` and `unique_identifier` creates a unique key and checks
+// if DumpWithoutCrashingWithUniqueId() meets the requirements to take dump or
+// not.
+bool ShouldDumpWithoutCrashWithLocationAndUniqueId(
+    size_t unique_identifier,
+    const base::Location& location,
+    base::TimeDelta time_between_dumps) {
+  static base::NoDestructor<
+      std::map<std::pair<base::Location, size_t>, base::TimeTicks>>
+      location_and_unique_identifier_to_timestamp;
+  std::pair<base::Location, size_t> key(location, unique_identifier);
+  return ShouldDump(*location_and_unique_identifier_to_timestamp, key,
+                    time_between_dumps);
+}
+
 }  // namespace
 
 namespace base {
 
 namespace debug {
 
-bool DumpWithoutCrashing() {
-  TRACE_EVENT0("base", "DumpWithoutCrashing");
+bool DumpWithoutCrashingUnthrottled() {
+  TRACE_EVENT0("base", "DumpWithoutCrashingUnthrottled");
   if (dump_without_crashing_function_) {
     (*dump_without_crashing_function_)();
     return true;
@@ -28,6 +72,38 @@ bool DumpWithoutCrashing() {
   return false;
 }
 
+bool DumpWithoutCrashing(const base::Location& location,
+                         base::TimeDelta time_between_dumps) {
+  TRACE_EVENT0("base", "DumpWithoutCrashing");
+  if (dump_without_crashing_function_ &&
+      ShouldDumpWithoutCrashWithLocation(location, time_between_dumps)) {
+    (*dump_without_crashing_function_)();
+    base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
+                                  DumpWithoutCrashingStatus::kUploaded);
+    return true;
+  }
+  base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
+                                DumpWithoutCrashingStatus::kThrottled);
+  return false;
+}
+
+bool DumpWithoutCrashingWithUniqueId(size_t unique_identifier,
+                                     const base::Location& location,
+                                     base::TimeDelta time_between_dumps) {
+  TRACE_EVENT0("base", "DumpWithoutCrashingWithUniqueId");
+  if (dump_without_crashing_function_ &&
+      ShouldDumpWithoutCrashWithLocationAndUniqueId(unique_identifier, location,
+                                                    time_between_dumps)) {
+    (*dump_without_crashing_function_)();
+    base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
+                                  DumpWithoutCrashingStatus::kUploaded);
+    return true;
+  }
+  base::UmaHistogramEnumeration("Stability.DumpWithoutCrashingStatus",
+                                DumpWithoutCrashingStatus::kThrottled);
+  return false;
+}
+
 void SetDumpWithoutCrashingFunction(void (CDECL *function)()) {
 #if !defined(COMPONENT_BUILD)
   // In component builds, the same base is shared between modules
@@ -39,5 +115,4 @@ void SetDumpWithoutCrashingFunction(void (CDECL *function)()) {
 }
 
 }  // namespace debug
-
 }  // namespace base
diff --git a/base/debug/dump_without_crashing.h b/base/debug/dump_without_crashing.h
index 378686148ec10..86581ff53a518 100644
--- a/base/debug/dump_without_crashing.h
+++ b/base/debug/dump_without_crashing.h
@@ -7,8 +7,18 @@
 
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class DumpWithoutCrashingStatus {
+  kThrottled,
+  kUploaded,
+  kMaxValue = kUploaded
+};
+
 namespace base {
 
 namespace debug {
@@ -28,15 +38,46 @@ namespace debug {
 // This function must not be called with a tail call because that would cause
 // the caller to be omitted from the call stack in the crash dump, and that is
 // confusing and omits what is likely the most important context.
-BASE_EXPORT bool NOT_TAIL_CALLED DumpWithoutCrashing();
+//
+// Note: Calls to this function will not be throttled. To avoid performance
+// problems if this is called many times in quick succession, prefer using one
+// of the below variants.
+BASE_EXPORT bool NOT_TAIL_CALLED DumpWithoutCrashingUnthrottled();
+
+// Handler to silently dump the current process without crashing, that keeps
+// track of call location so some throttling can be applied to avoid very
+// frequent dump captures, which can have side-effects.
+// `location` Location of the file from where the function is called.
+// `time_between_dumps` Time until the next dump should be captured.
+BASE_EXPORT bool NOT_TAIL_CALLED
+DumpWithoutCrashing(const base::Location& location = base::Location::Current(),
+                    base::TimeDelta time_between_dumps = base::Minutes(5));
+
+// Handler to silently dump the current process without crashing that takes a
+// location and unique id to keep a track and apply throttling. This function
+// should be used when a domain wishes to capture dumps for multiple, unique
+// reasons from a single location. An example would be unique bad mojo
+// messages, or a value outside an expected range and the value should be
+// considered interesting in the dump. The goal is to allow a single call to
+// generate multiple dumps as needed and throttle future instances of the same
+// identifiers for a short period of time.
+// `unique_identifier` Hash to uniquely identify the function call. Consider
+// using base::FastHash to generate the hash.
+// `location` Location of the file from where the function is called.
+// `time_between_dumps` Time until the next dump should be captured.
+// Note: The unique identifier, as of now, is not comparable across different
+// runs or builds and is stable only for a process lifetime.
+BASE_EXPORT bool NOT_TAIL_CALLED DumpWithoutCrashingWithUniqueId(
+    size_t unique_identifier,
+    const base::Location& location = base::Location::Current(),
+    base::TimeDelta time_between_dumps = base::Minutes(5));
 
 // Sets a function that'll be invoked to dump the current process when
-// DumpWithoutCrashing() is called. May be called with null to remove a
+// DumpWithoutCrashing* is called. May be called with null to remove a
 // previously set function.
 BASE_EXPORT void SetDumpWithoutCrashingFunction(void (CDECL *function)());
 
 }  // namespace debug
-
 }  // namespace base
 
 #endif  // BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
diff --git a/base/debug/dump_without_crashing_unittest.cc b/base/debug/dump_without_crashing_unittest.cc
new file mode 100644
index 0000000000000..044ee9920b461
--- /dev/null
+++ b/base/debug/dump_without_crashing_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/dump_without_crashing.h"
+
+#include "base/hash/hash.h"
+#include "base/location.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_mock_clock_override.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+class DumpWithoutCrashingTest : public testing::Test {
+ public:
+  static void DummyDumpWithoutCrashing() { number_of_dump_calls_++; }
+
+  static int number_of_dump_calls() { return number_of_dump_calls_; }
+
+ protected:
+  void SetUp() override {
+    SetDumpWithoutCrashingFunction(
+        &DumpWithoutCrashingTest::DummyDumpWithoutCrashing);
+    number_of_dump_calls_ = 0;
+  }
+
+  void TearDown() override { SetDumpWithoutCrashingFunction(nullptr); }
+
+  // Set override.
+  ScopedMockClockOverride clock_;
+
+  const base::HistogramTester histogram_tester_;
+  const base::Location location1_ = FROM_HERE;
+  const base::Location location2_ = FROM_HERE;
+  const size_t unique_identifier1_ =
+      base::FastHash("DumpWithoutCrashingFirstTest");
+  const size_t unique_identifier2_ =
+      base::FastHash("DumpWithoutCrashingSecondTest");
+
+ private:
+  static int number_of_dump_calls_;
+};
+
+int DumpWithoutCrashingTest::number_of_dump_calls_ = 0;
+
+// TODO(crbug.com/1295506) This test is flaky on iOS.
+#if BUILDFLAG(IS_IOS)
+#define MAYBE_DumpWithoutCrashingWithLocation \
+  DISABLED_DumpWithoutCrashingWithLocation
+#else
+#define MAYBE_DumpWithoutCrashingWithLocation DumpWithoutCrashingWithLocation
+#endif
+TEST_F(DumpWithoutCrashingTest, MAYBE_DumpWithoutCrashingWithLocation) {
+  EXPECT_EQ(0, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 0);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 0);
+
+  // The first call to DumpWithoutCrashing will always capture the dump and
+  // will return true
+  EXPECT_TRUE(DumpWithoutCrashing(location1_, base::Seconds(1)));
+  EXPECT_EQ(1, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 0);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 1);
+
+  // If DumpWithoutCrashing is called within 1 second, expected result is false.
+  EXPECT_FALSE(DumpWithoutCrashing(location1_, base::Seconds(1)));
+  EXPECT_EQ(1, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  // For testing, the time for capturing dump again is 1 second and if the
+  // function is called after 1 second, it will return true.
+  clock_.Advance(Seconds(2));
+  EXPECT_TRUE(DumpWithoutCrashing(location1_, base::Seconds(1)));
+  EXPECT_EQ(2, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 1);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 2);
+
+  EXPECT_TRUE(DumpWithoutCrashing(location2_, base::Seconds(1)));
+  EXPECT_EQ(3, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  EXPECT_FALSE(DumpWithoutCrashing(location2_, base::Seconds(1)));
+  EXPECT_EQ(3, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 2);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 3);
+}
+
+// TODO(crbug.com/1295506) This test is flaky on iOS.
+#if BUILDFLAG(IS_IOS)
+#define MAYBE_DumpWithoutCrashingWithLocationAndUniqueId \
+  DISABLED_DumpWithoutCrashingWithLocationAndUniqueId
+#else
+#define MAYBE_DumpWithoutCrashingWithLocationAndUniqueId \
+  DumpWithoutCrashingWithLocationAndUniqueId
+#endif
+TEST_F(DumpWithoutCrashingTest,
+       MAYBE_DumpWithoutCrashingWithLocationAndUniqueId) {
+  EXPECT_EQ(0, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 0);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 0);
+
+  // Test the variant of DumpWithoutCrashingWithUniqueId where the function
+  // takes a location and unique id.
+  EXPECT_TRUE(DumpWithoutCrashingWithUniqueId(unique_identifier1_, location1_,
+                                              base::Seconds(1)));
+  EXPECT_EQ(1, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 0);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 1);
+
+  // If DumpWithoutCrashingWithUniqueId called within 1 second, expected result
+  // is false.
+  EXPECT_FALSE(DumpWithoutCrashingWithUniqueId(unique_identifier1_, location1_,
+                                               base::Seconds(1)));
+  EXPECT_EQ(1, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  // For testing, the time for capturing dump again is 1 second and if the
+  // function is called after 1 second, it will return true.
+  clock_.Advance(Seconds(2));
+
+  EXPECT_TRUE(DumpWithoutCrashingWithUniqueId(unique_identifier1_, location1_,
+                                              base::Seconds(1)));
+  EXPECT_EQ(2, DumpWithoutCrashingTest::number_of_dump_calls());
+
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 1);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 2);
+
+  EXPECT_TRUE(DumpWithoutCrashingWithUniqueId(unique_identifier2_, location2_,
+                                              base::Seconds(1)));
+  EXPECT_EQ(3, DumpWithoutCrashingTest::number_of_dump_calls());
+  EXPECT_FALSE(DumpWithoutCrashingWithUniqueId(unique_identifier2_, location2_,
+                                               base::Seconds(1)));
+  EXPECT_EQ(3, DumpWithoutCrashingTest::number_of_dump_calls());
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kThrottled, 2);
+  histogram_tester_.ExpectBucketCount("Stability.DumpWithoutCrashingStatus",
+                                      DumpWithoutCrashingStatus::kUploaded, 3);
+}
+
+}  // namespace debug
+}  // namespace base
\ No newline at end of file
diff --git a/base/location.h b/base/location.h
index 446114764cf0b..c279be2915641 100644
--- a/base/location.h
+++ b/base/location.h
@@ -55,6 +55,12 @@ class BASE_EXPORT Location {
     return program_counter_ == other.program_counter_;
   }
 
+  // Comparator is necessary to use location object within an ordered container
+  // type (eg. std::map).
+  bool operator<(const Location& other) const {
+    return program_counter_ < other.program_counter_;
+  }
+
   // Returns true if there is source code location info. If this is false,
   // the Location object only contains a program counter or is
   // default-initialized (the program counter is also null).
diff --git a/chrome/browser/ash/printing/printers_sync_bridge_unittest.cc b/chrome/browser/ash/printing/printers_sync_bridge_unittest.cc
index df8a57dfc13b3..7993206063bfc 100644
--- a/chrome/browser/ash/printing/printers_sync_bridge_unittest.cc
+++ b/chrome/browser/ash/printing/printers_sync_bridge_unittest.cc
@@ -28,7 +28,8 @@ class PrintersSyncBridgeTest : public testing::Test {
     bridge_ = std::make_unique<PrintersSyncBridge>(
         syncer::ModelTypeStoreTestUtil::FactoryForInMemoryStoreForTest(),
         base::BindRepeating(
-            base::IgnoreResult(&base::debug::DumpWithoutCrashing)));
+            base::IgnoreResult(&base::debug::DumpWithoutCrashing), FROM_HERE,
+            base::Minutes(5)));
   }
 
  protected:
diff --git a/chrome/browser/ash/printing/synced_printers_manager_unittest.cc b/chrome/browser/ash/printing/synced_printers_manager_unittest.cc
index b4a8fde17fea4..06d6da86fa65c 100644
--- a/chrome/browser/ash/printing/synced_printers_manager_unittest.cc
+++ b/chrome/browser/ash/printing/synced_printers_manager_unittest.cc
@@ -60,12 +60,13 @@ class LoggingObserver : public SyncedPrintersManager::Observer {
 class SyncedPrintersManagerTest : public testing::Test {
  protected:
   SyncedPrintersManagerTest()
-      : manager_(SyncedPrintersManager::Create(
-            std::make_unique<PrintersSyncBridge>(
-                syncer::ModelTypeStoreTestUtil::
-                    FactoryForInMemoryStoreForTest(),
-                base::BindRepeating(
-                    base::IgnoreResult(&base::debug::DumpWithoutCrashing))))) {
+      : manager_(SyncedPrintersManager::Create(std::make_unique<
+                                               PrintersSyncBridge>(
+            syncer::ModelTypeStoreTestUtil::FactoryForInMemoryStoreForTest(),
+            base::BindRepeating(
+                base::IgnoreResult(&base::debug::DumpWithoutCrashing),
+                FROM_HERE,
+                base::Minutes(5))))) {
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 183cf9093d4f1..e6adea2d6f887 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25267,6 +25267,11 @@ Called by update_document_policy_enum.py.-->
   <int value="3" label="Success from Breakpad"/>
 </enum>
 
+<enum name="DumpWithoutCrashingStatus">
+  <int value="0" label="Dump throttled"/>
+  <int value="1" label="Dump uploaded"/>
+</enum>
+
 <enum name="DuplicateBookmarkEntityOnRemoteUpdateCondition">
   <int value="0" label="Entity with server ID is a tombstone"/>
   <int value="1" label="Only entity with temporary ID is a tombstone"/>
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml
index 6293bf65cebca..587d2af6b81d9 100644
--- a/tools/metrics/histograms/metadata/stability/histograms.xml
+++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -292,6 +292,20 @@ chromium-metrics-reviews@google.com.
   </summary>
 </histogram>
 
+<histogram name="Stability.DumpWithoutCrashingStatus"
+    enum="DumpWithoutCrashingStatus" expires_after="never">
+<!-- expires-never: Used for monitoring the throttling frequency of
+     DumpWithoutCrashing. -->
+
+  <owner>dcheng@chromium.org</owner>
+  <owner>wfh@chromium.org</owner>
+  <owner>adkushwa@microsoft.com</owner>
+  <summary>
+    Keeps a count of number of times uploading the dump was throttled when
+    calling DumpWithoutCrashing.
+  </summary>
+</histogram>
+
 <histogram name="Stability.Experimental.PageLoads" enum="StabilityPageLoadType"
     expires_after="2022-06-12">
   <owner>fdoray@chromium.org</owner>