Advanced Guides

Metadata & Filtering

Attach custom key-value data to conversations for user segmentation, campaign tracking, internal ID mapping, and advanced filtering.

Metadata lets you attach custom key-value pairs to conversations. This is how you connect Chatsby conversations to your own systems — associate a conversation with an internal user ID, tag it with a marketing campaign, flag it for A/B testing, or add any context your application needs.

What Metadata Is

Metadata is a flat JSON object of string key-value pairs stored on a conversation resource. It is not visible to the end user or the AI agent — it is exclusively for your application's use.

{
  "user_id": "usr_12345",
  "plan": "premium",
  "source_campaign": "winter_sale",
  "experiment_group": "variant_b"
}

Metadata is:

  • Stored on the conversation object and returned in all API responses that include the conversation.
  • Filterable via the List Conversations endpoint, so you can query conversations by any metadata value.
  • Immutable after creation on the current API version. Set metadata when creating the conversation. Update support is planned for a future release.

Attaching Metadata

Include the metadata object when sending the first message of a new conversation. Metadata is only applied when a new conversation is created — it is ignored if you provide a conversation_id for an existing conversation.

cURL

curl -X POST https://api.chatsby.co/v1/conversations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agent_1a2b3c4d5e",
    "message": "I need help with my order.",
    "metadata": {
      "user_id": "usr_12345",
      "plan": "premium",
      "source_campaign": "winter_sale",
      "order_id": "ord_98765"
    }
  }'

JavaScript

const response = await fetch('https://api.chatsby.co/v1/conversations', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    agent_id: 'agent_1a2b3c4d5e',
    message: 'I need help with my order.',
    metadata: {
      user_id: 'usr_12345',
      plan: 'premium',
      source_campaign: 'winter_sale',
      order_id: 'ord_98765',
    },
  }),
});
 
const data = await response.json();
// data.conversation_id contains the new conversation with metadata attached

Python

import requests
 
response = requests.post(
    "https://api.chatsby.co/v1/conversations",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "agent_id": "agent_1a2b3c4d5e",
        "message": "I need help with my order.",
        "metadata": {
            "user_id": "usr_12345",
            "plan": "premium",
            "source_campaign": "winter_sale",
            "order_id": "ord_98765",
        },
    },
)
 
data = response.json()
print(data["conversation_id"])

Node.js SDK

import { Chatsby } from '@chatsby/sdk';
 
const chatsby = new Chatsby({ apiKey: process.env.CHATSBY_API_KEY });
 
const result = await chatsby.conversations.create({
  agent_id: 'agent_1a2b3c4d5e',
  message: 'I need help with my order.',
  metadata: {
    user_id: 'usr_12345',
    plan: 'premium',
    source_campaign: 'winter_sale',
  },
});

Metadata Limits

ConstraintLimit
Maximum number of keys20 per conversation
Key length1-40 characters
Value length1-500 characters
Key charactersLowercase letters, numbers, and underscores only ([a-z0-9_])
Value charactersAny UTF-8 string

If you exceed these limits, the API returns a 422 Unprocessable Entity error:

{
  "error": {
    "type": "validation_error",
    "message": "Metadata cannot have more than 20 keys. Received 23.",
    "code": "metadata_limit_exceeded",
    "param": "metadata",
    "status": 422
  }
}

Filtering Conversations by Metadata

The List Conversations endpoint supports filtering by metadata values. Pass metadata filters as query parameters in the format metadata=key:value.

Single filter

curl "https://api.chatsby.co/v1/agents/agent_1a2b3c4d5e/conversations?metadata=plan:premium" \
  -H "Authorization: Bearer YOUR_API_KEY"

Multiple filters (AND logic)

When you provide multiple metadata filters, they are combined with AND logic — only conversations matching all filters are returned.

curl "https://api.chatsby.co/v1/agents/agent_1a2b3c4d5e/conversations?metadata=plan:premium&metadata=source_campaign:winter_sale" \
  -H "Authorization: Bearer YOUR_API_KEY"

JavaScript

const params = new URLSearchParams();
params.append('metadata', 'plan:premium');
params.append('metadata', 'source_campaign:winter_sale');
params.append('page_size', '50');
 
