feat: Add Betterbugs SDK support#41532
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds Betterbugs frontend integration: SDK dependency and wrapper, build and env wiring for an API key, runtime config and types, UI menu triggers to open the widget, route-change metadata refresh, and nginx/jest substitution flags. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as "Help Menu / Homepage"
participant Config as "App Configs"
participant Util as "BetterbugsUtil"
participant SDK as "@betterbugs/web-sdk"
participant Router as "RouteChangeListener"
User->>UI: Click "Send support info"
UI->>Config: read betterbugs.enabled, apiKey
UI->>Util: show(user)
Util->>Util: destroy existing instance (if any)
Util->>Config: read apiKey, appVersion, tenantId, runtime metadata
Util->>SDK: dynamic import (browser)
SDK-->>Util: module loaded
Util->>SDK: create widget with user, metadata, styles
SDK-->>Util: instance created
Util->>SDK: openWidget()
SDK-->>User: Widget displayed
Note over Router,Util: On route change
Router->>Util: updateMetadata()
Util->>SDK: setMetadata(updatedRuntimeMetadata)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@app/client/src/pages/common/SearchBar/HomepageHeaderAction.tsx`:
- Around line 146-153: Only render the "Send support info" MenuItem when
Betterbugs is enabled and has a valid API key, and localize its label via
createMessage; update the JSX in HomepageHeaderAction to conditionally include
the <MenuItem> that calls BetterbugsUtil.show(user) by checking the Betterbugs
config flag or API key presence (use whatever config accessor exists in this
component), and replace the hardcoded text with createMessage({ id: '...',
defaultMessage: 'Send support info' }) to match other menu items.
In `@app/client/src/pages/Editor/HelpButton.tsx`:
- Line 42: The menu item for "Send support info" is added and the BetterBugs SDK
is invoked unconditionally; update the HelpButton component to only render the
menu item when the feature flag is enabled (check the app config or
betterbugs.enabled) and guard the click handler to no-op if Betterbugs isn't
configured. Concretely: in HelpButton (where the menu is built / renderMenu or
addMenuItem is called) wrap the menu-item creation in a conditional that checks
betterbugs.enabled (or call a helper like BetterbugsUtil.isEnabled()), and in
the sendSupportInfo / onSendSupportInfo handler call BetterbugsUtil only after
verifying BetterbugsUtil.isEnabled() or API key presence; if not enabled, return
early (and optionally log a debug message) so the SDK is never triggered when no
API key is configured.
|
@sebastianiv21 , we need to have an option to allow the user to disable betterbugs. This is in scenarios where its airgapped, or the user has hosted in an isolated environment and does not want to outgoing traffic to betterbugs. |
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21598576654. |
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21679221046. |
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
… for disabling betterbugs
…e and update workflows
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21716034843. |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/deploy_preview.sh (1)
117-126:⚠️ Potential issue | 🟡 MinorConsider conditional injection for all optional API keys, not just Betterbugs.
Empty values are currently passed unconditionally to Helm for all optional API keys (OPENAI_API_KEY, APPSMITH_CARBON_API_KEY, APPSMITH_BETTERBUGS_API_KEY). While the application code handles empty Betterbugs keys explicitly, applying conditional injection consistently across all optional keys would prevent unnecessary ConfigMap pollution and avoid potential SDK initialization side effects.
Either implement conditional injection for all optional API keys, or confirm the Helm chart and application layers treat empty strings as disabled across the board.
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21718750696. |
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21725726438. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@app/client/src/utils/Analytics/betterbugs.ts`:
- Around line 183-195: The hide() method on the BetterBugs utility is marked
async but contains no await or asynchronous work; remove the async modifier from
the hide method declaration to avoid misleading callers and adjust any callers
only if they unnecessarily await BetterBugs.hide(); update references to the
method signature (BetterBugs.hide and this.instance.hide) accordingly so the
method is a plain synchronous function.
🧹 Nitpick comments (1)
app/client/src/utils/Analytics/betterbugs.ts (1)
145-148: RedundantupdateMetadata()call.
init()already callsgetRuntimeMetadata()and includes it in the initial metadata (line 113). CallingupdateMetadata()immediately after is redundant since the runtime state hasn't changed between these synchronous calls.♻️ Remove redundant call
// Initialize fresh instance await this.init(user); - this.updateMetadata(); - if (this.instance?.openWidget) {
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
…interface and simplify static hide method
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21827305063. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@app/client/src/utils/Analytics/betterbugs.ts`:
- Around line 95-114: The code is sending raw PII to Betterbugs: remove or
anonymize user.email and user.name from both the top-level SDK field
(user.email) and from metaData (user_email, user_name); instead pass a hashed or
non-identifying user ID (e.g., hash(user.email) or an internal userId) or omit
these fields entirely, and ensure any sensitive appVersion fields remain safe;
also replace the direct access store.getState().organization?.tenantId with the
canonical selector (use the same selector pattern as getInstanceId) to fetch
tenant_id consistently.
🧹 Nitpick comments (3)
app/client/src/utils/Analytics/betterbugs.ts (3)
117-117: Unsafe type assertionas BetterbugsInstance.If the SDK constructor's return type drifts from your interface (e.g., a version bump removes
openWidget), this cast silently hides the mismatch. A runtime shape check or a wrapper that adapts the SDK instance to the interface would be safer.
133-155: Concurrentshow()calls can leak orphaned SDK instances.If
show()is invoked twice before the firstawait this.init(user)resolves, both calls seethis.instanceasnull, both executenew Betterbugs(...), and the first instance is overwritten without being destroyed — a resource leak.A simple guard (e.g., a static
initializingpromise or flag) would prevent this.♻️ Suggested guard
class BetterbugsUtil { private static instance: BetterbugsInstance | null; + private static initPromise: Promise<void> | null = null; // ... public static async show(user?: User) { if (isAirgapped() || !getAppsmithConfigs().betterbugs.enabled) { log.warn("BetterBugs is disabled."); return; } + // Serialize concurrent calls + if (this.initPromise) { + await this.initPromise; + } + if (this.instance) { this.destroy(); } - await this.init(user); + this.initPromise = this.init(user); + await this.initPromise; + this.initPromise = null; this.updateMetadata(); if (this.instance?.openWidget) { this.instance.openWidget(); } else { log.warn("BetterBugs openWidget() is not available."); } }
157-181: Redundant optional chaining after null guard.Line 162:
this.instance?.setMetadata— the early return on line 158-160 already guaranteesthis.instanceis non-null. Same pattern on line 174 withgetMetadata. Not a bug, just noise.♻️ Suggested cleanup
- if (!this.instance?.setMetadata) { + if (!this.instance.setMetadata) { return; } // ... - const existingMeta = this.instance.getMetadata?.() || {}; + const existingMeta = this.instance.getMetadata?.() || {}; // this one is fine — getMetadata is optional on the interfaceActually
getMetadatais optional on the interface so?.is correct there. Only thesetMetadatacheck on line 162 has the redundant?..- if (!this.instance?.setMetadata) { + if (!this.instance.setMetadata) {
| ...(user?.email ? { email: user.email } : {}), | ||
| showActionButton: false, | ||
| styles: this.getDefaultStyles(), | ||
| mainHeading: "Send support info", | ||
| recordType: "recordVideo", | ||
| position: { bottom: "30px", right: "20px" }, | ||
| successMessageHeaderText: "Information received", | ||
| successMessageSubHeaderText: | ||
| "Our support team will use it to review the issue", | ||
| metaData: { | ||
| ...(user?.email ? { user_email: user.email } : {}), | ||
| ...(user?.name ? { user_name: user.name } : {}), | ||
| instance_id: getInstanceId(store.getState()), | ||
| tenant_id: store.getState().organization?.tenantId, | ||
| version: appVersion.id, | ||
| commit_sha: appVersion.sha, | ||
| edition: appVersion.edition, | ||
| release_date: appVersion.releaseDate, | ||
| ...this.getRuntimeMetadata(), | ||
| }, |
There was a problem hiding this comment.
User PII (email, name) is sent to a third-party service.
user.email is passed both as a top-level SDK field (line 95) and inside metaData (lines 105-106), along with user.name. This sends personally identifiable information to Betterbugs servers. Verify this aligns with your privacy policy and data processing agreements. Consider whether hashed identifiers or anonymized values would suffice for debugging.
Also, line 108 accesses store.getState().organization?.tenantId directly instead of using a selector — minor inconsistency with line 107 which uses getInstanceId.
🤖 Prompt for AI Agents
In `@app/client/src/utils/Analytics/betterbugs.ts` around lines 95 - 114, The code
is sending raw PII to Betterbugs: remove or anonymize user.email and user.name
from both the top-level SDK field (user.email) and from metaData (user_email,
user_name); instead pass a hashed or non-identifying user ID (e.g.,
hash(user.email) or an internal userId) or omit these fields entirely, and
ensure any sensitive appVersion fields remain safe; also replace the direct
access store.getState().organization?.tenantId with the canonical selector (use
the same selector pattern as getInstanceId) to fetch tenant_id consistently.
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
| } | ||
| } | ||
|
|
||
| if (item.id === "betterbugs-trigger") { |
There was a problem hiding this comment.
@subrata71 Right now this HelpButton is present in App and Workflows. Should be add it to packages as well?
There was a problem hiding this comment.
Yes, we should otherwise it will just remain as half-baked solution.
…arameters and enhance metadata handling
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21893986809. |
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
|
/build-deploy-preview skip-tests=true |
|
Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/21915963289. |
|
Deploy-Preview-URL: https://ce-41532.dp.appsmith.com |
subrata71
left a comment
There was a problem hiding this comment.
Please create an issue to add BetterBugs support for packages and workflows.
Description
Tip
Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team).
Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR.
This PR integrates Betterbugs bug reporting SDK into the Appsmith client application, providing users with an enhanced bug reporting experience directly within the application interface.
Motivation and Context
Currently, users need to manually report bugs through external channels, which can be cumbersome and may result in incomplete bug reports. By integrating Betterbugs, we enable:
Fixes #
Issue Numberor
Fixes
Issue URLWarning
If no issue exists, please create an issue first, and check with the maintainers if the issue is valid.
Automation
/ok-to-test tags="@tag.All"
🔍 Cypress test results
Tip
🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/21915839106
Commit: f70f563
Cypress dashboard.
Tags:
@tag.AllSpec:
Fri, 13 Feb 2026 01:50:46 UTC
Communication
Should the DevRel and Marketing teams inform users about this change?
Summary by CodeRabbit
New Features
Chores