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

# User Signals & Journeys

> Connect what your users do to the AI traces behind it

An AI trace records what the model did, but it does not tell you whether that was useful. Did the user accept the result, edit it, cancel it, or escalate to a human? That is what a **signal** is: an event you send DataFramer about what a user, or your product, did.

A **journey** links a user's signals to the AI traces that happened around them, even across several AI calls or agents. Every signal and every trace carries the same `journey_id`, so DataFramer can line them up into one timeline.

## The pieces

<CardGroup cols={3}>
  <Card title="Browser SDK" icon="browser" href="/docs/user-signals/browser-sdk">
    Runs in your frontend. Sends user events to DataFramer and creates the journey id.
  </Card>

  <Card title="Server Instrumentation" icon="server" href="/docs/user-signals/server-instrumentation">
    Runs in your backend. Picks the journey id up from each request and stamps it onto your Langfuse traces or LangSmith runs.
  </Card>

  <Card title="Connect your traces" icon="plug" href="/docs/connect-traces">
    Connect Langfuse or LangSmith and DataFramer pulls your AI traces in. This is how traces reach DataFramer.
  </Card>
</CardGroup>

## How it fits together

Signals go straight from the browser to DataFramer. Traces go through your observability tool, and DataFramer pulls them from there. The journey id travels with both.

<div className="not-prose my-8 flex flex-col sm:flex-row items-stretch gap-3">
  <div className="flex-[3] flex flex-col gap-3">
    <div className="flex-1 flex flex-col sm:flex-row items-stretch gap-2">
      <div className="flex-1 rounded-2xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-white/[0.03] p-4 flex flex-col items-center text-center gap-2">
        <span className="font-mono text-[11px] tracking-widest uppercase text-gray-500 dark:text-gray-400">Browser</span>
        <span className="font-mono text-xs rounded-full px-3 py-1.5 bg-gray-900 text-white dark:bg-white dark:text-gray-900">@dataframer/signals</span>
        <p className="text-sm text-gray-600 dark:text-gray-400 m-0">Sends <code>track</code>/<code>identify</code>/<code>group</code> events, tagged with <code>journey\_id</code>, straight to DataFramer</p>
      </div>

      <div className="hidden sm:flex items-center justify-center text-green-600 dark:text-green-400 font-mono text-lg px-1">→</div>
    </div>

    <div className="flex-1 flex flex-col sm:flex-row items-stretch gap-2">
      <div className="flex-1 rounded-2xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-white/[0.03] p-4 flex flex-col items-center text-center gap-2">
        <span className="font-mono text-[11px] tracking-widest uppercase text-gray-500 dark:text-gray-400">Your Backend</span>
        <span className="font-mono text-xs rounded-full px-3 py-1.5 bg-gray-900 text-white dark:bg-white dark:text-gray-900">dataframer-journey</span>
        <p className="text-sm text-gray-600 dark:text-gray-400 m-0">Stamps <code>journey\_id</code> onto every trace</p>
      </div>

      <div className="hidden sm:flex items-center justify-center text-green-600 dark:text-green-400 font-mono text-lg px-1">→</div>
      <div className="flex sm:hidden items-center justify-center text-green-600 dark:text-green-400 font-mono text-lg py-0.5">↓</div>

      <div className="flex-1 rounded-2xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-white/[0.03] p-4 flex flex-col items-center text-center gap-2">
        <span className="font-mono text-[11px] tracking-widest uppercase text-gray-500 dark:text-gray-400">Your Observability Tool</span>
        <span className="font-mono text-xs rounded-full px-3 py-1.5 bg-gray-900 text-white dark:bg-white dark:text-gray-900">Langfuse / LangSmith</span>
        <p className="text-sm text-gray-600 dark:text-gray-400 m-0">Holds the tagged traces</p>
      </div>

      <div className="hidden sm:flex items-center justify-center text-green-600 dark:text-green-400 font-mono text-lg px-1">→</div>
    </div>
  </div>

  <div className="flex sm:hidden items-center justify-center text-green-600 dark:text-green-400 font-mono text-lg py-0.5">↓</div>

  <div className="flex-[2] rounded-2xl border border-green-600/30 dark:border-green-400/25 bg-green-600/[0.05] dark:bg-green-400/[0.06] p-5 flex flex-col items-center justify-center text-center gap-2">
    <span className="font-mono text-[11px] tracking-widest uppercase text-green-700 dark:text-green-400">DataFramer</span>

    <div className="flex flex-col gap-1.5 items-center">
      <span className="font-mono text-xs rounded-full px-3 py-1.5 bg-green-600 text-white">Signal · journey\_id</span>
      <span className="font-mono text-xs rounded-full px-3 py-1.5 bg-green-600 text-white">Trace · journey\_id</span>
    </div>

    <p className="text-sm text-gray-600 dark:text-gray-400 m-0">Both land with the same <code>journey\_id</code> and get lined up into one timeline</p>
  </div>
</div>

<Note>
  This feature is early; reach out at [info@dataframer.ai](mailto:info@dataframer.ai) if something does not work as described.
</Note>


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