---
source: Jupyter Notebook
title: Query Langfuse Data with Metrics API v2
sidebarTitle: Metrics API v2
description: Learn how to query Langfuse Metrics API v2 from a Jupyter notebook to analyze observations and scores with practical examples.
category: Examples
---

# Query Langfuse Data with Metrics API v2

This notebook shows how to query the [Langfuse Metrics API v2](https://langfuse.com/docs/metrics/features/metrics-api#v2) from Python to build custom analytics on observations and scores.

We will cover three practical examples:

- Most expensive models over a time window
- Daily request volume and latency trends
- Numeric evaluation scores grouped by score name

> **Note:** Metrics API v2 is currently available on **Langfuse Cloud**. Depending on your SDK version, newly ingested data may take a few minutes to appear in the v2 endpoints.

## Step 1: Install packages

We use `requests` for the API calls, `pandas` for tabular analysis, and `matplotlib` for a quick chart.

```python
%pip install --upgrade requests pandas matplotlib

```

## Step 2: Configure credentials

Get your API keys from your Langfuse project settings in [Langfuse Cloud](https://langfuse.com/cloud). The Metrics API v2 uses HTTP Basic Auth with your public key as the username and your secret key as the password.

```python
import os

os.environ.setdefault("LANGFUSE_PUBLIC_KEY", "pk-lf-...");
os.environ.setdefault("LANGFUSE_SECRET_KEY", "sk-lf-...");
os.environ.setdefault("LANGFUSE_BASE_URL", "https://cloud.langfuse.com");  # EU region
# os.environ.setdefault("LANGFUSE_BASE_URL", "https://us.cloud.langfuse.com")  # US region

```

## Step 3: Build a small query helper

The API expects a JSON query object under the `query` parameter. This helper keeps the examples compact and converts the response into a `DataFrame`.

```python
import json
import os
from datetime import datetime, timedelta, timezone

import pandas as pd
import requests
from requests.auth import HTTPBasicAuth

LANGFUSE_PUBLIC_KEY = os.environ["LANGFUSE_PUBLIC_KEY"]
LANGFUSE_SECRET_KEY = os.environ["LANGFUSE_SECRET_KEY"]
LANGFUSE_BASE_URL = os.environ.get("LANGFUSE_BASE_URL", "https://cloud.langfuse.com")


def run_metrics_query(query: dict) -> pd.DataFrame:
    response = requests.get(
        f"{LANGFUSE_BASE_URL}/api/public/v2/metrics",
        params={"query": json.dumps(query)},
        auth=HTTPBasicAuth(LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY),
        timeout=30,
    )
    response.raise_for_status()
    payload = response.json()
    df = pd.DataFrame(payload.get("data", []))

    numeric_prefixes = ("count_", "sum_", "avg_", "p50_", "p75_", "p90_", "p95_", "p99_", "min_", "max_")

    for col in df.columns:
        if col.startswith(numeric_prefixes):
            df[col] = pd.to_numeric(df[col], errors="coerce")

    return df


now = datetime.now(timezone.utc)
seven_days_ago = now - timedelta(days=7)

print("Query window:", seven_days_ago.isoformat(), "to", now.isoformat())

```

## Step 4: Query the most expensive models

This example groups observation data by `providedModelName` and sums `totalCost`.

```python
cost_by_model_query = {
    "view": "observations",
    "metrics": [{"measure": "totalCost", "aggregation": "sum"}],
    "dimensions": [{"field": "providedModelName"}],
    "filters": [],
    "fromTimestamp": seven_days_ago.isoformat(),
    "toTimestamp": now.isoformat(),
    "orderBy": [{"field": "sum_totalCost", "direction": "desc"}],
    "config": {"row_limit": 10},
}

cost_by_model_df = run_metrics_query(cost_by_model_query)
cost_by_model_df

```

## Step 5: Plot daily request volume and latency

Next, we group observations by day and calculate both request count and p95 latency so you can spot traffic and performance changes together.

```python
volume_and_latency_query = {
    "view": "observations",
    "metrics": [
        {"measure": "count", "aggregation": "count"},
        {"measure": "latency", "aggregation": "p95"},
    ],
    "dimensions": [],
    "filters": [],
    "timeDimension": {"granularity": "day"},
    "fromTimestamp": seven_days_ago.isoformat(),
    "toTimestamp": now.isoformat(),
    "orderBy": [{"field": "time_dimension", "direction": "asc"}],
    "config": {"row_limit": 100},
}

volume_and_latency_df = run_metrics_query(volume_and_latency_query)
volume_and_latency_df

```

```python
if not volume_and_latency_df.empty:
    plot_df = volume_and_latency_df.copy()
    plot_df["time_dimension"] = pd.to_datetime(plot_df["time_dimension"])
    plot_df = plot_df.set_index("time_dimension")

    ax = plot_df[["count_count", "p95_latency"]].plot(
        subplots=True,
        figsize=(10, 6),
        title=["Daily request volume", "Daily p95 latency (ms)"],
        legend=False,
        marker="o",
    )
else:
    print("No observations returned for the selected time window.")

```

## Step 6: Analyze numeric evaluation scores

The `scores-numeric` view is useful for aggregating user feedback, evaluator outputs, or experiment results. This example groups by score name and computes the average score.

```python
score_summary_query = {
    "view": "scores-numeric",
    "metrics": [
        {"measure": "value", "aggregation": "avg"},
        {"measure": "count", "aggregation": "count"},
    ],
    "dimensions": [{"field": "name"}],
    "filters": [],
    "fromTimestamp": seven_days_ago.isoformat(),
    "toTimestamp": now.isoformat(),
    "orderBy": [{"field": "avg_value", "direction": "desc"}],
    "config": {"row_limit": 20},
}

score_summary_df = run_metrics_query(score_summary_query)
score_summary_df

```

## Next steps

You can adapt the same helper for other v2 views such as `scores-categorical`, add filters on fields like environment or trace name, or export the resulting `DataFrame` for downstream reporting.

To explore the full query schema and supported fields, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api#v2) and the [API reference](https://api.reference.langfuse.com/#tag/metrics/GET/api/public/v2/metrics).

<!-- agent-instructions -->

---

## Agent Instructions

This page is part of the [Langfuse](https://langfuse.com) documentation, published as plain Markdown for AI agents. Every page is available as Markdown by appending `.md` to its URL, or by sending an `Accept: text/markdown` header. This page: `https://langfuse.com/guides/cookbook/example_metrics_api_v2.md`.

### Querying these docs

If the answer is not on this page, query the documentation instead of guessing:

- **Semantic search** across all Langfuse docs, returning an answer with the relevant pages and excerpts. Ask a specific, self-contained question:

  ```bash
  curl -sG "https://langfuse.com/api/search-docs" --data-urlencode "query=How do I trace a LangGraph agent?"
  ```

- **Index of every page**: <https://langfuse.com/llms.txt>, with per-section indexes [llms-docs.txt](https://langfuse.com/llms-docs.txt), [llms-integrations.txt](https://langfuse.com/llms-integrations.txt), and [llms-self-hosting.txt](https://langfuse.com/llms-self-hosting.txt).

### Before writing Langfuse code

- **Install the [Langfuse Agent Skill](https://langfuse.com/docs/api-and-data-platform/features/agent-skill).** It encodes Langfuse's own best practices for instrumentation, prompt management, and evaluation, and materially improves results.
- **Read [What does a good trace look like?](https://langfuse.com/docs/observability/best-practices.md)** before instrumenting an application.
- **Verify endpoints, parameters, and response fields** against the [API reference](https://api.reference.langfuse.com) instead of inferring them from code examples.
- **Use the [Langfuse CLI](https://langfuse.com/docs/api-and-data-platform/features/cli)** (`npx langfuse-cli api <resource> <action>`) to read or write traces, prompts, datasets, and scores from the terminal.

Found an error in these docs? Please open an issue at <https://github.com/langfuse/langfuse-docs/issues>.
