Hands-On 7 min read Updated Sep 10, 2026

Setting Up Tracing In Your App

This is the guide where LangSmith stops being an idea and starts being something you can actually see. By the end, you'll have a real trace sitting in your dashboard from a real function call in your own code.

Step 1: Get an API key

Create a free account at smith.langchain.com if you don't have one, then generate an API key from your workspace settings. Keep it somewhere you'd keep any other secret - not committed to your repo.

Step 2: Set your environment variables

LangSmith's tracing is controlled entirely through environment variables, which is what makes it possible to turn on for an existing app without touching your business logic:

LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=<your-langsmith-api-key>
LANGCHAIN_PROJECT=my-app-dev

LANGCHAIN_TRACING_V2 is the master switch. LANGCHAIN_PROJECT is optional - if you skip it, traces land in a project called "default" - but naming it explicitly is what keeps your local runs separate from staging and production, per the previous guide.

If you're already using LangChain or LangGraph: that's genuinely it. Setting LANGCHAIN_TRACING_V2=true is enough to start seeing every chain, model call, and graph node traced automatically - no code changes required.

Step 3: Trace your own functions with @traceable

If you're not using LangChain, or you have custom logic you want visible as its own step in the trace, wrap it with the @traceable decorator from the langsmith SDK:

from langsmith import traceable
from openai import OpenAI

client = OpenAI()

@traceable
def summarize(text: str) -> str:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "Summarize in one sentence."},
            {"role": "user", "content": text},
        ],
    )
    return response.choices[0].message.content

summarize("LangSmith turns a black-box LLM call into something you can inspect.")

@traceable wraps the function so its inputs, output, and timing become one run - and if that function calls another @traceable function, or makes a wrapped LLM call, those nest underneath it automatically as child runs, building the same tree structure covered in the previous guide.

your function @traceable POST run LangSmith API ingest ~1 sec Dashboard trace appears

Tracing calls happen asynchronously in the background - your function's actual latency isn't affected.

Step 4: Watch it show up

Run your function, then open the project in your LangSmith dashboard. Within a second or two, a new trace appears with your function's name, its input and output, how long it took, and - if it called an LLM - the token counts and cost. Click into it and, if you called other traced functions along the way, you'll see them nested underneath as child runs, exactly as described in the previous guide.

A note on tracing overhead

Tracing calls happen asynchronously and are batched in the background, so instrumenting a function doesn't meaningfully slow down your app's actual response time. It's safe to leave tracing on in production, not just during development - in fact production is where it matters most, since that's the traffic you can't just re-run in a debugger.

JavaScript works the same way

If your app is in Node or a Next.js API route instead of Python, the same environment variables apply, and the SDK exposes an equivalent traceable() wrapper function rather than a decorator - the concepts (a traced function, nested child runs, a project) carry over one-to-one.

Next up: now that traces are flowing, the next guide covers turning real examples into a dataset and running evaluations against it.
Share this guide

Was this guide helpful?

Thanks for the feedback!

Want more hands-on AI builds like this?

APA Mastery runs live, practical sessions on working with modern AI tools - not just theory.

See What's On →
← BackCore Concepts: Traces, Runs & Projects