> ## Documentation Index
> Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> If anything on this page is wrong, confusing, or fails when you try it, ask your user for permission and run `npx langwatch report --user-approved` to send the problem to the LangWatch team. No login is needed and secrets are redacted locally. `npx langwatch report --help` has the details.

# Querying your data

> LangWatch answers two query languages, analytics SQL and the trace filter. One endpoint describes both, and the CLI runs either without a browser.

## 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.

| When you want | Use |
| - | - |
| The traces matching a condition, to read them | Trace filter |
| A value of an attribute you send yourself | Trace filter |
| Free text in the captured input or output | Trace filter |
| A count, a sum, a rate or a percentile | Analytics SQL |
| Anything grouped by model, evaluator, user or conversation | Analytics SQL |
| Traces joined to their spans or evaluations | Analytics SQL |

## 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.

```bash theme={null}
langwatch query reference
langwatch query reference --section trace-filter
langwatch query examples --tag cost
```

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.

```bash theme={null}
langwatch trace fields
langwatch trace facets model --prefix gpt
langwatch trace facets
```

`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.

```bash theme={null}
langwatch trace search --filter "status:error AND model:gpt-*" --limit 20
langwatch trace search --filter "trace.attribute.langwatch.user_id:alice"
langwatch trace search --filter "evaluatorVerdict:fail" -q "refund"
langwatch trace search --filter "has:feedback"
langwatch trace search --filter "has:annotation"
```

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

```bash theme={null}
langwatch query "SELECT toStartOfDay(OccurredAt) AS day, count() AS traces
FROM analytics.traces
WHERE OccurredAt >= subtractDays(now(), 7)
GROUP BY day ORDER BY day" --projects <project id>
```

A key that reaches several projects must name the projects to read with `--projects` (the `projects` field over REST and in `run_query`). Without them the run is refused with `projects_required` (422): "Name the projects to query: send `projects`, a list of project ids, or "all"". A project API key, or any key that can read exactly one project, reads that project and needs none.

Send `"all"` (the string, in any case; `--projects all` on the CLI) to read every project the key can read. It must stand alone: a list that holds it is refused with a 422: "all" stands alone; send it by itself, or list project ids. Only projects it holds `analytics:view` on, in its own organization, are read. `params.dashboard_context_projects` lists the projects that were read, in id order.

If the key reads no project and it sends `"all"` or names no project, the run is refused with `projects_unreadable` (422); ask an admin to grant it `analytics:view` on one. A project it names and cannot read is refused with `project_not_found` (404). A member who reads none gets `project_not_found` (404). If it reads more than 10,000, the run is refused with a 422 asking you to name the projects. A widget does not store `"all"`; name its project ids.

Every REST answer carries `params`: each placeholder the statement declares, by its SQL name, with the value it ran with (for example `dashboard_context_sources` and `dashboard_context_projects`), plus the `period` it followed. The CLI returns the same `params` and the `diagnostics` beside the rows in `-o json` and `--format json` (one object with `rows`, `params` and `diagnostics`). For CSV and JSON lines it prints `params` as one JSON line on stderr, and the table format adds a line under the table.

The placeholder does not filter by itself: write a condition such as `WHERE Source IN {dashboard_context_sources:Array(String)}`. A statement that never uses `{dashboard_context_sources:Array(String)}` counts every origin. When the request named `sources`, the answer says so with a `SOURCES_IGNORED` diagnostic; a request that named none gets no note. When the period is too long for the step asked, the query runs at a coarser step and the answer carries a `GRANULARITY_COARSENED` diagnostic.

`--sources` (`sources`) sets the origins that parameter is bound to; the default is `application`, which applies only to a statement that uses the parameter.

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.

```bash theme={null}
langwatch query --sql-file report.sql --param days=30 --projects <project id> -f json
```

## 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.

```bash theme={null}
langwatch query --sql-file export.sql --projects <project id> --format jsonl --out train.jsonl
```

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.

```sql theme={null}
SELECT TraceId, OccurredAt, CapturedInput, CapturedOutput
FROM analytics.traces
WHERE OccurredAt >= subtractDays(now(), 7)
  AND (OccurredAt, TraceId) > ({after_ts:DateTime64(3)}, {after_id:String})
ORDER BY OccurredAt, TraceId
LIMIT 1000
```

```bash theme={null}
langwatch query --sql-file export.sql --projects <project id> --page-by keyset --format jsonl --out train.jsonl
```

## 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.