diff --git a/src/content/docs/configuration.mdx b/src/content/docs/configuration.mdx
index 7c8244b..524cad9 100644
--- a/src/content/docs/configuration.mdx
+++ b/src/content/docs/configuration.mdx
@@ -218,7 +218,27 @@ Control how screenshots are collected during the feedback flow.
- **`auto`** -- Automatically captures a full-page screenshot after the form is submitted, without showing the manual screenshot picker or redaction step.
- **`required`** -- Requires a screenshot before submission. Users can choose full page, element, or area, then annotate or redact before submitting.
-Manual redaction is controlled by the person submitting feedback. Use developer-configured masking for fields that should never appear in screenshots, especially with automatic screenshots.
+Manual redaction is controlled by the person submitting feedback. Use developer-configured masking for fields that should be visually covered in supported screenshot modes, especially with automatic screenshots. Auto mode warns users that a full-page screenshot will be attached, but it does not show the manual picker or annotation review step.
+
+### Developer-configured screenshot masking
+
+BugDrop can visually mask fields that your app marks as private before a screenshot is uploaded:
+
+```html
+
+Private account details
+```
+
+Supported attributes:
+
+- `data-bugdrop-redact`
+- `data-bd-redact`
+- `data-bugdrop-redacted`
+- `data-bugdrop-mask`
+
+This is best-effort visual masking, not a data-loss-prevention or security boundary. BugDrop can only mask content it can measure in the page DOM. Unmarked sensitive information can still appear, and browser rendering limits can apply to canvas, image, video, iframe, SVG, shadow DOM, pseudo-element, and highly custom control content.
+
+Selected-area screenshots are rendered to the selected dimensions and masks are translated into that crop, but the capture still runs client-side against the page DOM. Avoid screenshots entirely for pages where client-side screenshot rendering is unacceptable.
```html
diff --git a/src/content/docs/faq.mdx b/src/content/docs/faq.mdx
index 014b622..94ae350 100644
--- a/src/content/docs/faq.mdx
+++ b/src/content/docs/faq.mdx
@@ -42,9 +42,9 @@ Since BugDrop uses Shadow DOM for isolation, it does not conflict with any frame
### How does BugDrop handle screenshots?
-BugDrop uses [html2canvas](https://html2canvas.hertzen.com/) to capture screenshots entirely on the client side. When a user clicks the screenshot button:
+BugDrop uses [html-to-image](https://github.com/bubkoo/html-to-image) to capture screenshots entirely on the client side. When a user clicks the screenshot button:
-1. html2canvas renders the current page to an HTML Canvas element in the user's browser
+1. html-to-image renders the current page to an HTML Canvas element in the user's browser
2. In optional and required manual screenshot flows, the user can annotate the screenshot and cover sensitive regions with opaque blocks
3. The canvas is converted to a PNG image
4. The image is sent to the BugDrop API along with the form submission
@@ -198,7 +198,7 @@ Check the following:
1. **Verify the script tag** -- Make sure it does not have `async` or `defer` attributes
2. **Check the console** -- Open your browser's developer console and look for `[BugDrop]` messages or errors
-3. **Check CSP** -- If your site uses a Content Security Policy, make sure `https://bugdrop.neonwatty.workers.dev` and `https://cdn.jsdelivr.net` are allowed in `script-src`
+3. **Check CSP** -- If your site uses a Content Security Policy, make sure `https://bugdrop.neonwatty.workers.dev` is allowed in `script-src`
4. **Check the repo** -- Ensure `data-repo` matches your GitHub repository path exactly (case-sensitive)
5. **Check app installation** -- Verify the BugDrop GitHub App is installed on the repository
@@ -216,8 +216,8 @@ If the widget appears but submissions fail:
If issues are created but without screenshots:
1. **Check branch protection** -- The GitHub App needs permission to push to the `bugdrop-screenshots` branch. See the [Installation](/docs/installation) page for details on branch protection configuration.
-2. **Check CSP** -- The html2canvas library is loaded from `cdn.jsdelivr.net`. Make sure it is allowed by your Content Security Policy.
-3. **Cross-origin content** -- html2canvas cannot capture cross-origin iframes or images loaded without CORS headers. These elements may appear blank in the screenshot.
+2. **Check CSP** -- Make sure your Content Security Policy allows the BugDrop widget script.
+3. **Cross-origin content** -- Browser screenshot rendering cannot capture cross-origin iframes or images loaded without CORS headers. These elements may appear blank in the screenshot.
### Can I use BugDrop on a static site?
diff --git a/src/content/docs/installation.mdx b/src/content/docs/installation.mdx
index 81b8828..57f49a4 100644
--- a/src/content/docs/installation.mdx
+++ b/src/content/docs/installation.mdx
@@ -73,8 +73,9 @@ See the [Configuration](/docs/configuration) and [Styling](/docs/styling) docs f
## Protecting sensitive data
-If your page renders customer data, billing details, or any other content you do not
-want to appear in submitted screenshots, mark those elements with `data-bugdrop-mask`:
+If your page renders customer data, billing details, or any other content you want
+BugDrop to visually cover in supported screenshot modes, mark those elements with
+`data-bugdrop-mask`:
```html
@@ -82,9 +83,9 @@ want to appear in submitted screenshots, mark those elements with `data-bugdrop-
```
-BugDrop covers each marked element with an opaque rectangle on the captured screenshot.
+BugDrop covers each marked element with an opaque rectangle on supported captured screenshots.
Password inputs and credit-card autocomplete fields are masked automatically. See
-[Screenshot masking](/docs/security#screenshot-masking) on the Security page for details.
+[Screenshot masking](/security#screenshot-masking) on the Security page for details.
## Step 3: You Are Done
@@ -107,13 +108,13 @@ The BugDrop script tag should **not** include the `async` or `defer` attributes.
### Content Security Policy (CSP)
-If your site uses a Content Security Policy, you will need to allow `cdn.jsdelivr.net` in your CSP directives. BugDrop loads the html2canvas library from jsDelivr for screenshot functionality:
+If your site uses a Content Security Policy, allow the BugDrop worker domain in your CSP directives:
```
-Content-Security-Policy: script-src 'self' https://bugdrop.neonwatty.workers.dev https://cdn.jsdelivr.net;
+Content-Security-Policy: script-src 'self' https://bugdrop.neonwatty.workers.dev;
```
-If you have a strict CSP, make sure both the BugDrop worker domain and jsDelivr are included in your `script-src` directive.
+If you have a strict CSP, make sure the BugDrop worker domain is included in your `script-src` directive.
### Branch Protection and the Screenshots Branch
diff --git a/src/content/docs/security.mdx b/src/content/docs/security.mdx
index 34692c8..c6c202f 100644
--- a/src/content/docs/security.mdx
+++ b/src/content/docs/security.mdx
@@ -53,14 +53,14 @@ Treat screenshots as unauthenticated user-generated content. The hosted service
### Screenshot Format
-Screenshots are captured client-side using [html2canvas](https://html2canvas.hertzen.com/), which renders the current page to a canvas element in the user's browser. The canvas is then converted to a PNG image and uploaded. This means:
+Screenshots are captured client-side using [html-to-image](https://github.com/bubkoo/html-to-image), which renders the current page to a canvas element in the user's browser. The canvas is then converted to a PNG image and uploaded. This means:
- The initial screenshot capture is rendered from what the user actually sees
- No server-side rendering or page access is required
- The screenshot is generated entirely in the user's browser before being sent to the API
- Users can redact additional screenshot regions before submitting when using the manual screenshot flow
-Manual redaction is user-driven and does not automatically detect sensitive content. It complements, but does not replace, developer-configured masking for fields that should never appear in screenshots, especially when using automatic screenshots.
+Manual redaction is user-driven and does not automatically detect sensitive content. It complements, but does not replace, developer-configured masking for fields that should be visually covered in supported screenshot modes, especially when using automatic screenshots.
Because clients are untrusted, the API validates screenshot uploads server-side before storing them. BugDrop currently accepts PNG data URLs only and rejects SVG, malformed base64, oversized payloads, and data that does not have a PNG file signature.
@@ -78,11 +78,10 @@ BugDrop is built with a privacy-first approach:
### Screenshot masking
-You can mark sensitive elements so they never appear in submitted screenshots. Add the
-`data-bugdrop-mask` attribute to any element you want covered:
+You can mark sensitive elements so BugDrop visually covers them in supported screenshot modes. Add `data-bugdrop-redact` or `data-bugdrop-mask` to any element you want covered:
```html
-
+
Customer name
@@ -90,9 +89,19 @@ You can mark sensitive elements so they never appear in submitted screenshots. A
```
-When a user submits feedback, BugDrop paints an opaque rectangle over each tagged
-element's bounding box on the captured PNG before showing the user the annotator
-preview. The user sees what is masked and can audit it before submitting.
+Supported explicit attributes are `data-bugdrop-redact`, `data-bd-redact`,
+`data-bugdrop-redacted`, and `data-bugdrop-mask`.
+
+When a user submits feedback, BugDrop plans redactions from matching DOM
+elements, then paints an opaque rectangle over each target's measured bounding
+box on supported captured PNGs. In manual screenshot flows, the masked image is
+shown in the annotator preview so the user can audit it before submitting. In
+automatic screenshot mode, BugDrop applies supported masks but submits without
+showing the preview step.
+
+Masking is best-effort visual coverage, not a data-loss-prevention or security
+boundary. Users should still review screenshots before submitting when the manual
+screenshot flow is enabled.
**Inheritance.** When an ancestor has `data-bugdrop-mask`, the entire ancestor box is
masked as a single rectangle. Descendants do not get individual rectangles — this
@@ -105,8 +114,14 @@ prevents gaps from CSS `gap` or non-masked siblings inside a masked container.
**Known limitations:**
-- Elements inside Shadow DOM and cross-origin iframes are not traversed in this
- iteration.
+- Elements inside open Shadow DOM are traversed when the browser exposes the
+ shadow root. Closed Shadow DOM cannot be traversed; mark the host element if
+ the whole custom control should be covered.
+- Iframe contents are not traversed. Mark the iframe element itself if the whole
+ embedded frame should be visually covered.
+- BugDrop does not inspect pixels or text inside canvas, image, video, plugin,
+ or iframe content. Mark the containing DOM element if that entire region should
+ be visually covered.
- Mask rectangles are collected at the start of capture. If the page reflows or reveals
sensitive elements between collection and the moment `html-to-image` finishes
rendering, the mask may not cover the final pixels. Keep masked content stable during
@@ -121,8 +136,7 @@ prevents gaps from CSS `gap` or non-masked siblings inside a masked container.
The only network requests BugDrop makes are:
1. Loading the widget script from Cloudflare Workers
-2. Loading html2canvas from cdn.jsdelivr.net (for screenshot functionality)
-3. Submitting the feedback form to the BugDrop Cloudflare Worker API
+2. Submitting the feedback form to the BugDrop Cloudflare Worker API
The API acts as a pass-through to the GitHub API -- it receives the form data, creates the issue and uploads the screenshot, and discards the data. Nothing is persisted on the Cloudflare Worker.
diff --git a/src/content/docs/self-hosting.mdx b/src/content/docs/self-hosting.mdx
index b256a5a..fae2730 100644
--- a/src/content/docs/self-hosting.mdx
+++ b/src/content/docs/self-hosting.mdx
@@ -35,7 +35,8 @@ You need to create your own GitHub App to replace the hosted BugDrop app. The ap
| **Webhook** | Not required (optional) |
| **Installation scope** | Your repositories |
-You will need the App ID, private key, and installation ID to configure the Worker.
+You will need the App ID and private key to configure the Worker. BugDrop discovers the
+installation for each repository at request time.
## Architecture Overview
@@ -60,7 +61,7 @@ The Cloudflare Worker acts as a secure proxy between the user's browser and the
## Setup Instructions
-Full self-hosting instructions, including environment variables, Wrangler configuration, and deployment steps, are available in the repository:
+Full self-hosting instructions, including environment variables, ignored local configuration, and deployment steps, are available in the repository:
**[SELF_HOSTING.md on GitHub](https://github.com/mean-weasel/bugdrop/blob/main/SELF_HOSTING.md)**
@@ -68,7 +69,7 @@ The guide covers:
1. **Forking the repository** -- Get your own copy of the BugDrop codebase
2. **Creating a GitHub App** -- Step-by-step instructions for creating and configuring the app
-3. **Configuring Wrangler** -- Setting up `wrangler.toml` with your account details
+3. **Configuring local overrides** -- Using ignored `.dev.vars` and `public/test/local-config.js` files so your fork stays clean
4. **Setting secrets** -- Storing your GitHub App credentials as Worker secrets
5. **Deploying** -- Publishing the Worker to your Cloudflare account
6. **Testing** -- Verifying the deployment works end-to-end