Skip to main content

Why metadata matters

The more metadata you attach to each conversation, the more you can filter, segment, and analyze in the dashboard. Start with user and organization data, then layer on session and custom fields as needed.
Every recordMessages call accepts optional metadata objects alongside your messages. These fields power filtering across the OpenBat dashboard — by plan, industry, MRR range, device type, country, or any custom dimension you define.

User metadata

Attach user information so you can trace conversations back to specific accounts and filter by plan, revenue, or industry.
user: {
  id: string,        // Your internal user ID
  name: string,      // Display name
  email: string,     // Email address
  plan: string,      // "free" | "pro" | "enterprise" | etc.
  createdAt: Date,   // Account creation date
  industry: string,  // User's industry
  mrr: number        // Monthly recurring revenue in dollars
}
All fields are optional. Pass whichever ones you have available.

Organization metadata

When your users belong to teams or companies, attach organization data for account-level filtering.
organization: {
  id: string,
  name: string,
  plan: string,
  mrr: number,
  industry: string
}

Session metadata

Session fields help you understand where and how conversations happen.
session: {
  id: string,
  pageUrl: string,   // Page where the conversation started
  referrer: string,  // Referring URL
  device: string,    // "desktop" | "mobile" | "tablet"
  country: string    // ISO country code
}

Custom fields

For anything not covered by the built-in fields, use the custom object.
custom: Record<string, string | number | boolean>
Custom fields must match the metadata schema configured in your chatbot’s Settings → Metadata tab. Unknown fields produce a warning in the response but do not fail the request.

Fully enriched example

Here is a complete recordMessages call with all metadata objects populated:
await client.recordMessages({
  conversationId: `conv_${userId}_${sessionId}`,

  user: {
    id: user.id,
    name: user.fullName,
    email: user.email,
    plan: user.subscriptionPlan,
    createdAt: user.createdAt,
    industry: user.company?.industry,
    mrr: user.monthlyRevenue
  },

  organization: {
    id: user.organization.id,
    name: user.organization.name,
    plan: user.organization.plan,
    mrr: user.organization.monthlyRevenue,
    industry: user.organization.industry
  },

  session: {
    id: sessionId,
    pageUrl: req.headers['referer'],
    device: detectDevice(req.headers['user-agent']),
    country: req.headers['cf-ipcountry']
  },

  custom: {
    trial_days_remaining: user.trialDaysLeft,
    feature_flags: user.activeFeatures.join(","),
    account_tier: user.accountTier
  },

  messages: conversationHistory
});
With this data attached, you can filter conversations in the dashboard by plan, industry, MRR range, device type, country, or any of your custom fields.

Server-side header forwarding

When you call recordMessages from a server-side route handler, pass the incoming request headers so OpenBat can automatically detect the user’s country and device type from Cloudflare headers (cf-ipcountry, user-agent).
await client.recordMessages({
  conversationId: metadata.conversationId,
  user: metadata.user,
  messages: conversationHistory,
  headers: Object.fromEntries(req.headers)
});
This removes the need to manually populate session.country and session.device — OpenBat extracts them from the forwarded headers on the server side.