When building AI applications, you often need to track and analyze requests by different dimensions like project, feature, or workflow stage. Custom Properties let you tag LLM requests with metadata, enabling advanced filtering, cost analysis per user or feature, and performance tracking across different parts of your application.
Custom Properties appear as headers in the `Request` table.
Why use Custom Properties
Track unit economics : Calculate cost per user, conversation, or feature to understand your application’s profitability
Debug complex workflows : Group related requests in multi-step AI processes for easier troubleshooting
Analyze performance by segment : Compare latency and costs across different user types, features, or environments
Quick Start
Use headers to add Custom Properties to your LLM requests.
Define the Header
Name your header in the format Helicone-Property-[Name] where Name is the name of your custom property.
Define the Value
The value is a string that labels your request for this custom property. Here are some examples: Node.js
Python
cURL
Langchain (Python)
import { OpenAI } from "openai" ;
const client = new OpenAI ({
baseURL: "https://ai-gateway.helicone.ai" ,
apiKey: process . env . HELICONE_API_KEY ,
defaultHeaders: {
"Helicone-Property-Conversation" : "support_issue_2" ,
"Helicone-Property-App" : "mobile" ,
"Helicone-Property-Environment" : "production" ,
},
});
const response = await client . chat . completions . create ({
model: "gpt-4o-mini" ,
messages: [{ role: "user" , content: "Hello, how are you?" }]
});
Understanding Custom Properties
How Properties Work
Custom properties are metadata attached to each request that help you:
What they enable:
Filter requests in the dashboard by any property
Calculate costs and metrics grouped by properties
Export data segmented by custom dimensions
Set up alerts based on property values
Use Cases
Track performance and costs across different environments and deployments: import { OpenAI } from "openai" ;
const client = new OpenAI ({
baseURL: "https://ai-gateway.helicone.ai" ,
apiKey: process . env . HELICONE_API_KEY ,
});
// Production deployment
const response = await client . chat . completions . create (
{
model: "gpt-4o-mini" ,
messages: [{ role: "user" , content: "Process this customer request" }]
},
{
headers: {
"Helicone-Property-Environment" : "production" ,
"Helicone-Property-Version" : "v2.1.0" ,
"Helicone-Property-Region" : "us-east-1"
}
}
);
// Staging deployment with different version
const testResponse = await client . chat . completions . create (
{
model: "gpt-4o-mini" ,
messages: [{ role: "user" , content: "Test new feature" }]
},
{
headers: {
"Helicone-Property-Environment" : "staging" ,
"Helicone-Property-Version" : "v2.2.0-beta" ,
"Helicone-Property-Region" : "us-west-2"
}
}
);
// Compare performance and costs across environments
Configuration Reference
Custom properties use a simple header-based format:
Any custom metadata you want to track. Replace [Name] with your property name. Example: Helicone-Property-Environment: staging
Special reserved property for user tracking. Enables per-user cost analytics and usage metrics. See User Metrics for detailed tracking capabilities. Example: Helicone-User-Id: user-123
Advanced Features
Updating Properties After Request
You can update properties after a request is made using the REST API :
// Get the request ID from the response
const { data , response } = await client . chat . completions
. create ({ /* your request */ })
. withResponse ();
const requestId = response . headers . get ( "helicone-id" );
// Update properties via API
await fetch ( `https://api.helicone.ai/v1/request/ ${ requestId } /property` , {
method: "PUT" ,
headers: {
"Authorization" : `Bearer ${ HELICONE_API_KEY } ` ,
"Content-Type" : "application/json"
},
body: JSON . stringify ({
"Environment" : "production" ,
"PostProcessed" : "true"
})
});
Querying by Custom Properties
Once you’ve added custom properties to your requests, you can filter and retrieve requests using those properties via the Query API .
Important: When filtering by custom properties, you MUST wrap the properties filter inside a request_response_rmt object. Omitting this wrapper will return empty results.
Simple Property Filter
Filter requests by a single property value:
curl --request POST \
--url https://api.helicone.ai/v1/request/query-clickhouse \
--header "Content-Type: application/json" \
--header "authorization: Bearer $HELICONE_API_KEY " \
--data '{
"filter": {
"request_response_rmt": {
"properties": {
"Environment": {
"equals": "production"
}
}
}
},
"limit": 100
}'
Multiple Property Filters
Combine multiple property filters using AND/OR operators:
curl --request POST \
--url https://api.helicone.ai/v1/request/query-clickhouse \
--header "Content-Type: application/json" \
--header "authorization: Bearer $HELICONE_API_KEY " \
--data '{
"filter": {
"left": {
"request_response_rmt": {
"properties": {
"Environment": {
"equals": "production"
}
}
}
},
"operator": "and",
"right": {
"request_response_rmt": {
"properties": {
"App": {
"equals": "mobile"
}
}
}
}
},
"limit": 100
}'
Combining Properties with Other Filters
Filter by properties AND other criteria like date range or model:
curl --request POST \
--url https://api.helicone.ai/v1/request/query-clickhouse \
--header "Content-Type: application/json" \
--header "authorization: Bearer $HELICONE_API_KEY " \
--data '{
"filter": {
"left": {
"request_response_rmt": {
"request_created_at": {
"gte": "2024-01-01T00:00:00Z"
}
}
},
"operator": "and",
"right": {
"request_response_rmt": {
"properties": {
"Conversation": {
"equals": "support_issue_2"
}
}
}
}
},
"limit": 100
}'
Common Mistake
❌ WRONG - Properties without request_response_rmt wrapper
# This will return empty results even if data exists
curl --request POST \
--url https://api.helicone.ai/v1/request/query-clickhouse \
--header "Content-Type: application/json" \
--header "authorization: Bearer $HELICONE_API_KEY " \
--data '{
"filter": {
"properties": {
"Environment": {
"equals": "production"
}
}
}
}'
✅ CORRECT - Properties with request_response_rmt wrapper
# This will correctly return filtered results
curl --request POST \
--url https://api.helicone.ai/v1/request/query-clickhouse \
--header "Content-Type: application/json" \
--header "authorization: Bearer $HELICONE_API_KEY " \
--data '{
"filter": {
"request_response_rmt": {
"properties": {
"Environment": {
"equals": "production"
}
}
}
}
}'
See the full Query API documentation for more advanced filtering options.