Introduction

Introduction

Bugline is a browser SDK that turns in-app user feedback and unhandled client-side errors into developer-ready bug reports. By dropping a single lightweight widget into your web application, you let users, QA testers, and clients report issues directly from the page—without leaving your product.

Instead of vague email descriptions, every report Bugline sends automatically carries the current page path, browser name and version, operating system, screen resolution, language, and user agent. Users can attach a screenshot, pin the report to a specific element, or draw a highlight box around the problem area, and everything lands in your hosted Bugline dashboard.

Main Features

Feedback & Bug Reporting

A floating widget lets users write a note, pick a category, and submit feedback or bug reports directly from your app.

Automatic Error Capture

Optional listeners catch unhandled exceptions and promise rejections and forward them as reports with the stack trace attached.

Screenshots & Annotations

Users can capture the page, select a specific element, or draw a highlight box to show developers exactly where the issue is.

AI Page Assistant

An inspect mode where users click any element to get a plain-language description of its role, action, and page context.

Automatic Device Context

Every report includes the page path, browser, OS, screen resolution, language, user agent, and any global metadata you set.

Web & React Native

A browser SDK for React, Next.js, Vue, or plain JS, plus a separate React Native / Expo SDK for element-based mobile audits.

Why integrated feedback? Reports arrive with the environment already attached—browser, OS, resolution, and the exact page—so you skip the back-and-forth of asking users for device specifications and reproduction details.
Two SDKs: the web widget ships as @xtatistix/bugline-web, and the React Native / Expo SDK ships separately as @xtatistix/bugline-sdk with its own component-based API.

Quick Start

Get Bugline running in your web application in under two minutes.

Building a mobile app? This guide covers the web SDK (@xtatistix/bugline-web). For React Native / Expo, use the separate @xtatistix/bugline-sdk package—see React Native (Mobile).

1. Install the SDK

Add the Bugline Web SDK to your project via npm, yarn, or pnpm:

Terminal
npm install @xtatistix/bugline-web

2. Initialize Bugline

Import the named Bugline export and call init() once at the entry point of your application (such as index.js, main.js, or _app.js):

index.js
import { Bugline } from class="token-string">'@xtatistix/bugline-web';

Bugline.init({
  apiKey: class="token-string">'bl_your_api_key_here',                      class=class="token-string">"token-comment">// Required
  endpoint: class="token-string">'https:class="token-comment">//your-bugline-domain.com/api/reports', // Optional
  theme: class="token-string">'dark'                                         class=class="token-string">"token-comment">// Optional: class="token-string">'dark' or class="token-string">'light'
});

Minimum Configuration Explained

  • apiKey: (Required) The API key for your app, generated in the Bugline dashboard. It is sent as the x-api-key header on every report.
  • endpoint: (Optional) The URL of your hosted Bugline reports API. Defaults to '/api/reports', which is convenient when the SDK runs on the same origin as your dashboard.
  • theme: (Optional) Widget appearance: 'dark' or 'light'. Defaults to 'dark'.
Named import: Bugline is a named export, so use import { Bugline }—not a default import. Once init() runs, the floating widget mounts automatically unless you set showWidget: false.
Get an API key first: Create an app in your Bugline dashboard to obtain a valid apiKey. Without it, init() logs a warning and reports are rejected by the server with a 401.

Web Integration Guide

Bugline is a framework-agnostic browser SDK. It guards every access to window and document, so it is safe to import in server-rendered builds and only mounts the widget in the browser.

Supported Frameworks

  • React: Call Bugline.init() once in a top-level effect.
  • Next.js: Initialize from a Client Component; the SDK no-ops during SSR and mounts on the client.
  • Vue: Initialize once when the root app mounts.
  • Vanilla JavaScript: Import the module (or bundle it) and call init() on load.

Initialization Example (Next.js App Router)

Initialize Bugline inside a Client Component so it only runs in the browser:

app/providers.js
class="token-string">"use client";

import { useEffect } from class="token-string">'react';
import { Bugline } from class="token-string">'@xtatistix/bugline-web';

export function BuglineProvider({ children }) {
  useEffect(() => {
    Bugline.init({
      apiKey: class="token-string">'bl_your_api_key_here',
      endpoint: class="token-string">'https:class="token-comment">//your-bugline-domain.com/api/reports',
      environment: class="token-string">'production'
    });
  }, []);

  return children;
}

