diff --git a/docs/guide/essentials/config/entrypoint-loaders.md b/docs/guide/essentials/config/entrypoint-loaders.md
index c33c870ad..23a85d19d 100644
--- a/docs/guide/essentials/config/entrypoint-loaders.md
+++ b/docs/guide/essentials/config/entrypoint-loaders.md
@@ -10,7 +10,7 @@ WXT does several pre-processing steps to try and prevent errors during this proc
 2. Use `@webext-core/fake-browser` to create a fake version of the `chrome` and `browser` globals expected by extensions.
 3. Pre-process the JS/TS code, stripping out the `main` function then tree-shaking unused code from the file
 
-However, this process is not perfect. It doesn't setup all the globals found in the browser and the APIs may behave differently. As such, **_you should avoid using browser or extension APIs outside the `main` function of your entrypoints!_**
+However, this process is not perfect. It doesn't setup all the globals found in the browser and the APIs may behave differently. As such, **_you should avoid using browser or extension APIs outside the `main` function of your entrypoints!_** See [Entrypoint Limitations](/guide/essentials/extension-apis#entrypoint-limitations) for more details.
 
 :::tip
 If you're running into errors while importing entrypoints, run `wxt prepare --debug` to see more details about this process. When debugging, WXT will print out the pre-processed code to help you identify issues.
diff --git a/docs/guide/essentials/extension-apis.md b/docs/guide/essentials/extension-apis.md
index 6397acf96..15439d8c6 100644
--- a/docs/guide/essentials/extension-apis.md
+++ b/docs/guide/essentials/extension-apis.md
@@ -75,3 +75,63 @@ Alternatively, if you're trying to use similar APIs under different names (to su
   //
 });
 ```
+
+## Entrypoint Limitations
+
+Because WXT imports your entrypoint files into a NodeJS, non-extension environment, the `chrome`/`browser` variables provided to extensions by the browser **will not be available**.
+
+To prevent some basic errors, WXT polyfills these globals with the same in-memory, fake implementation it uses for testing: [`@webext-core/fake-browser`](https://webext-core.aklinker1.io/fake-browser/installation/). However, not all the APIs have been implemented.
+
+So it is extremely important to NEVER use `browser.*` extension APIs outside the main function of any JS/TS entrypoints (background, content scripts, and unlisted scripts). If you do, you'll see an error like this:
+
+```plaintext
+✖ Command failed after 440 ms
+
+ ERROR  Browser.action.onClicked.addListener not implemented.
+```
+
+The fix is simple, just move your API usage into the entrypoint's main function:
+
+:::code-group
+
+```ts [background.ts]
+browser.action.onClicked.addListener(() => {
+  /* ... */
+}); // [!code --]
+
+export default defineBackground(() => {
+  browser.action.onClicked.addListener(() => {
+    /* ... */
+  }); // [!code ++]
+});
+```
+
+```ts [content.ts]
+browser.runtime.onMessage.addListener(() => {
+  /* ... */
+}); // [!code --]
+
+export default defineContentScript({
+  main() {
+    browser.runtime.onMessage.addListener(() => {
+      /* ... */
+    }); // [!code ++]
+  },
+});
+```
+
+```ts [unlisted.ts]
+browser.runtime.onMessage.addListener(() => {
+  /* ... */
+}); // [!code --]
+
+export default defineUnlistedScript(() => {
+  browser.runtime.onMessage.addListener(() => {
+    /* ... */
+  }); // [!code ++]
+});
+```
+
+:::
+
+Read [Entrypoint Loaders](/guide/essentials/config/entrypoint-loaders) for more technical details about this limitation.