Skip to main content

Which language answers which question

The trace filter finds traces. It is the language the Trace Explorer’s search bar speaks, it returns whole traces with their spans and evaluations, and it reaches attribute keys, span events and evaluator verdicts. Analytics SQL (LangWatchQL) answers questions about many traces at once: a count, a rate, a percentile, any of them grouped or over time, and joins across views. It returns columns, not traces.

One reference for both

GET /api/v1/query/reference describes both languages in one payload: the SQL views and columns, the filter fields and syntax, worked examples in each, and the decision table above. Every example goes through the real validator and the real translator on every build, so a published example is never one the API would refuse on sight. Whether your key can run a given example is a separate question, and each example answers it. available is false when a column it reads is withheld from you, and requires says what it would take.
The reference carries no values from your project. Values change under you and reading them all is expensive, so they come from a separate call.
trace fields lists what you can filter on. trace facets says what those fields hold in your project right now, which is the question to ask before guessing how a value is spelled.

Filtering traces

Send the filter string as filter on POST /api/traces/search, or pass --filter to the CLI. It combines with the free-text query and the other options, so every condition you send has to hold.
Three namespaces reach arbitrary OpenTelemetry attributes: trace.attribute.<key>, span.attribute.<key> and event.attribute.<key>. The older attribute.<key> and event.<key> spellings still work. A filter naming a field the language does not have answers 422 and names both the offending field and the fields that exist.

Running analytics SQL

The statement runs exactly as submitted. Filter on the dataset’s time column, as every example does: without that predicate the read touches every partition your project has, including the cold ones. --sql-file reads the statement from a file, --param key=value binds a parameter the statement declares, and --start with --end fills the reserved period parameters.

Exporting rows

--format jsonl writes one JSON object per row and parses JSON-typed columns back into real values, which is the shape a training-data reader expects. --format csv writes a header row with RFC 4180 escaping. --out writes to a file.
The query endpoint has no cursor of its own, so a result larger than one response pages through a predicate you write. Declare the two cursor parameters, order by the same two columns, and --page-by keyset rebinds them between pages without changing a character of your statement.

From an MCP client

discover_schema answers the same two descriptions, as markdown: category filters for the trace filter, lwql for the analytics SQL, all for everything. run_query runs a statement and renders up to 50 rows as a table, saying how many the statement really returned. search_traces takes the same filter string the REST endpoint does.

Permissions

Both query doors need analytics:view; the trace search and the facets endpoint need traces:view. A column your key cannot read is listed with available: false and names the permission it needs, rather than being hidden, so you can see what a wider key would reach.
Last modified on September 18, 2026