Opening the Feedback Widget

By default a floating trigger button sits in the bottom-right corner. To open the panel from your own UI, call Bugline.open() (and Bugline.close() to dismiss it):

Custom Button Handler
const handleFeedbackClick = () => {
  Bugline.open();
};
Prefer to trigger the widget entirely from your own button? Pass showWidget: false to init() to hide the default floating button, then call Bugline.open() yourself.

Sending a Report Programmatically

You can submit feedback or bug reports from anywhere in your code without the widget:

Programmatic report
Bugline.sendReport({
  text: class="token-string">'Checkout button is unresponsive on click',
  category: class="token-string">'bug',        class=class="token-string">"token-comment">// Optional: class="token-string">'feedback' | class="token-string">'bug' | class="token-string">'ui'
  severity: class="token-string">'warning',    class=class="token-string">"token-comment">// Optional: class="token-string">'info' | class="token-string">'warning' | class="token-string">'error'
  metadata: { cartTotal: 129.99 }
});

Attaching Global Metadata

Pass a metadata object to init() to merge the same diagnostic keys into every report the SDK sends—useful for user tiers, organizations, or release tags:

Global metadata
Bugline.init({
  apiKey: class="token-string">'bl_your_api_key_here',
  metadata: {
    plan: class="token-string">'Pro',
    organization: class="token-string">'Acme Inc',
    releaseTag: class="token-string">'v1.4.2'
  }
});
The browser, OS, screen resolution, language, and user agent are collected automatically—you don't need to add them to metadata yourself.

Error Reporting

Bugline collects errors two ways: automatically through global listeners, and manually through the captureException and sendReport methods. All of them funnel into the same request flow.

Automatic Error Capture

When captureErrors is enabled (it defaults to true), the SDK attaches listeners for the window error and unhandledrejection events. Each caught error is sent as a report with severity: 'error' and category: 'bug', including the message, source file, line/column, and stack trace in metadata.

Enable / disable auto-capture
Bugline.init({
  apiKey: class="token-string">'bl_your_api_key_here',
  captureErrors: true   class=class="token-string">"token-comment">// set to false to opt out of global error listeners
});

Capturing a Handled Exception

Inside a try/catch, forward a caught error along with any extra context:

captureException
try {
  executeRiskyOperation();
} catch (error) {
  Bugline.captureException(error, {
    additionalContext: class="token-string">'Failed during payment processing'
  });
}

How Reports Are Sent

Every report—whether from the widget, automatic capture, or a manual call—is POSTed to your configured endpoint as JSON, authenticated with the x-api-key header. The SDK enriches the body with the current page path, browser, OS, app version, environment, resolution, language, and user agent before sending.

Request sent by the SDK
POST /api/reports
Headers:
  Content-Type: application/json
  x-api-key: bl_your_api_key_here

Body:
{
  class="token-string">"text": class="token-string">"Unhandled error: Cannot read properties of undefined",
  class="token-string">"screen": class="token-string">"/checkout",
  class="token-string">"deviceModel": class="token-string">"Chrome (128)",
  class="token-string">"osVersion": class="token-string">"Windows 10/11",
  class="token-string">"appVersion": class="token-string">"1.0.0",
  class="token-string">"environment": class="token-string">"production",
  class="token-string">"sdkVersion": class="token-string">"web-sdk-1.0.0",
  class="token-string">"severity": class="token-string">"error",
  class="token-string">"category": class="token-string">"bug",
  class="token-string">"metadata": {
    class="token-string">"userAgent": class="token-string">"...",
    class="token-string">"resolution": class="token-string">"1920x1080",
    class="token-string">"language": class="token-string">"en-US",
    class="token-string">"errorStack": class="token-string">"..."
  }
}
The server validates the x-api-key against your registered apps and responds with { "id": "..." } and a 201 status. An invalid or missing key returns 401.

React Native (Mobile)

Bugline ships a separate SDK for React Native and Expo apps, published as @xtatistix/bugline-sdk. It is an element-based audit SDK: testers enter a selection mode, tap a registered UI element (drilling into nested children or parents when targets overlap), write a required note, queue it locally, and submit the collected notes to your API as plain JSON.

