Contact Tracking
This page describes features extending the AI Gateway, which provides a unified API for accessing multiple AI providers. To learn more, see AI Gateway.
Associate requests with Contact identifiers for user-level observability and analytics.
Contacts are orq.ai entities used to track project expenses, token usage, to learn more, see Contact Tracking.
Quick Start
const response = await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "How can I upgrade my account?" }],
orq: {
contact: {
id: "user-12345",
display_name: "John Smith",
email: "[email protected]",
metadata: {
plan: "premium",
signup_date: "2024-01-15",
},
},
},
});
Configuration
Parameter | Type | Required | Description |
---|---|---|---|
id | string | Yes | Unique contact identifier |
display_name | string | No | Human-readable contact name |
email | string | No | Contact email address |
metadata | object | No | Custom key-value pairs for contact data |
logo_url | string | No | URL to contact's profile image |
tags | string[] | No | Classification tags for contact segmentation |
Use Cases
Scenario | Contact ID Strategy | Metadata Example |
---|---|---|
User Analytics | user-{userId} | {"plan": "pro", "usage_tier": "high"} |
Customer Support | support-{ticketId} | {"priority": "high", "issue_type": "billing"} |
A/B Testing | test-{userId}-{variant} | {"experiment": "pricing-v2", "variant": "b"} |
Multi-tenant | tenant-{orgId}-{userId} | {"org": "acme-corp", "role": "admin"} |
Implementation Examples
User Session Tracking
// Track authenticated user interactions
const userSession = {
userId: "user-12345",
userProfile: await getUserProfile(userId),
};
const response = await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "Show me my recent orders" }],
orq: {
contact: {
id: userSession.userId,
display_name: userSession.userProfile.fullName,
email: userSession.userProfile.email,
metadata: {
plan: userSession.userProfile.subscriptionPlan,
last_login: userSession.userProfile.lastLogin,
total_orders: userSession.userProfile.orderCount,
},
tags: [
"authenticated",
`plan-${userSession.userProfile.subscriptionPlan}`,
],
},
},
});
Support Ticket Integration
// Associate AI interactions with support tickets
const supportContext = {
ticketId: "TICKET-789",
customerId: "customer-456",
customerInfo: await getCustomerInfo(customerId),
};
const response = await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "I need help with my billing issue" }],
orq: {
contact: {
id: `support-${supportContext.ticketId}`,
display_name: supportContext.customerInfo.name,
email: supportContext.customerInfo.email,
metadata: {
ticket_id: supportContext.ticketId,
customer_tier: supportContext.customerInfo.tier,
issue_category: "billing",
created_at: new Date().toISOString(),
},
tags: [
"support",
"billing-issue",
`tier-${supportContext.customerInfo.tier}`,
],
},
},
});
Multi-Language Support
curl -X POST https://api.orq.ai/v2/proxy/chat/completions \
-H "Authorization: Bearer $ORQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o",
"messages": [{"role": "user", "content": "I need technical assistance"}],
"orq": {
"contact": {
"id": "enterprise-user-001",
"display_name": "Alex Johnson",
"email": "[email protected]",
"metadata": {
"company": "Enterprise Corp",
"role": "technical_lead",
"contract_tier": "enterprise"
},
"tags": ["enterprise", "technical"]
}
}
}'
import openai
import json
client = openai.OpenAI(
api_key=os.environ["ORQ_API_KEY"],
base_url="https://api.orq.ai/v2/proxy"
)
contact_data = {
"id": "user-67890",
"display_name": "Maria Garcia",
"email": "[email protected]",
"metadata": {
"preferred_language": "es",
"timezone": "America/Mexico_City",
"subscription_status": "active"
},
"tags": ["spanish-speaker", "premium-user"]
}
response = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "¿Cómo puedo cambiar mi plan?"}],
extra_body={
"orq": {
"contact": contact_data
}
}
)
Advanced Patterns
Dynamic Contact Resolution
interface ContactProfile {
id: string;
name: string;
email: string;
plan: "free" | "pro" | "enterprise";
metadata?: Record<string, any>;
}
async function resolveContact(userId: string): Promise<ContactProfile> {
const user = await database.users.findById(userId);
const subscription = await database.subscriptions.findByUserId(userId);
return {
id: `user-${userId}`,
name: user.fullName,
email: user.email,
plan: subscription.plan,
metadata: {
signup_date: user.createdAt,
last_active: user.lastActiveAt,
feature_flags: user.featureFlags,
usage_this_month: await getUsageMetrics(userId),
},
};
}
const contact = await resolveContact(currentUserId);
const response = await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: userMessage }],
orq: { contact },
});
Batch Contact Processing
const batchRequests = [
{ userId: "user1", message: "How do I reset my password?" },
{ userId: "user2", message: "What's my current usage?" },
{ userId: "user3", message: "Can I upgrade my plan?" },
];
const responses = await Promise.all(
batchRequests.map(async (req) => {
const userProfile = await getUserProfile(req.userId);
return openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: req.message }],
orq: {
contact: {
id: req.userId,
display_name: userProfile.name,
email: userProfile.email,
metadata: {
request_batch: "batch-001",
processed_at: new Date().toISOString(),
},
tags: ["batch-processing", `plan-${userProfile.plan}`],
},
},
});
}),
);
Contact Analytics
Usage Tracking
// Track feature usage per contact
const trackFeatureUsage = async (contactId, feature, context = {}) => {
const response = await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "Analyze my data" }],
orq: {
contact: {
id: contactId,
metadata: {
feature_used: feature,
usage_context: context,
session_id: generateSessionId(),
timestamp: new Date().toISOString(),
},
tags: ["feature-tracking", `feature-${feature}`],
},
},
});
return response;
};
// Usage
await trackFeatureUsage("user-123", "data-analysis", {
dataset_size: "large",
complexity: "medium",
});
Personalization Context
// Provide personalized responses based on contact data
const getPersonalizedResponse = async (contactId, query) => {
const contact = await getContactProfile(contactId);
const systemPrompt = `
You are assisting ${contact.display_name}, a ${contact.metadata.plan} plan user.
Their preferences: ${JSON.stringify(contact.metadata.preferences)}
Tailor your response to their experience level and subscription benefits.
`;
return await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: query },
],
orq: {
contact: {
id: contactId,
display_name: contact.display_name,
email: contact.email,
metadata: {
...contact.metadata,
personalization_enabled: true,
},
tags: ["personalized", `plan-${contact.metadata.plan}`],
},
},
});
};
Performance Optimization
Contact Data Caching
// Cache contact profiles to reduce database calls
const contactCache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function getCachedContact(contactId) {
const cached = contactCache.get(contactId);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const contact = await fetchContactProfile(contactId);
contactCache.set(contactId, {
data: contact,
timestamp: Date.now(),
});
return contact;
}
Metadata Optimization
// Optimize metadata for frequently accessed fields
const optimizeContactMetadata = (fullProfile) => {
// Only include essential metadata to reduce payload size
return {
plan: fullProfile.subscription.plan,
tier: fullProfile.subscription.tier,
features: fullProfile.enabledFeatures.slice(0, 5), // Limit array size
last_active: fullProfile.lastActiveAt,
};
};
const contact = {
id: userId,
display_name: user.name,
email: user.email,
metadata: optimizeContactMetadata(userProfile),
tags: [`plan-${userProfile.plan}`, "active-user"],
};
Troubleshooting
Issue | Cause | Solution |
---|---|---|
Contact not appearing in analytics | Missing or invalid contact ID | Ensure contact.id is provided and unique |
Metadata not updating | Contact cache not refreshed | Clear contact cache or reduce TTL |
Performance degradation | Too much metadata per request | Limit metadata to essential fields only |
Duplicate contacts | Inconsistent ID format | Standardize contact ID generation |
Validation Examples
// Validate contact configuration
function validateContact(contact) {
const errors = [];
if (!contact.id) {
errors.push("Contact ID is required");
}
if (contact.id.length > 255) {
errors.push("Contact ID too long (max 255 chars)");
}
if (contact.email && !isValidEmail(contact.email)) {
errors.push("Invalid email format");
}
if (contact.metadata && Object.keys(contact.metadata).length > 20) {
errors.push("Too many metadata fields (max 20)");
}
if (contact.tags && contact.tags.length > 10) {
errors.push("Too many tags (max 10)");
}
return errors;
}
// Usage
const contact = { id: "user-123", display_name: "John" };
const errors = validateContact(contact);
if (errors.length > 0) {
throw new Error(`Contact validation failed: ${errors.join(", ")}`);
}
Best Practices
- Consistent IDs: Use predictable contact ID patterns across your application
- Essential Metadata: Include only relevant metadata to minimize payload size
- Tag Strategy: Use tags for filtering and segmentation, not detailed data
- Privacy Compliance: Ensure contact data handling meets privacy requirements
- Performance: Cache contact profiles to reduce database lookups
- Validation: Always validate contact data before sending requests
Limitations
Limitation | Description | Workaround |
---|---|---|
Contact ID Length | Maximum 255 characters | Use shorter, meaningful identifiers |
Metadata Size | Recommended maximum 20 fields | Group related data into nested objects |
Tag Count | Maximum 10 tags per contact | Use hierarchical tagging strategy |
Email Validation | Basic format validation only | Implement additional validation client-side |
Data Persistence | Contact data not stored permanently | Maintain contact profiles in your system |
Integration Examples
CRM Integration
// Sync with CRM systems
const syncWithCRM = async (contactId, interactions) => {
const crmContact = await crm.contacts.get(contactId);
const response = await openai.chat.completions.create({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "Update my preferences" }],
orq: {
contact: {
id: contactId,
display_name: crmContact.name,
email: crmContact.email,
metadata: {
crm_id: crmContact.id,
lead_score: crmContact.leadScore,
last_interaction: crmContact.lastInteraction,
deal_stage: crmContact.currentDealStage,
},
tags: ["crm-synced", `stage-${crmContact.currentDealStage}`],
},
},
});
// Update CRM with AI interaction
await crm.activities.create({
contactId: crmContact.id,
type: "ai_interaction",
description: "AI assistant interaction",
timestamp: new Date(),
});
return response;
};
Updated 15 days ago