Documentation

Everything you need to integrate FeatureBot into your product. From widget installation to webhooks and the JavaScript API.

Widget Installation

Basic Installation

Add this snippet before the closing </body> tag on every page where you want the widget to appear.

<script
  async
  src="https://cdn.featurebot.com/widget.js"
  data-key="YOUR_PUBLIC_KEY"
></script>

Replace YOUR_PUBLIC_KEY with your workspace public key from Settings → Install.

With User Context

Pass user information to enable personalization, MRR tracking, and segment-based analytics.

<script
  async
  src="https://cdn.featurebot.com/widget.js"
  data-key="YOUR_PUBLIC_KEY"
  data-user-id="USER_ID"
  data-email="USER_EMAIL"
  data-name="USER_NAME"
  data-plan="PLAN_NAME"
  data-mrr="MRR_IN_CENTS"
  data-company="COMPANY_NAME"
  data-role="USER_ROLE"
  data-company-size="COMPANY_SIZE"
  data-attributes='{"key": "value"}'
></script>

Available Attributes:

  • data-user-id - Your internal user ID
  • data-email - User's email address
  • data-name - User's display name
  • data-plan - Subscription plan name (e.g., "Pro", "Enterprise")
  • data-mrr - Monthly recurring revenue in cents
  • data-company - Company or organization name
  • data-role - User's role in the company (e.g., "Admin", "Developer")
  • data-company-size - Company size or headcount (e.g., "10-50", "Enterprise")
  • data-attributes - JSON string of custom key-value pairs

Single Page Applications

For React, Vue, Angular, or other SPAs where the user logs in after page load, use the JavaScript API to identify users dynamically.

// After user logs in
window.FeatureBot.identify({
  userId: user.id,
  email: user.email,
  name: user.name,
  plan: user.subscription.plan,
  mrr: user.subscription.mrr,
  company: user.company.name,
  role: user.role,
  companySize: user.company.size,
  attributes: {
    team: user.team,
    signupSource: user.signupSource,
    betaFeatures: user.betaFeatures
  }
});

// When user logs out
window.FeatureBot.reset();

Custom Styling

CSS Variables API

Customize the widget appearance using CSS variables. Pass them via the data-css-vars attribute or dynamically with FeatureBot.setTheme().

<script
  async
  src="https://cdn.featurebot.com/widget.js"
  data-key="YOUR_PUBLIC_KEY"
  data-css-vars='{
    "--fb-primary-color": "#0066cc",
    "--fb-user-message-bg": "#0066cc",
    "--fb-input-bg": "#f0f0f0"
  }'
></script>

Available Variables

Trigger Button

  • --fb-button-bg - Button background color
  • --fb-button-text - Button text color
  • --fb-button-border - Button border style (none, thin, thick)
  • --fb-button-border-color - Button border color
  • --fb-button-emoji - Button icon/emoji (e.g., "💬", "🚀", or empty string)

Chat Container

  • --fb-chat-border-radius - Chat window corner radius (e.g., "0", "12px", "24px")
  • --fb-shadow - Chat window box shadow

Chat Interior

  • --fb-primary-color - Accent color for header, buttons, focus states
  • --fb-chat-bg - Chat window background
  • --fb-text-color - Primary text color
  • --fb-muted-text - Secondary/muted text color
  • --fb-input-bg - Input field background
  • --fb-input-border - Input field border color
  • --fb-input-text - Input field text color
  • --fb-user-message-bg - User message bubble background
  • --fb-user-message-text - User message text color
  • --fb-bot-message-bg - Bot message bubble background
  • --fb-bot-message-text - Bot message text color

Note on Fonts

Only preset fonts are available: Inter, Poppins, Roboto, Open Sans, Lato, and System UI. Configure fonts in your dashboard under Widget Settings. Need a different font? Request it via the FeatureBot feedback button in your dashboard.

Webhooks

Overview

Webhooks allow you to receive real-time notifications when events occur in FeatureBot. Configure webhook endpoints in Settings → Webhooks.

Available Events

feedback.created

Triggered when new feedback is submitted via the widget, API, or public board.

voice.added

Triggered when a user adds their voice to existing feedback (me too!).

feedback.status_changed

Triggered when feedback status changes (e.g., Open → In Progress → Completed).

feedback.clustered

Triggered when feedback is grouped into a cluster by AI or manually.

Example Payload

Here's an example payload for the feedback.created event:

{
  "event": "feedback.created",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "feedback": {
    "id": "fb_abc123",
    "title": "Add dark mode support",
    "description": "It would be great to have a dark mode option",
    "category": "FEATURE_REQUEST",
    "status": "OPEN",
    "priority": "MEDIUM",
    "voiceCount": 1,
    "totalMrr": 9900,
    "avgSentiment": 0.8,
    "aiSummary": null,
    "aiTags": ["ui", "accessibility"],
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T10:30:00.000Z"
  },
  "workspace": {
    "id": "ws_xyz789",
    "name": "Acme Corp",
    "slug": "acme-corp"
  },
  "triggeredBy": "widget"
}

Request Headers

Each webhook request includes the following headers:

X-Webhook-Signature

HMAC-SHA256 signature for verification

X-Webhook-Event

The event type (e.g., FEEDBACK_CREATED)

X-Webhook-Delivery-Id

Unique ID for this delivery attempt

Content-Type

application/json

Verifying Signatures

Always verify webhook signatures to ensure requests are from FeatureBot. The signature format is: t=timestamp,v1=signature

import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  // Parse signature: t=<timestamp>,v1=<signature>
  const parts = signature.split(',');
  const timestamp = parts.find(p => p.startsWith('t='))?.slice(2);
  const sig = parts.find(p => p.startsWith('v1='))?.slice(3);

  if (!timestamp || !sig) return false;

  // Check timestamp (within 5 minutes)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) return false;

  // Verify signature
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(sig),
    Buffer.from(expectedSig)
  );
}

// In your webhook handler
app.post('/webhooks/featurebot', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const isValid = verifyWebhookSignature(
    JSON.stringify(req.body),
    signature,
    process.env.FEATUREBOT_WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the webhook...
  res.status(200).json({ received: true });
});

Delivery & Retries

  • • Webhooks timeout after 30 seconds by default
  • • Failed deliveries are retried up to 3 times
  • • Retries use exponential backoff
  • • Return a 2xx status code to acknowledge receipt
  • • View delivery history in Settings → Webhooks

JavaScript API

Control the widget programmatically using the global window.FeatureBot object.

window.FeatureBot.open()

Open the feedback widget

window.FeatureBot.open({ prefill: "I want..." })

Open with pre-filled text

window.FeatureBot.close()

Close the widget

window.FeatureBot.isOpen()

Returns true if the widget is currently open

window.FeatureBot.identify({ userId, email, name, plan, mrr, company, role, companySize, attributes })

Identify the current user (for SPAs). All fields are optional. The attributes field accepts any JSON object for custom data.

window.FeatureBot.reset()

Clear user identity (on logout)

window.FeatureBot.setTheme({ cssVars })

Customize widget colors dynamically using CSS variables. Changes apply immediately if the widget is open.

// Customize widget colors dynamically
window.FeatureBot.setTheme({
  '--fb-primary-color': '#0066cc',
  '--fb-chat-bg': '#fafafa',
  '--fb-user-message-bg': '#0066cc',
  '--fb-bot-message-bg': '#e5e5e5'
});
window.FeatureBot.hide()

Hide the widget completely (button and chat window)

window.FeatureBot.show()

Show the widget again after hiding

Ready to Get Started?

Create your free account and start collecting feedback in minutes.

Get Started Free