Widgets & EmbedsIdentity Verification

Identity Verification

Automatically identify your logged-in users in the ProductBridge widget. Generate a signed JWT on your server, pass it to the widget, and users never need to log in manually. Includes copy-paste code for Node.js, Python, PHP, Ruby, Go, React, Vue, and Angular.

Why Identify Users?

By default the widget works anonymously. When you add identity verification:

  • Feedback is automatically linked to the real user's profile — name, email, company, and plan
  • Your team sees who submitted each piece of feedback, not just what they said
  • Duplicate detection and user segmentation work immediately — no manual tagging
  • Users skip the login prompt inside the widget

How It Works

  1. Your server generates a short-lived JWT signed with your Widget API Secret
  2. Your frontend fetches that token and passes it to ProductBridge.init() as userToken
  3. ProductBridge verifies the signature and logs the user in automatically

The JWT is signed server-side so the widget can trust its contents. Your Widget API Secret never leaves your server.

Step 1 — Create a Widget API Key

Open Widget Settings

In your ProductBridge dashboard go to Settings > Widget & Embeds > API Keys.

Generate a new key

Click Generate API Key, give it a name (e.g. production), and copy the secret.

The full secret is shown only once. Copy it now and store it in your server's environment variables. If you lose it, generate a new one.

Store it server-side

Add the secret to your environment — never commit it to source control or expose it in client-side code:

PRODUCTBRIDGE_WIDGET_SECRET=your_64_char_hex_secret

Step 2 — Generate the JWT on Your Server

Create an endpoint on your backend that returns a short-lived JWT. The widget calls this endpoint after the user logs in.

const jwt = require('jsonwebtoken');
// npm install jsonwebtoken

const PRODUCTBRIDGE_SECRET = process.env.PRODUCTBRIDGE_WIDGET_SECRET;

function generateProductBridgeToken(user) {
  return jwt.sign(
    {
      // --- Required ---
      email: user.email,

      // --- Recommended ---
      name: user.name,
      sub: String(user.id),          // your internal user ID
      avatar_url: user.avatarUrl,

      // --- Optional: Company & Plan data ---
      company_name: user.companyName,
      company_id: String(user.companyId),
      company_mrr: user.mrr,         // monthly recurring revenue (number)
      customer_status: user.status,  // e.g. "active", "trial", "churned"
      renewal_date: user.renewalDate, // ISO date string
      renewal_risk: user.renewalRisk, // e.g. "low", "medium", "high"
    },
    PRODUCTBRIDGE_SECRET,
    {
      expiresIn: '1h',
      algorithm: 'HS256',
    }
  );
}

// Express route
app.get('/api/productbridge-token', requireAuth, (req, res) => {
  const token = generateProductBridgeToken(req.user);
  res.json({ token });
});

Step 3 — Pass the Token to the Widget

Fetch the token from your backend and pass it as userToken in ProductBridge.init(). Choose your frontend framework:

<script>
  (function () {
    // 1. Fetch the token from your backend
    fetch('/api/productbridge-token')
      .then(function (res) { return res.json(); })
      .then(function (data) {
        // 2. Load the SDK and init with the token
        var s = document.createElement('script');
        s.src = 'https://app.productbridge.io/sdk/pb-widget.js';
        s.async = true;
        s.onload = function () {
          ProductBridge.init({
            organizationId: 'YOUR_ORGANIZATION_ID',
            userToken: data.token,    // JWT from your server
            position: 'bottom-right',
            theme: 'auto',
          });
        };
        document.head.appendChild(s);
      });
  })();
</script>

JWT Payload Reference

FieldTypeRequiredDescription
emailstringYesUser's email address — used as the primary identity anchor
namestringRecommendedDisplay name shown in the ProductBridge dashboard
substringRecommendedYour internal user ID for deduplication
avatar_urlstringNoProfile picture URL
company_namestringNoUser's company name
company_idstringNoYour internal company/account ID
company_mrrnumberNoMonthly recurring revenue in USD (for prioritization)
customer_statusstringNoactive, trial, churned, or any custom status
renewal_datestringNoISO date string of the next renewal
renewal_riskstringNolow, medium, or high
account_owner_emailstringNoEmail of the account manager or CSM
external_user_idstringNoAny external system ID (CRM, Salesforce, etc.)

All fields except email are optional. Start with just email, name, and sub. Add company fields later if you want segmentation and prioritization data in your ProductBridge dashboard.

Token Expiry

Tokens are valid for 1 hour (expiresIn: '1h'). This is a short-lived token by design — it prevents stolen tokens from being reused indefinitely.

Your frontend should fetch a fresh token on each page load or session start. Since the token endpoint is behind your own authentication middleware, unauthenticated users automatically get no token, and the widget falls back to anonymous mode.

Advanced: User Hash Verification

For extra security, you can enable user hash verification in Settings > Widget & Embeds > Security. When enabled, ProductBridge requires your server to also send a hash of the user's ID:

const crypto = require('crypto');

// Compute HMAC-SHA256 of the user's ID with your Widget API Secret
const userHash = crypto
  .createHmac('sha256', process.env.PRODUCTBRIDGE_WIDGET_SECRET)
  .update(String(user.id))
  .digest('hex');

// Include it in the JWT payload
jwt.sign({ email: user.email, sub: String(user.id), user_hash: userHash }, ...);

With user hash enabled, any JWT that does not contain the correct hash is rejected — even if the signature is valid. This prevents one user from crafting a token that impersonates another.

Advanced: Identify After Init

If the widget loads before the user logs in (e.g. on a public page with a login modal), you can identify the user after the fact with ProductBridge.identify():

// 1. Init without a token (anonymous)
ProductBridge.init({ organizationId: 'YOUR_ORGANIZATION_ID' });

// 2. After the user logs in, fetch a token and identify
async function onLoginSuccess() {
  const { token } = await fetch('/api/productbridge-token').then(r => r.json());
  ProductBridge.identify(token);
}