-
Notifications
You must be signed in to change notification settings - Fork 234
docs: add web callback docs #2973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| --- | ||
| title: Web callbacks | ||
| description: Trigger a browser-side HTTP callback from a trace or observation in Langfuse. | ||
| sidebarTitle: Web Callbacks | ||
| --- | ||
|
|
||
| # Web callbacks | ||
|
|
||
| Web callbacks let project members trigger an HTTP `POST` request from a trace or observation in Langfuse. Use them to connect trace debugging to your own tools, for example opening an internal investigation workflow, notifying an external system, or sending a selected trace ID to a local helper service. | ||
|
|
||
| Unlike [prompt webhooks](/docs/prompt-management/features/webhooks-slack-integrations), web callbacks are not event-driven automations. A project member manually triggers them from the trace detail menu. | ||
|
|
||
| <Callout type="info"> | ||
| Web callbacks send only identifiers. Trace input, output, metadata, scores, | ||
| and user data are not included in the callback payload. | ||
| </Callout> | ||
|
|
||
| ## Configure a web callback | ||
|
|
||
| 1. Open your project in Langfuse. | ||
| 2. Go to `Project Settings` > `Integrations` > `Web Callbacks`. | ||
| 3. Create or edit the callback endpoint. | ||
| 4. Configure the endpoint name, URL, toast message, request timeout, and optional browser-visible headers. | ||
| 5. Save the endpoint and make sure it is enabled. | ||
|
|
||
| Only one web callback endpoint can be configured per project. | ||
|
|
||
| ## Trigger a callback | ||
|
|
||
| Open a trace or observation and click the three-dot actions menu in the detail header. If an enabled endpoint exists, the menu shows `Call <callback name>`. | ||
|
|
||
| When you click the action, Langfuse immediately shows the configured toast message and sends the request from your browser to the configured endpoint. | ||
|
|
||
| ## Request payload | ||
|
|
||
| Langfuse sends a JSON `POST` request with the following payload: | ||
|
|
||
| ```json filename="web-callback-payload.json" | ||
| { | ||
| "version": 1, | ||
| "items": [ | ||
| { | ||
| "projectId": "project-id", | ||
| "traceId": "trace-id", | ||
| "observationId": null | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| Payload fields: | ||
|
|
||
| - `version`: Payload contract version. The current version is `1`. | ||
| - `items`: List of selected objects. V1 sends one item. | ||
| - `projectId`: Langfuse project ID. | ||
| - `traceId`: Trace ID for the selected trace or observation. | ||
| - `observationId`: `null` for trace-level callbacks, or the selected observation ID for observation-level callbacks. | ||
|
|
||
| If your receiver needs the full trace, observation, session, or score data, use the IDs from the payload to query the [Langfuse API](/docs/api-and-data-platform/features/public-api) from your own backend. | ||
|
|
||
| ## Endpoint requirements | ||
|
|
||
| Your endpoint must: | ||
|
|
||
| - Accept `POST` requests with a JSON body. | ||
| - Return any HTTP `2xx` status for success. | ||
| - Respond before the configured timeout. | ||
| - Allow browser requests from your Langfuse origin via CORS. | ||
| - Respond to CORS preflight `OPTIONS` requests if you configure custom headers. | ||
|
Check failure on line 69 in content/docs/observability/features/web-callbacks.mdx
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 The prose at lines 69 and 155 says CORS preflight is needed "if you configure custom headers", but a POST with Extended reasoning...What the bug is. Lines 69 and 155 of |
||
|
|
||
| Langfuse treats non-2xx responses, timeouts, network errors, and CORS failures as failed callbacks and shows an error toast. | ||
|
|
||
| ## Browser-side delivery | ||
|
|
||
| Web callbacks are delivered directly from the user's browser with `fetch`. | ||
|
|
||
| This has a few practical consequences: | ||
|
|
||
| - The receiver sees the user's browser as the client, not Langfuse servers. | ||
| - The receiver must allow CORS from the Langfuse origin. | ||
| - Custom headers are visible in browser developer tools. | ||
| - Headers are not suitable for secrets or private API keys. | ||
| - Langfuse does not retry failed callback requests in the background. | ||
|
|
||
| <Callout type="warn"> | ||
| Do not put secrets into web callback headers. If the receiver needs privileged | ||
| access to Langfuse data, let the receiver call the Langfuse API with credentials | ||
| stored on the receiver side. | ||
| </Callout> | ||
|
|
||
| ## Minimal receiver | ||
|
|
||
| The receiver can be any HTTP server. This example logs the payload and acknowledges the callback: | ||
|
|
||
| ```ts filename="server.ts" | ||
| import http from "node:http"; | ||
|
|
||
| type WebCallbackPayload = { | ||
| version: 1; | ||
| items: Array<{ | ||
| projectId: string; | ||
| traceId: string; | ||
| observationId: string | null; | ||
| }>; | ||
| }; | ||
|
|
||
| const server = http.createServer((req, res) => { | ||
| res.setHeader("Access-Control-Allow-Origin", "https://cloud.langfuse.com"); | ||
| res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); | ||
| res.setHeader("Access-Control-Allow-Headers", "content-type"); | ||
|
Check warning on line 110 in content/docs/observability/features/web-callbacks.mdx
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 The example sets Extended reasoning...What the bug is. In res.setHeader("Access-Control-Allow-Headers", "content-type");A reader who follows step 4 and adds any custom header on the Langfuse side will hit a CORS preflight failure the moment they wire up this example. The code path that triggers it. Per the CORS spec, when the browser issues a non-simple request (here a JSON Why existing code/docs don't prevent it. The "Endpoint requirements" section (line 69) acknowledges that custom headers trigger preflight. The "Troubleshooting > CORS error" section (line 155) repeats that the server must handle preflight — but neither section actually names Impact. Pure documentation completeness. The example works fine for the default no-custom-headers case (which is why this is a nit, not a normal-severity bug). But the doc itself invites the very configuration that breaks the example, and the failure mode — a CORS preflight error toast on first click — is exactly the kind of friction users blame the example for. Step-by-step proof.
How to fix. The lowest-friction fix is a one-line code comment in the example, e.g. |
||
|
|
||
| if (req.method === "OPTIONS") { | ||
| res.writeHead(204); | ||
| res.end(); | ||
| return; | ||
| } | ||
|
|
||
| if (req.method !== "POST") { | ||
| res.writeHead(405); | ||
| res.end("Method not allowed"); | ||
| return; | ||
| } | ||
|
|
||
| let body = ""; | ||
|
|
||
| req.on("data", (chunk: Buffer) => { | ||
| body += chunk.toString("utf8"); | ||
| }); | ||
|
|
||
| req.on("end", () => { | ||
| const payload = JSON.parse(body) as WebCallbackPayload; | ||
|
|
||
| console.log("Received Langfuse web callback", payload); | ||
|
|
||
| res.writeHead(202, { "Content-Type": "application/json" }); | ||
| res.end(JSON.stringify({ ok: true })); | ||
| }); | ||
| }); | ||
|
|
||
| server.listen(4047, "127.0.0.1", () => { | ||
| console.log("Listening on http://127.0.0.1:4047"); | ||
| }); | ||
| ``` | ||
|
|
||
| For production, set `Access-Control-Allow-Origin` to your Langfuse deployment URL, validate the request body, and keep any Langfuse API credentials on the server. | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Callback endpoint returned HTTP 404 | ||
|
|
||
| The request reached your endpoint, but the path does not exist. Check the configured URL path and make sure the receiver handles `POST` requests at that route. | ||
|
|
||
| ### CORS error | ||
|
|
||
| Because the request is sent from the browser, the receiver must allow the Langfuse origin. If you use custom headers, the browser may send an `OPTIONS` preflight request before the `POST`; your server must handle that request too. | ||
|
|
||
| ### Callback request timed out | ||
|
|
||
| Increase the timeout in the endpoint settings or make the receiver return a `2xx` response faster. For longer jobs, acknowledge the callback quickly and process the work asynchronously. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Trace URLs](/docs/observability/features/url) | ||
| - [Sessions](/docs/observability/features/sessions) | ||
| - [Prompt webhooks](/docs/prompt-management/features/webhooks-slack-integrations) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| export const GITHUB_STARS = 23619; | ||
| export const GITHUB_STARS = 27501; |
Uh oh!
There was an error while loading. Please reload this page.