Different package and API from the web SDK. The web widget (@xtatistix/bugline-web) uses the imperative Bugline.init() API. The mobile SDK (@xtatistix/bugline-sdk) is component-based—createAuditClient() plus <AuditProvider>. They are not interchangeable.

Requirements

The SDK declares react >= 18 and react-native >= 0.73 as peer dependencies, and works with Expo.

1. Install

Install the SDK and make sure the React Native peer dependencies are present:

Terminal
npm install @xtatistix/bugline-sdk
# peer dependencies (already present in most RN/Expo apps)
npm install react react-native

2. Create a Client and Wrap Your App

Create an audit client with createAuditClient(), wrap your tree in <AuditProvider> and <AuditSelectionRoot>, mark the elements you want to be selectable with stable <AuditSelectable> ids, and drop an <AuditWidget> to expose the floating audit button:

App.tsx
import {
  AuditProvider,
  AuditSelectable,
  AuditSelectionRoot,
  AuditWidget,
  createAuditClient,
} from class="token-string">'@xtatistix/bugline-sdk';

const audit = createAuditClient({
  apiKey: class="token-string">'project-api-key',
  endpoint: class="token-string">'https:class="token-comment">//your-domain.com/api/audit/issues',
  environment: class="token-string">'staging',
  projectId: class="token-string">'mobile-app',
  sdkVersion: class="token-string">'0.1.0',
  reporter: { id: class="token-string">'user-123', role: class="token-string">'tester' },
  privacy: { enabled: true },
});

export function App() {
  return (
    <AuditProvider client={audit}>
      <AuditSelectionRoot>
        <AuditSelectable id=class="token-string">"top-bar" kind=class="token-string">"navigation">
          <TopBar />
        </AuditSelectable>

        <AuditSelectable id=class="token-string">"save-button" kind=class="token-string">"button">
          <Button title=class="token-string">"Save" />
        </AuditSelectable>

        <AuditWidget screenName=class="token-string">"Profile" />
      </AuditSelectionRoot>
    </AuditProvider>
  );
}

Client Options

createAuditClient(config) accepts:

OptionTypeDescription
apiKeystringProject API key. Sent as the x-audit-api-key header when configured.
endpointstringYour HTTP endpoint that receives the JSON audit payloads.
environmentstringEnvironment label attached to the payload (e.g. 'staging').
projectIdstringIdentifier for the mobile project, included in every payload.
sdkVersionstringVersion string recorded with each submitted note.
reporterobjectWho is filing the notes, e.g. { id, role }.
privacyobjectPrivacy masking config, e.g. { enabled: true }. On by default.

How Element Auditing Works

  • AuditSelectionRoot measures every registered AuditSelectable element.
  • AuditSelectionOverlay outlines selectable elements while selection mode is active.
  • Tapping a point selects the smallest matching child; a parent/child switcher moves between nested targets (e.g. SaveText → SaveButton → TopBar).
  • Confirming a target opens a required note flow; category and severity are optional.
  • Saved notes stay in a local draft audit session; audit-only breadcrumbs track select, save, delete, and submit events.
  • Submitting the session sends all queued notes together.

How Notes Are Sent

The SDK does not talk to Firebase directly—the built-in HttpAuditTransport posts JSON to your endpoint, and the recommended boundary is Mobile SDK → API route handler → Firebase. Each request sends:

  • content-type: application/json
  • x-audit-api-key when apiKey is configured
  • a JSON body built by buildElementNotePayload()
  • a batch body { session, notes: [...] } when several saved notes are submitted together

Each element note payload is plain JSON with these fields:

buildElementNotePayload() output
{
  projectId, environment, sdkVersion, screenName,
  selectedElement, ancestors, children,
  note, category, severity,
  sessionId, breadcrumbs, createdAt
}
This repo's reports API (app/api/reports/route.js) already accepts the x-audit-api-key header and batch { notes: [...] } bodies, so one backend can serve both the web and mobile SDKs.

Privacy Masking

Masking is enabled by default in the payload builder and redacts sensitive data before JSON leaves the device: keys containing token, authorization, cookie, secret, password, email, or phone, plus email addresses, phone-like numbers, and bearer/JWT/API-token values. Override the defaults via createAuditClient({ privacy: ... }).

