diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts
index d034330b6283..804db7608dee 100644
--- a/packages/browser/src/index.ts
+++ b/packages/browser/src/index.ts
@@ -56,6 +56,7 @@ export {
   moduleMetadataIntegration,
   zodErrorsIntegration,
   thirdPartyErrorFilterIntegration,
+  _experimentalDomainBasedErrorsFilterIntegration,
 } from '@sentry/core';
 export type { Span } from '@sentry/core';
 export { makeBrowserOfflineTransport } from './transports/offline';
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 35bfc35bc603..9aeca897ea19 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -108,6 +108,7 @@ export { extraErrorDataIntegration } from './integrations/extraerrordata';
 export { rewriteFramesIntegration } from './integrations/rewriteframes';
 export { zodErrorsIntegration } from './integrations/zoderrors';
 export { thirdPartyErrorFilterIntegration } from './integrations/third-party-errors-filter';
+export { _experimentalDomainBasedErrorsFilterIntegration } from './integrations/domain-based-errors-filter';
 export { profiler } from './profiling';
 export { instrumentFetchRequest } from './fetch';
 export { trpcMiddleware } from './trpc';
diff --git a/packages/core/src/integrations/domain-based-errors-filter.ts b/packages/core/src/integrations/domain-based-errors-filter.ts
new file mode 100644
index 000000000000..c0290ab489bb
--- /dev/null
+++ b/packages/core/src/integrations/domain-based-errors-filter.ts
@@ -0,0 +1,160 @@
+import { defineIntegration } from '../integration';
+import type { StackFrame } from '../types-hoist';
+import { GLOBAL_OBJ, isErrorEvent } from '../utils-hoist';
+import { getFramesFromEvent } from '../utils-hoist/stacktrace';
+
+type DomainBasedErrorsFilterOptions = {
+  /**
+   * List of domains that are considered "first-party" (your application domains).
+   * Errors from these domains will not be filtered.
+   * Example: ['myapp.com', 'cdn.myapp.com']
+   */
+  appDomains: string[];
+
+  /**
+   * List of third-party domains that should be allowed despite not being in appDomains.
+   * Errors from these domains will not be filtered.
+   *
+   */
+  allowlistedDomains?: string[];
+
+  /**
+   * Defines how the integration should behave with third-party errors.
+   *
+   * - `drop-error-if-contains-third-party-frames`: Drop error events that contain at least one third-party stack frame.
+   * - `drop-error-if-exclusively-contains-third-party-frames`: Drop error events that exclusively contain third-party stack frames.
+   * - `apply-tag-if-contains-third-party-frames`: Keep all error events, but apply a `third_party_domain: true` tag in case the error contains at least one third-party stack frame.
+   * - `apply-tag-if-exclusively-contains-third-party-frames`: Keep all error events, but apply a `third_party_domain: true` tag in case the error exclusively contains third-party stack frames.
+   */
+  behaviour:
+    | 'drop-error-if-contains-third-party-frames'
+    | 'drop-error-if-exclusively-contains-third-party-frames'
+    | 'apply-tag-if-contains-third-party-frames'
+    | 'apply-tag-if-exclusively-contains-third-party-frames';
+
+  /**
+   * Whether to apply the `is_external` flag to stack frames from third-party domains.
+   *
+   * Default: `false`
+   */
+  applyIsExternalFrameFlag?: boolean;
+};
+
+export const _experimentalDomainBasedErrorsFilterIntegration = defineIntegration(
+  (options: DomainBasedErrorsFilterOptions) => {
+    const isRunningOnLocalhost = (): boolean => {
+      // Check if we're in a browser environment
+      const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;
+      if (WINDOW?.location?.href) {
+        const href = WINDOW.location.href;
+
+        // todo: add a more advanced check
+        if (href.includes('://localhost:') || href.includes('://127.0.0.1')) {
+          return true;
+        }
+      }
+
+      return false;
+    };
+
+    const isLocalhost = isRunningOnLocalhost();
+
+    return {
+      name: '_experimentalDomainBasedErrorsFilter',
+      processEvent(event) {
+        // skip for non error events and locally running apps
+        if (isLocalhost || !isErrorEvent(event)) {
+          return event;
+        }
+
+        const frames = getFramesFromEvent(event);
+        if (!frames || frames.length === 0) {
+          return event;
+        }
+
+        // collect firstParty domains
+        // todo: get a sensible default, maybe href + subdomains
+        const appDomains = options.appDomains || [];
+
+        // todo: merge this list with clientOptions.allowUrls
+        const allowlistedDomains = options.allowlistedDomains || [];
+
+        let hasThirdPartyFrames = false;
+        let allFramesAreThirdParty = true;
+
+        frames.forEach(frame => {
+          // todo: check abs_path or filename here?
+          if (frame.abs_path) {
+            try {
+              const url = new URL(frame.abs_path);
+              const domain = url.hostname;
+
+              const isExternal = isThirdPartyDomain(domain, appDomains, allowlistedDomains);
+
+              // Add is_external flag to the frame
+              if (options.applyIsExternalFrameFlag) {
+                (frame as StackFrame & { is_external?: boolean }).is_external = isExternal;
+              }
+
+              if (isExternal) {
+                hasThirdPartyFrames = true;
+              } else {
+                allFramesAreThirdParty = false;
+              }
+            } catch (e) {
+              // can't get URL
+              allFramesAreThirdParty = false;
+            }
+          } else {
+            // No abs path
+            allFramesAreThirdParty = false;
+          }
+        });
+
+        let applyTag = false;
+
+        if (hasThirdPartyFrames) {
+          if (options.behaviour === 'drop-error-if-contains-third-party-frames') {
+            return null;
+          }
+          if (options.behaviour === 'apply-tag-if-contains-third-party-frames') {
+            applyTag = true;
+          }
+        }
+
+        if (allFramesAreThirdParty) {
+          if (options.behaviour === 'drop-error-if-exclusively-contains-third-party-frames') {
+            return null;
+          }
+          if (options.behaviour === 'apply-tag-if-exclusively-contains-third-party-frames') {
+            applyTag = true;
+          }
+        }
+
+        if (applyTag) {
+          event.tags = {
+            ...event.tags,
+            third_party_code: true,
+          };
+        }
+
+        return event;
+      },
+    };
+  },
+);
+
+const isThirdPartyDomain = (domain: string, appDomains: string[], allowlistedDomains: string[]): boolean => {
+  const isAppDomain = appDomains.some(appDomain => domain === appDomain || domain.endsWith(`.${appDomain}`));
+
+  if (isAppDomain) {
+    return false;
+  }
+
+  // todo: extend this check also check for regexes
+  const isAllowlisted = allowlistedDomains?.some(
+    allowedDomain => domain === allowedDomain || domain.endsWith(`.${allowedDomain}`),
+  );
+
+  return !isAllowlisted;
+};
diff --git a/packages/core/src/integrations/eventFilters.ts b/packages/core/src/integrations/eventFilters.ts
index fbf9475feca2..43462fd5c30c 100644
--- a/packages/core/src/integrations/eventFilters.ts
+++ b/packages/core/src/integrations/eventFilters.ts
@@ -148,6 +148,7 @@ function _shouldDropEvent(event: Event, options: Partial<EventFiltersOptions>):
       );
     return true;
   }
+
   return false;
 }