Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/content/docs/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
<input data-bugdrop-redact value="sk_live_..." />
<section data-bugdrop-mask>Private account details</section>
```

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
<!-- Automatically attach a full-page screenshot -->
Expand Down
10 changes: 5 additions & 5 deletions src/content/docs/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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?

Expand Down
15 changes: 8 additions & 7 deletions src/content/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,19 @@ 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
<div class="customer-row" data-bugdrop-mask>
Jane Doe — jane@acme.com
</div>
```

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

Expand All @@ -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

Expand Down
38 changes: 26 additions & 12 deletions src/content/docs/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -78,21 +78,30 @@ 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
<input type="email" data-bugdrop-mask />
<input type="email" data-bugdrop-redact />

<div data-bugdrop-mask>
<span>Customer name</span>
<span>customer@example.com</span>
</div>
```

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
Expand All @@ -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
Expand All @@ -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.

Expand Down
7 changes: 4 additions & 3 deletions src/content/docs/self-hosting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -60,15 +61,15 @@ 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)**

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
Expand Down
Loading