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

String Operators

1// Exact match
2'name = "greeting-prompt"';
3
4// Not equal
5'name != "old-prompt"';
6
7// Contains substring (case-insensitive)
8'name contains "greeting"';
9
10// Does not contain substring
11'name not_contains "deprecated"';
12
13// Starts with prefix
14'name starts_with "prod-"';
15
16// Ends with suffix
17'name ends_with "-v2"';

Comparison Operators

1// Greater than (alphabetical for strings, numeric for numbers)
2'name > "m"'; // Names starting with n-z
3'duration > 300'; // Threads longer than 300 seconds
4
5// Less than (alphabetical for strings, numeric for numbers)
6'name < "m"'; // Names starting with a-l
7'number_of_messages < 5'; // Threads with fewer than 5 messages
8
9// Greater than or equal
10'feedback_scores.quality >= 0.8';
11
12// Less than or equal
13'duration <= 600';

Numeric Operators

1// Equality
2'number_of_messages = 3';
3
4// Not equal
5'duration != 0';
6
7// Check if field is empty
8'feedback_scores.quality is_empty';
9
10// Check if field is not empty
11'feedback_scores.quality is_not_empty';

DateTime Operators

1// Use ISO 8601 format for dates
2'start_time >= "2024-01-01T00:00:00Z"';
3'end_time < "2024-12-31T23:59:59Z"';

List Operators

1// Check if list contains value
2'tags contains "production"';
3
4// Check if list does not contain value
5'tags not_contains "experimental"';

Combining Conditions

Use AND to combine multiple filter conditions. All conditions must be true for a result to match:

1// Multiple conditions with AND
2'tags contains "production" AND name contains "greeting" AND created_by = "user@example.com"';
3
4// Complex multi-field filtering
5'name starts_with "prod-" AND tags contains "stable" AND name not_contains "deprecated"';

Currently, only AND logic is supported. OR logic is not available in OQL.

Examples

Searching Prompts

1import { Opik } from "opik";
2
3const client = new Opik();
4
5// Filter by single tag
6const prod = await client.searchPrompts('tags contains "production"');
7
8// Combine name pattern and tag
9const approved = await client.searchPrompts(
10 'name starts_with "prod-" AND tags contains "qa-approved"'
11);
12
13// Multiple conditions
14const results = await client.searchPrompts(
15 'created_by = "user@example.com" AND tags contains "production" AND name not_contains "deprecated"'
16);

Searching Threads

1import { Opik } from "opik";
2
3const client = new Opik();
4
5// Filter by status
6const activeThreads = await client.searchThreads({
7 projectName: "my-project",
8 filterString: 'status = "active"'
9});
10
11// Filter by duration and message count
12const longConversations = await client.searchThreads({
13 projectName: "my-project",
14 filterString: 'duration > 300 AND number_of_messages >= 5'
15});
16
17// Filter by feedback score
18const highQualityThreads = await client.searchThreads({
19 projectName: "my-project",
20 filterString: 'feedback_scores.quality > 0.8'
21});
22
23// Filter by empty feedback score
24const unratedThreads = await client.searchThreads({
25 projectName: "my-project",
26 filterString: 'feedback_scores.quality is_empty'
27});
28
29// Filter by tags and metadata
30const importantProdThreads = await client.searchThreads({
31 projectName: "my-project",
32 filterString: 'tags contains "important" AND metadata.environment = "production"'
33});
34
35// Filter by date range
36const recentThreads = await client.searchThreads({
37 projectName: "my-project",
38 filterString: 'start_time >= "2024-01-01T00:00:00Z"'
39});

Searching Traces

1import { Opik } from "opik";
2
3const client = new Opik();
4
5// Filter by metadata
6const traces = await client.searchTraces({
7 projectName: "my-project",
8 filterString: 'metadata.model = "gpt-5"'
9});
10
11// Filter by feedback scores
12const goodTraces = await client.searchTraces({
13 projectName: "my-project",
14 filterString: 'feedback_scores.accuracy > 0.9'
15});

The same OQL syntax works across all search methods (searchPrompts(), searchTraces(), searchThreads()). Specific resource types may support additional fields - see their respective documentation for available columns.

Syntax Rules

String Values

Always wrap string values in double quotes:

1// ✅ Correct - double quotes around values
2await client.searchPrompts('name = "my-prompt"');
3await client.searchPrompts('tags contains "production"');
4
5// ❌ Incorrect - missing quotes
6await client.searchPrompts("name = my-prompt"); // Will fail
7
8// ❌ Incorrect - single quotes
9await client.searchPrompts("name = 'my-prompt'"); // Will fail

Error Handling

1try {
2 const results = await client.searchPrompts("invalid syntax ===");
3} catch (error) {
4 console.error("Invalid OQL syntax:", error.message);
5}

Best Practices

  1. Use descriptive tag hierarchies - Structure tags like "production", "staging", "team-alpha" for effective filtering
  2. Use naming conventions - Implement consistent naming patterns (e.g., "prod-" prefix) to enable powerful filtering
  3. Handle errors - Always wrap OQL queries in try-catch blocks to handle syntax errors gracefully