diff --git a/docs/platforms/javascript/common/best-practices/browser-extensions.mdx b/docs/platforms/javascript/common/best-practices/browser-extensions.mdx
new file mode 100644
index 00000000000000..64bab39b8c1b8f
--- /dev/null
+++ b/docs/platforms/javascript/common/best-practices/browser-extensions.mdx
@@ -0,0 +1,51 @@
+---
+title: Browser Extensions
+sidebar_order: 50
+description: Learn how to use Sentry in shared environments (for example in browser extensions or VSCode extensions).
+keywords:
+ [
+ "BrowserClient",
+ "NodeClient",
+ "shared environment",
+ "browser extension",
+ "VSCode extension"
+ ]
+---
+
+When setting up Sentry in a shared environment where multiple Sentry instances may run, for example, in a browser extension or similar, you should **not use `Sentry.init()`**, as this will pollute the global state. If your browser extension uses `Sentry.init()`, and the website the extension is running on also uses Sentry, the extension may send events to the website's Sentry project, or vice versa.
+
+For such scenarios, you have to set up a client manually as seen in the example below.
+In addition, you should also avoid adding any integrations that use global state, like `Breadcrumbs` or `TryCatch`.
+As a rule of thumb, it's best to avoid using any integrations and to rely on manual capture of errors only in such scenarios.
+
+
+
+```javascript
+import {
+ BrowserClient,
+ defaultStackParser,
+ defaultIntegrations,
+ makeFetchTransport,
+ Scope,
+} from "@sentry/browser";
+
+const client = new BrowserClient({
+ dsn: "___PUBLIC_DSN___",
+ transport: makeFetchTransport,
+ stackParser: defaultStackParser,
+ integrations: defaultIntegrations,
+});
+
+const scope = new Scope();
+scope.setClient(client);
+
+client.init() // initializing has to be done after setting the client on the scope
+
+// You can capture exceptions manually for this client like this:
+scope.captureException(new Error("example"));
+
+```
+
+If you notice that Sentry is not capturing error events from the browser extension,
+try disabling the Browser extension errors option in the Inbound Filters of your Sentry configuration.
+Read more about Inbound Filters in the product documentation under [Inbound filters](/product/data-management-settings/filtering/#inbound-data-filters).
diff --git a/docs/platforms/javascript/common/best-practices/index.mdx b/docs/platforms/javascript/common/best-practices/index.mdx
new file mode 100644
index 00000000000000..3d9f94b089daf3
--- /dev/null
+++ b/docs/platforms/javascript/common/best-practices/index.mdx
@@ -0,0 +1,7 @@
+---
+title: Best Practices
+description: "Learn how to set up Sentry in specific scenarios with those best practice guides"
+sidebar_order: 3
+---
+
+
diff --git a/docs/platforms/javascript/common/configuration/micro-frontend-support.mdx b/docs/platforms/javascript/common/best-practices/micro-frontends.mdx
similarity index 98%
rename from docs/platforms/javascript/common/configuration/micro-frontend-support.mdx
rename to docs/platforms/javascript/common/best-practices/micro-frontends.mdx
index b36662d4f09bbb..c761996822e717 100644
--- a/docs/platforms/javascript/common/configuration/micro-frontend-support.mdx
+++ b/docs/platforms/javascript/common/best-practices/micro-frontends.mdx
@@ -1,5 +1,5 @@
---
-title: Micro Frontend Support
+title: Micro Frontends
sidebar_order: 200
description: Learn how to identify the source of errors and route events to different Sentry projects when using micro frontend or module federation.
keywords:
@@ -14,7 +14,7 @@ keywords:
If your frontend includes JavaScript bundles from multiple sources with
different release cycles, you may want to identify these or route events to specific projects. This is especially useful if you've set up [module federation](https://module-federation.github.io/) or a similar frontend architecture.
-Below we offer two approaches.
+Below we offer two approaches.
In all cases `Sentry.init()` must never be called more than once, doing so will result in undefined behavior.
@@ -60,7 +60,7 @@ module.exports = {
};
```
-Once metadata has been injected into modules, the `moduleMetadataIntegration`
+Once metadata has been injected into modules, the `moduleMetadataIntegration`
can be used to look up that metadata and attach it to stack frames with
matching file names. This metadata is then available in the `beforeSend` callback
as the `module_metadata` property on each `StackFrame`. This can be used to identify
diff --git a/docs/platforms/javascript/common/best-practices/multiple-sentry-instances.mdx b/docs/platforms/javascript/common/best-practices/multiple-sentry-instances.mdx
new file mode 100644
index 00000000000000..1b8be390b56845
--- /dev/null
+++ b/docs/platforms/javascript/common/best-practices/multiple-sentry-instances.mdx
@@ -0,0 +1,114 @@
+---
+title: Multiple Sentry Instances
+sidebar_order: 300
+description: Learn how to manage several Sentry instances by creating your own clients.
+keywords:
+ [
+ "multiple instances",
+ "multiple clients",
+ "BrowserClient",
+ "NodeClient",
+ "monorepo"
+ ]
+---
+
+
+
+Creating multiple Sentry clients is not recommended in general, as it can lead to unexpected behavior. If you are using Micro Frontends or similar, multiplexing might be a better solution that using multiple clients. Check out [Micro Frontends](/platforms/javascript/best-practices/micro-frontends) in the Best Practices for more information.
+
+ Note>
+
+To be able to manage several Sentry instances without any conflicts between them you need to create your own `Client`.
+This also helps to prevent tracking of any parent application errors in case your application is integrated
+inside of it. In this example we use `BrowserClient` from `@sentry/browser` but it's also applicable to `NodeClient` from `@sentry/node`.
+
+
+
+```javascript
+import {
+ BrowserClient,
+ defaultStackParser,
+ defaultIntegrations,
+ makeFetchTransport,
+ Scope,
+} from "@sentry/browser";
+
+const client = new BrowserClient({
+ dsn: "___PUBLIC_DSN___",
+ transport: makeFetchTransport,
+ stackParser: defaultStackParser,
+ integrations: defaultIntegrations,
+});
+
+const scope = new Scope();
+scope.setClient(client);
+
+client.init() // initializing has to be done after setting the client on the scope
+
+// You can capture exceptions manually for this client like this:
+scope.captureException(new Error("example"));
+```
+
+You can now customize the scope to your liking, without affecting other hubs/clients.
+
+### Dealing with Integrations
+
+Integrations are setup on the `Client`, if you need to deal with multiple clients and hubs you have to make sure to also do the integration handling correctly.
+
+We do not recommend doing this if you are using Sentry in a browser extension or in similar scenarios.
+If you can't avoid using global integrations (e.g. in a micro frontend application), here is a working example of how to use multiple clients with multiple scopes running global integrations.
+
+
+
+```javascript
+import * as Sentry from "@sentry/browser";
+
+// Very happy integration that'll prepend and append very happy stick figure to the message
+function happyIntegration() {
+ return {
+ name: 'Happy',
+ setupOnce() {
+ Sentry.addGlobalEventProcessor((event) => {
+ const self = Sentry.getClient().getIntegration(HappyIntegration);
+ // Run the integration ONLY when it was installed on the current Hub
+ if (self) {
+ event.message = `\\o/ ${event.message} \\o/`;
+ }
+ return event;
+ });
+ }
+ }
+}
+
+const client1 = new Sentry.BrowserClient({
+ dsn: "___PUBLIC_DSN___",
+ transport: Sentry.makeFetchTransport,
+ stackParser: Sentry.defaultStackParser,
+ integrations: [...Sentry.defaultIntegrations, happyIntegration()],
+ beforeSend(event) {
+ console.log("client 1", event);
+ return null; // Returning `null` prevents the event from being sent
+ },
+});
+const scope1 = new Sentry.Scope(client1);
+
+const client2 = new Sentry.BrowserClient({
+ dsn: "___PUBLIC_DSN___", // Can be a different DSN
+ transport: Sentry.makeFetchTransport,
+ stackParser: Sentry.defaultStackParser,
+ integrations: [...Sentry.defaultIntegrations, happyIntegration()],
+ beforeSend(event) {
+ console.log("client 2", event);
+ return null; // Returning `null` prevents the event from being sent
+ },
+});
+const scope2 = new Sentry.Scope(client2);
+
+scope1.captureMessage("a");
+scope1.setTag("a", "b");
+
+scope2.captureMessage("x");
+scope2.setTag("c", "d");
+```
+
+
diff --git a/docs/platforms/javascript/common/configuration/sentry-testkit/index.mdx b/docs/platforms/javascript/common/best-practices/sentry-testkit.mdx
similarity index 100%
rename from docs/platforms/javascript/common/configuration/sentry-testkit/index.mdx
rename to docs/platforms/javascript/common/best-practices/sentry-testkit.mdx
diff --git a/docs/platforms/javascript/common/configuration/webworkers/index.mdx b/docs/platforms/javascript/common/best-practices/web-workers.mdx
similarity index 100%
rename from docs/platforms/javascript/common/configuration/webworkers/index.mdx
rename to docs/platforms/javascript/common/best-practices/web-workers.mdx
diff --git a/docs/platforms/javascript/common/troubleshooting/index.mdx b/docs/platforms/javascript/common/troubleshooting/index.mdx
index 9d495b316c5d4f..72768ee6c0100e 100644
--- a/docs/platforms/javascript/common/troubleshooting/index.mdx
+++ b/docs/platforms/javascript/common/troubleshooting/index.mdx
@@ -284,115 +284,6 @@ If you would like to copy and paste the snippet directly, here it is minified:
```
-## Using a Client directly
-
-To be able to manage several Sentry instances without any conflicts between them you need to create your own `Client`.
-This also helps to prevent tracking of any parent application errors in case your application is integrated
-inside of it. In this example we use `@sentry/browser` but it's also applicable to `@sentry/node`.
-
-
-
-```javascript
-import {
- BrowserClient,
- defaultStackParser,
- defaultIntegrations,
- makeFetchTransport,
- Scope,
-} from "@sentry/browser";
-
-const client = new BrowserClient({
- dsn: "___PUBLIC_DSN___",
- transport: makeFetchTransport,
- stackParser: defaultStackParser,
- integrations: defaultIntegrations,
-});
-
-const scope = new Scope();
-scope.setClient(client);
-
-client.init() // initializing has to be done after setting the client on the scope
-
-// You can capture exceptions manually for this client like this:
-scope.captureException(new Error("example"));
-```
-
-You can now customize the hub to your liking, without affecting other hubs/clients.
-
-### Setting up Sentry in shared environments (e.g. Browser Extensions)
-
-When setting up Sentry in a shared environment where multiple Sentry instances may run, for example, in a browser extension or similar, you should **not use `Sentry.init()`**, as this will pollute the global state. If your browser extension uses `Sentry.init()`, and the website the extension is running on also uses Sentry, the extension may send events to the website's Sentry project, or vice versa.
-
-For such scenarios, you have to set up a client manually as seen in the example above.
-In addition, you should also avoid adding any integrations that use global state, like `Breadcrumbs` or `TryCatch`.
-As a rule of thumb, it's best to avoid using any integrations and to rely on manual capture of errors only in such scenarios.
-
-### Dealing with Integrations
-
-Integrations are setup on the `Client`, if you need to deal with multiple clients and hubs you have to make sure to also do the integration handling correctly.
-
-We do not recommend doing this if you are using Sentry in a browser extension or in similar scenarios.
-If you can't avoid using global integrations (e.g. in a micro frontend application), here is a working example of how to use multiple clients with multiple hubs running global integrations.
-
-
-
-```javascript
-import * as Sentry from "@sentry/browser";
-
-// Very happy integration that'll prepend and append very happy stick figure to the message
-function happyIntegration() {
- return {
- name: 'Happy',
- setupOnce() {
- Sentry.addGlobalEventProcessor((event) => {
- const self = Sentry.getClient().getIntegration(HappyIntegration);
- // Run the integration ONLY when it was installed on the current Hub
- if (self) {
- event.message = `\\o/ ${event.message} \\o/`;
- }
- return event;
- });
- }
- }
-}
-
-const client1 = new Sentry.BrowserClient({
- dsn: "___PUBLIC_DSN___",
- transport: Sentry.makeFetchTransport,
- stackParser: Sentry.defaultStackParser,
- integrations: [...Sentry.defaultIntegrations, happyIntegration()],
- beforeSend(event) {
- console.log("client 1", event);
- return null; // Returning `null` prevents the event from being sent
- },
-});
-const hub1 = new Sentry.Hub(client1);
-
-const client2 = new Sentry.BrowserClient({
- dsn: "___PUBLIC_DSN___", // Can be a different DSN
- transport: Sentry.makeFetchTransport,
- stackParser: Sentry.defaultStackParser,
- integrations: [...Sentry.defaultIntegrations, happyIntegration()],
- beforeSend(event) {
- console.log("client 2", event);
- return null; // Returning `null` prevents the event from being sent
- },
-});
-const hub2 = new Sentry.Hub(client2);
-
-hub1.run((currentHub) => {
- // The `hub.run` method makes sure that `Sentry.getCurrentHub()` returns this hub during the callback
- currentHub.captureMessage("a");
- Sentry.getCurrentScope().setTag("a", "b");
-});
-
-hub2.run((currentHub) => {
- // The `hub.run` method makes sure that `Sentry.getCurrentHub()` returns this hub during the callback
- currentHub.captureMessage("x");
- Sentry.getCurrentScope().setTag("c", "d");
-});
-```
-
## Third Party Promise Libraries
When you include and configure Sentry, our JavaScript SDK automatically attaches global handlers to _capture_ uncaught exceptions and unhandled promise rejections. You can disable this default behavior by changing the `onunhandledrejection` option to `false` in your GlobalHandlers integration and manually hook into each event handler, then call `Sentry.captureException` or `Sentry.captureMessage` directly.
diff --git a/src/middleware.ts b/src/middleware.ts
index 5270698b90f428..13c3931cfd144a 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -2488,6 +2488,18 @@ const REDIRECTS: {from: PathWithTrailingSlash; to: string}[] = [
from: '/product/sentry-basics/search/searchable-properties/session-replay/',
to: '/product/reference/search/searchable-properties/session-replay/',
},
+ {
+ from: '/platforms/javascript/configuration/micro-frontend-support/',
+ to: '/platforms/javascript/best-practices/micro-frontends/',
+ },
+ {
+ from: '/platforms/javascript/configuration/sentry-testkit/',
+ to: '/platforms/javascript/best-practices/sentry-testkit/',
+ },
+ {
+ from: 'platforms/javascript/configuration/webworkers/',
+ to: '/platforms/javascript/best-practices/web-workers/',
+ },
];
const redirectMap = new Map(REDIRECTS.map(r => [r.from as string, r.to]));
diff --git a/vercel.json b/vercel.json
index c16c955d0c5767..c5f8ccd7d60d1d 100644
--- a/vercel.json
+++ b/vercel.json
@@ -734,6 +734,18 @@
"source": "/platforms/javascript/sourcemaps/tools/",
"destination": "/platforms/javascript/sourcemaps/"
},
+ {
+ "source": "/platforms/javascript/guides/([^/]*)/configuration/micro-frontend-support/",
+ "destination": "/platforms/javascript/guides/$1/best-practices/micro-frontends/"
+ },
+ {
+ "source": "/platforms/javascript/guides/([^/]*)/configuration/sentry-testkit/",
+ "destination": "/platforms/javascript/guides/$1/best-practices/sentry-testkit/"
+ },
+ {
+ "source": "/platforms/javascript/guides/([^/]*)/configuration/webworkers/",
+ "destination": "/platforms/javascript/guides/$1/best-practices/web-workers/"
+ },
{
"source": "/platforms/apple/guides/([^/]*)/configuration/integrations/([^/]*)/",
"destination": "/platforms/apple/guides/$1/integrations/$2/"