Exporting Notes

The SDK also exposes buildMarkdown() and buildDocx() helpers to turn a collected audit session into a Markdown or Word document for sharing.

Widget & Reporting Tools

When showWidget is enabled (the default), Bugline mounts a floating trigger button in the bottom-right corner. Clicking it slides out a feedback panel with the tools below.

Note & Category

Users type a description and pick a category chip (such as Bug, Feedback, or UI) before submitting.

Select Element

An inspect mode where the user taps any element on the page to pin the report to a specific DOM node.

Draw Area

Users drag a highlight box over the page to outline the exact region where the problem appears.

Screenshot Capture

The widget renders the page to an image with html2canvas (loaded on demand) and attaches it to the report.

Offline Drafts

Reports the user creates are saved locally under the bugline_draft_reports key in localStorage. A badge on the trigger button shows how many drafts are pending, and users can send them individually or all at once. Drafts that fail to send are kept and marked as failed so they can be retried.

The widget captures screenshots by loading html2canvas-pro from a CDN the first time a capture is requested. If your site enforces a strict Content Security Policy, allow that script source or disable screenshot capture in your integration.

AI Assistant

The AI Assistant is an in-page inspect mode. A second floating button (the ring-shaped icon above the main widget) turns any element on the page into a plain-language explanation of what it is and what it does—handy for users describing an issue and for teammates unfamiliar with the UI.

How It Works

  1. The user clicks the AI Assistant button above the main widget trigger.
  2. They click any element—a button, link, input, or section.
  3. A card appears describing the element's role, its likely action, and where it sits on the page (navigation, sidebar, form, footer, or main content).

Context-Aware Descriptions

The assistant reads the element's tag, text, ARIA labels, and surrounding headings to explain its purpose in context.

Layout Location Detection

It detects whether the element lives in a nav bar, sidebar, form, card, table, or footer, and phrases the explanation accordingly.

Local Analysis with Optional Backend

The assistant first attempts to POST the selected element's tag, id, class, a trimmed outerHTML, and inner text to {endpoint}/ai-analyze. If that request fails or the endpoint isn't available, it falls back to a built-in heuristic engine that runs entirely in the browser—so the assistant works out of the box even without a hosted analysis endpoint.

The ai-analyze endpoint is optional. Out of the box the assistant produces its descriptions locally from the page DOM; wiring up a backend at {endpoint}/ai-analyze lets you return richer, model-generated explanations.

Configuration

Configure the SDK by passing an options object to Bugline.init(). Only apiKey is required; every other option has a sensible default.

OptionTypeDefaultDescription
apiKeystringRequiredThe API key for your app from the Bugline dashboard. Sent as the x-api-key header on every report.
endpointstring'/api/reports'URL the SDK posts reports to. Use your hosted dashboard's full URL when the SDK runs on a different origin.
appVersionstring'1.0.0'The version of your client application, attached to each report.
environmentstring'production'Deployment environment label (e.g. 'development', 'staging', 'production').
captureErrorsbooleantrueAutomatically capture unhandled errors and promise rejections as reports.
showWidgetbooleantrueMount the floating feedback button and side panel. Set to false to drive the widget yourself.
themestring'dark'Widget appearance: 'dark' or 'light'.
metadataobject{}Key-value pairs merged into the metadata of every report the SDK sends.
You can override the widget's accent colors with CSS variables such as --bl-primary-color and --bl-accent-color in your own stylesheet.

API Reference

The Bugline named export exposes the following methods. Import it with import { Bugline } from '@xtatistix/bugline-web'. (This is the web API; the React Native SDK has a different, component-based API—see React Native (Mobile).)

Bugline.init(options)

Initializes the SDK, wires up error capture, and mounts the widget. Call it once at startup.

  • Parameters: options (Object) — see the Configuration table. apiKey is required.
  • Returns: void
javascript
Bugline.init({ apiKey: class="token-string">'bl_your_api_key_here' });

Bugline.open()

Opens the feedback side panel.

  • Returns: void
javascript
Bugline.open();

Bugline.close()

Closes the feedback side panel.

  • Returns: void
javascript
Bugline.close();

Bugline.sendReport(report)