const response = await fetch(
  `https://api.chatsby.co/v1/agents/agent_1a2b3c4d5e/conversations?${params}`,
  { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
 
const { data, has_more, next_cursor } = await response.json();
console.log(`Found ${data.length} matching conversations`);

Python

response = requests.get(
    "https://api.chatsby.co/v1/agents/agent_1a2b3c4d5e/conversations",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    params=[
        ("metadata", "plan:premium"),
        ("metadata", "source_campaign:winter_sale"),
        ("page_size", "50"),
    ],
)
 
data = response.json()
print(f"Found {len(data['data'])} matching conversations")

Combining metadata filters with date filters

Metadata filters work alongside other query parameters:

curl "https://api.chatsby.co/v1/agents/agent_1a2b3c4d5e/conversations?metadata=plan:premium&created_after=2025-03-01T00:00:00Z&created_before=2025-03-31T23:59:59Z&page_size=100" \
  -H "Authorization: Bearer YOUR_API_KEY"

Use Cases

User segmentation

Map conversations to your internal user system to track which users are engaging with the agent and what they are asking about.

{
  "metadata": {
    "user_id": "usr_12345",
    "plan": "enterprise",
    "team": "engineering"
  }
}

Then pull all conversations for a specific user:

curl "https://api.chatsby.co/v1/agents/agent_1a2b3c4d5e/conversations?metadata=user_id:usr_12345" \
  -H "Authorization: Bearer YOUR_API_KEY"

Campaign tracking

Tag conversations that originate from marketing campaigns to measure engagement and conversion.

{
  "metadata": {
    "source_campaign": "spring_launch_2025",
    "utm_source": "google",
    "utm_medium": "cpc",
    "landing_page": "/products/new"
  }
}

A/B testing

Run experiments by tagging conversations with variant identifiers and comparing outcomes.

{
  "metadata": {
    "experiment_id": "exp_welcome_message",
    "variant": "b",
    "cohort": "2025_q1"
  }
}

After the experiment, query each variant to analyze results:

// Get conversations for variant A
const variantA = await fetchConversations({
  metadata: ['experiment_id:exp_welcome_message', 'variant:a'],
});
 
// Get conversations for variant B
const variantB = await fetchConversations({
  metadata: ['experiment_id:exp_welcome_message', 'variant:b'],
});
 
console.log(`Variant A: ${variantA.length} conversations`);
console.log(`Variant B: ${variantB.length} conversations`);

Internal ID mapping

Connect Chatsby conversations to records in your CRM, helpdesk, or database.

{
  "metadata": {
    "crm_contact_id": "sf_003abc",
    "helpdesk_ticket_id": "zendesk_12345",
    "session_id": "sess_abc123def456"
  }
}

Multi-tenant applications

If you are building a SaaS product on top of Chatsby, use metadata to isolate conversations by tenant.

{
  "metadata": {
    "tenant_id": "tenant_acme",
    "tenant_plan": "business",
    "end_user_id": "eu_789"
  }
}

Best Practices

Use consistent naming conventions. Stick to snake_case for all metadata keys. Establish a naming scheme and document it for your team.

ConventionExample
Internal IDsuser_id, order_id, tenant_id
Trackingsource_campaign, utm_source, referrer_url
Segmentationplan, team, region
Experimentationexperiment_id, variant, cohort

Avoid storing PII in metadata. Do not store personally identifiable information like email addresses, phone numbers, or full names in metadata. Use opaque identifiers (like internal user IDs) and look up the PII in your own system when needed. Metadata values may appear in API logs and dashboard views.

Keep values short and categorical. Metadata is designed for filtering and grouping, not for storing large blobs of data. Use short, categorical values that you will actually filter on.

Plan your metadata schema upfront. Since metadata is currently immutable after conversation creation, decide what data you need before the conversation starts. Missing metadata cannot be added retroactively.

Metadata filtering uses exact string matching. The filter metadata=plan:premium matches conversations where the plan key is exactly "premium". Partial matches, wildcards, and regex are not supported.

Do not use metadata for data that changes. Since metadata is set at conversation creation and cannot be updated, avoid storing values that may change during the conversation lifecycle (e.g., conversation status, resolution state). Use your own database for mutable state and reference the Chatsby conversation ID.