diff --git a/example/browser/index.html b/example/browser/index.html
index 83c80388..d69681d5 100644
--- a/example/browser/index.html
+++ b/example/browser/index.html
@@ -15,6 +15,7 @@
Error Submission
+
Log Submission
diff --git a/example/browser/index.js b/example/browser/index.js
index b772df3b..73a66904 100644
--- a/example/browser/index.js
+++ b/example/browser/index.js
@@ -53,6 +53,15 @@ document.addEventListener("DOMContentLoaded", () => {
await builder.submit();
});
+ document
+ .querySelector("#throw-browser-extension-error")
+ .addEventListener("click", () => {
+ const error = new Error("A Browser Extension Error");
+ error.stack = "at () in chrome-extension://bmagokdooijbeehmkpknfglimnifench/firebug-lite.js:line 9716:col 29"
+
+ throw error;
+ });
+
document
.querySelector("#throw-custom-error")
.addEventListener("click", () => {
diff --git a/packages/browser/src/BrowserExceptionlessClient.ts b/packages/browser/src/BrowserExceptionlessClient.ts
index e9199b74..d959882f 100644
--- a/packages/browser/src/BrowserExceptionlessClient.ts
+++ b/packages/browser/src/BrowserExceptionlessClient.ts
@@ -2,6 +2,7 @@ import { Configuration, ExceptionlessClient, SimpleErrorPlugin } from "@exceptio
import { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js";
import { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
+import { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js";
import { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
import { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js";
import { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js";
@@ -13,6 +14,7 @@ export class BrowserExceptionlessClient extends ExceptionlessClient {
config.useLocalStorage();
config.addPlugin(new BrowserGlobalHandlerPlugin());
+ config.addPlugin(new BrowserIgnoreExtensionErrorsPlugin());
config.addPlugin(new BrowserLifeCyclePlugin());
config.addPlugin(new BrowserModuleInfoPlugin());
config.addPlugin(new BrowserRequestInfoPlugin());
diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts
index ae31746a..d9e11b46 100644
--- a/packages/browser/src/index.ts
+++ b/packages/browser/src/index.ts
@@ -1,5 +1,6 @@
export { BrowserErrorPlugin } from "./plugins/BrowserErrorPlugin.js"
export { BrowserGlobalHandlerPlugin } from "./plugins/BrowserGlobalHandlerPlugin.js";
+export { BrowserIgnoreExtensionErrorsPlugin } from "./plugins/BrowserIgnoreExtensionErrorsPlugin.js";
export { BrowserLifeCyclePlugin } from "./plugins/BrowserLifeCyclePlugin.js";
export { BrowserModuleInfoPlugin } from "./plugins/BrowserModuleInfoPlugin.js";
export { BrowserRequestInfoPlugin } from "./plugins/BrowserRequestInfoPlugin.js";
diff --git a/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts b/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts
index be9d06ab..cbb2d44c 100644
--- a/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts
+++ b/packages/browser/src/plugins/BrowserGlobalHandlerPlugin.ts
@@ -46,7 +46,7 @@ export class BrowserGlobalHandlerPlugin implements IEventPlugin {
void this._client?.submitNotFound(settings.url);
} else if (xhr.status !== 401) {
// TODO: Handle async
- void this._client?.createUnhandledException(toError(error) as Error, "JQuery.ajaxError")
+ void this._client?.createUnhandledException(toError(error), "JQuery.ajaxError")
.setSource(settings.url)
.setProperty("status", xhr.status)
.setProperty("request", settings.data)
diff --git a/packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts b/packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts
new file mode 100644
index 00000000..c11a4c68
--- /dev/null
+++ b/packages/browser/src/plugins/BrowserIgnoreExtensionErrorsPlugin.ts
@@ -0,0 +1,20 @@
+import {
+ EventPluginContext,
+ IEventPlugin
+} from "@exceptionless/core";
+
+export class BrowserIgnoreExtensionErrorsPlugin implements IEventPlugin {
+ public priority = 15;
+ public name = "BrowserIgnoreExtensionErrorsPlugin";
+
+ public async run(context: EventPluginContext): Promise {
+ const exception = context.eventContext.getException();
+ if (exception?.stack && exception.stack.includes("-extension://")) {
+ // Handles all extensions like chrome-extension://, moz-extension://, ms-browser-extension://, safari-extension://
+ context.log.info("Ignoring event with error stack containing browser extension");
+ context.cancelled = true;
+ }
+
+ return Promise.resolve();
+ }
+}
diff --git a/packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts b/packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts
new file mode 100644
index 00000000..ba366b38
--- /dev/null
+++ b/packages/browser/test/plugins/BrowserIgnoreExtensionErrorsPlugin.test.ts
@@ -0,0 +1,50 @@
+import { describe, test } from "@jest/globals";
+import { expect } from "expect";
+
+import {
+ EventContext,
+ EventPluginContext,
+ ExceptionlessClient
+} from "@exceptionless/core";
+
+import { BrowserIgnoreExtensionErrorsPlugin } from "../../src/plugins/BrowserIgnoreExtensionErrorsPlugin.js";
+
+describe("BrowserIgnoreExtensionErrorsPlugin", () => {
+ let client: ExceptionlessClient;
+ let plugin: BrowserIgnoreExtensionErrorsPlugin;
+
+ beforeEach(() => {
+ client = new ExceptionlessClient();
+ plugin = new BrowserIgnoreExtensionErrorsPlugin();
+ });
+
+ const run = async (stackTrace?: string | undefined): Promise => {
+ const error = new Error("Test");
+ if (stackTrace) {
+ error.stack = stackTrace;
+ }
+
+ const eventContext = new EventContext();
+ eventContext.setException(error);
+
+ const context = new EventPluginContext(client, { type: "error" }, eventContext);
+
+ await plugin.run(context);
+ return context;
+ }
+
+ test("should not cancel empty stack trace", async () => {
+ const context = await run();
+ expect(context.cancelled).toBe(false);
+ });
+
+ test("should not cancel normal stack trace", async () => {
+ const context = await run("at t() in https://test/Content/js/Exceptionless/exceptionless.min.js:line 1:col 260");
+ expect(context.cancelled).toBe(false);
+ });
+
+ test("should cancel browser extension stack trace", async () => {
+ const context = await run("at Object.initialize() in chrome-extension://bmagokdooijbeehmkpknfglimnifench/firebug-lite.js:line 6289:col 29");
+ expect(context.cancelled).toBe(true);
+ });
+});