Sends a feedback or bug report programmatically. The SDK enriches it with device, browser, and page context before posting.

  • Parameters: report (Object) — text (string), and optionally screen, deviceModel, osVersion, screenshotUrl, severity ('info' | 'warning' | 'error', default 'info'), category (default 'feedback'), and metadata (Object).
  • Returns: Promise — resolves with the server response (e.g. { id }), rejects on failure.
javascript
Bugline.sendReport({
  text: class="token-string">'Save button overlaps the input on narrow screens',
  category: class="token-string">'ui',
  severity: class="token-string">'warning',
  metadata: { viewport: window.innerWidth }
});

Bugline.captureException(error, extraMetadata?)

Sends a caught error as a report with severity: 'error' and category: 'bug', attaching the stack trace.

  • Parameters: error (Error or value) and optional extraMetadata (Object) merged into the report metadata.
  • Returns: Promise
javascript
try {
  doSomething();
} catch (err) {
  Bugline.captureException(err, { screen: class="token-string">'/settings' });
}

Best Practices

A few recommendations for running Bugline cleanly in production.

Set the Environment

Pass an accurate environment to init() ('development', 'staging', or 'production'). It's attached to every report so you can filter dashboard reports by where they came from.

Attach Context with Metadata

Provide a metadata object at init() with details like the current user's plan, organization, or a release tag. Those keys are merged into every report, which makes triage in the dashboard much faster than device data alone.

Protect Your API Key

The apiKey ships to the browser, so treat it as a publishable client key: scope it to a single app and rotate it from the dashboard if it's misused. Reports are only accepted for the app the key belongs to.

Screenshots & CSP

Screenshot capture loads html2canvas-pro from a CDN on first use. If you run a strict Content Security Policy, allow that script origin—otherwise capture silently falls back to sending the report without an image.

Errors in Production

Keep captureErrors enabled in production so unhandled exceptions and promise rejections are reported automatically. Disable it only if another error-monitoring tool already owns those global listeners.

Troubleshooting

Solutions to the most common integration issues.

Confirm init() actually runs in the browser (not only on the server), that showWidget isn't set to false, and that no other element with a very high z-index covers the bottom-right corner. In Next.js, call init() from a Client Component or inside a useEffect.

The apiKey is missing or invalid. Make sure you passed apiKey to init() and that it matches an app registered in your Bugline dashboard. The key is sent as the x-api-key header, and the server rejects unknown keys with 401.

Bugline is a named export. Use import { Bugline } from '@xtatistix/bugline-web', not a default import. A default import resolves to undefined.

When the SDK and your dashboard are on different origins, the reports endpoint must allow your site's origin and the x-api-key header. Point endpoint at your hosted dashboard's full /api/reports URL and confirm its CORS configuration permits cross-origin POST requests.

The SDK guards browser globals, so importing it during SSR is safe. This error usually means your own code touches window at module scope—move Bugline.init() into a client-only lifecycle such as useEffect.

Capture loads html2canvas-pro from a CDN on first use. If a Content Security Policy or network block prevents that script from loading, the report is still sent but without the image. Allowlist the CDN script source to enable captures.

FAQ

Frequently asked developer questions regarding integration, features, and security scopes.

Yes. Import the named Bugline export and call Bugline.init() once in a top-level effect. There's no React-specific package—the same browser SDK works everywhere.

Yes. The SDK guards every access to window and document, so it's safe to import in SSR builds. Call init() from a Client Component (or inside useEffect) so the widget mounts on the client.

Yes. React Native and Expo apps use a separate package, @xtatistix/bugline-sdk, which is a component-based element-audit SDK (createAuditClient + AuditProvider). It's different from the web SDK—see the React Native (Mobile) guide. There is no Flutter, native Android, or native iOS package.

Yes. The widget can render the page to an image using html2canvas (loaded on demand) and attach it to the report. Users can also select a specific element or draw a highlight box to pinpoint the issue.

It's an inspect mode: users click an element and get a plain-language description of its role and page context. It tries an optional {endpoint}/ai-analyze backend and otherwise falls back to a local heuristic engine that runs in the browser.

Each report carries your message, category, and severity plus automatically collected context: the page path, browser name/version, OS, screen resolution, language, user agent, app version, environment, and any global metadata you configured.