Opik Query Language (OQL)
OQL provides a powerful, SQL-like syntax for filtering data in Opik. It's used with various SDK methods like searchPrompts(), searchTraces(), and searchThreads() to find exactly the data you need using expressive filter conditions.
Operators
Section titled “Operators”String Operators
Section titled “String Operators”// Exact match
'name = "greeting-prompt"';
// Not equal
'name != "old-prompt"';
// Contains substring (case-insensitive)
'name contains "greeting"';
// Does not contain substring
'name not_contains "deprecated"';
// Starts with prefix
'name starts_with "prod-"';
// Ends with suffix
'name ends_with "-v2"';Comparison Operators
Section titled “Comparison Operators”// Greater than (alphabetical for strings, numeric for numbers)
'name > "m"'; // Names starting with n-z
'duration > 300'; // Threads longer than 300 seconds
// Less than (alphabetical for strings, numeric for numbers)
'name < "m"'; // Names starting with a-l
'number_of_messages < 5'; // Threads with fewer than 5 messages
// Greater than or equal
'feedback_scores.quality >= 0.8';
// Less than or equal
'duration <= 600';Numeric Operators
Section titled “Numeric Operators”// Equality
'number_of_messages = 3';
// Not equal
'duration != 0';
// Check if field is empty
'feedback_scores.quality is_empty';
// Check if field is not empty
'feedback_scores.quality is_not_empty';DateTime Operators
Section titled “DateTime Operators”// Use ISO 8601 format for dates
'start_time >= "2024-01-01T00:00:00Z"';
'end_time < "2024-12-31T23:59:59Z"';Enum Operators
Section titled “Enum Operators”Used for fields with a fixed set of values, such as environment:
// Exact match
'environment = "production"';
// Not equal
'environment != "development"';
// Match any of a set of values
'environment in ("production", "staging")';
// Exclude a set of values
'environment not_in ("development", "local")';List Operators
Section titled “List Operators”// Check if list contains value
'tags contains "production"';
// Check if list does not contain value
'tags not_contains "experimental"';Combining Conditions
Section titled “Combining Conditions”Use AND to combine multiple filter conditions. All conditions must be true for a result to match:
// Multiple conditions with AND
'tags contains "production" AND name contains "greeting" AND created_by = "user@example.com"';
// Complex multi-field filtering
'name starts_with "prod-" AND tags contains "stable" AND name not_contains "deprecated"';Examples
Section titled “Examples”Searching Prompts
Section titled “Searching Prompts”import { Opik } from "opik";
const client = new Opik();
// Filter by single tag
const prod = await client.searchPrompts('tags contains "production"');
// Combine name pattern and tag
const approved = await client.searchPrompts(
'name starts_with "prod-" AND tags contains "qa-approved"'
);
// Multiple conditions
const results = await client.searchPrompts(
'created_by = "user@example.com" AND tags contains "production" AND name not_contains "deprecated"'
);Searching Threads
Section titled “Searching Threads”import { Opik } from "opik";
const client = new Opik();
// Filter by status
const activeThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'status = "active"'
});
// Filter by duration and message count
const longConversations = await client.searchThreads({
projectName: "my-project",
filterString: 'duration > 300 AND number_of_messages >= 5'
});
// Filter by feedback score
const highQualityThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'feedback_scores.quality > 0.8'
});
// Filter by empty feedback score
const unratedThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'feedback_scores.quality is_empty'
});
// Filter by environment
const prodThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'environment = "production"'
});
// Filter by multiple environments
const stagingOrProdThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'environment in ("production", "staging")'
});
// Filter by tags and metadata
const importantProdThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'tags contains "important" AND metadata.environment = "production"'
});
// Filter by date range
const recentThreads = await client.searchThreads({
projectName: "my-project",
filterString: 'start_time >= "2024-01-01T00:00:00Z"'
});Searching Traces
Section titled “Searching Traces”import { Opik } from "opik";
const client = new Opik();
// Filter by metadata
const traces = await client.searchTraces({
projectName: "my-project",
filterString: 'metadata.model = "gpt-5"'
});
// Filter by feedback scores
const goodTraces = await client.searchTraces({
projectName: "my-project",
filterString: 'feedback_scores.accuracy > 0.9'
});
// Filter by environment
const prodTraces = await client.searchTraces({
projectName: "my-project",
filterString: 'environment = "production"'
});
// Combine environment with other filters
const goodProdTraces = await client.searchTraces({
projectName: "my-project",
filterString: 'environment = "production" AND feedback_scores.accuracy > 0.9'
});Syntax Rules
Section titled “Syntax Rules”String Values
Section titled “String Values”Always wrap string values in double quotes:
// ✅ Correct - double quotes around values
await client.searchPrompts('name = "my-prompt"');
await client.searchPrompts('tags contains "production"');
// ❌ Incorrect - missing quotes
await client.searchPrompts("name = my-prompt"); // Will fail
// ❌ Incorrect - single quotes
await client.searchPrompts("name = 'my-prompt'"); // Will failError Handling
Section titled “Error Handling”try {
const results = await client.searchPrompts("invalid syntax ===");
} catch (error) {
console.error("Invalid OQL syntax:", error.message);
}Best Practices
Section titled “Best Practices”- Use descriptive tag hierarchies - Structure tags like
"production","staging","team-alpha"for effective filtering - Use naming conventions - Implement consistent naming patterns (e.g.,
"prod-"prefix) to enable powerful filtering - Handle errors - Always wrap OQL queries in try-catch blocks to handle syntax errors gracefully