/Pydantic Logfire

Full-stack tracing: Javascript observability with Pydantic Logfire

Petyo Ivanov avatar
Petyo Ivanov
5 mins

Full-stack tracing: Javascript observability with Pydantic Logfire

You've instrumented your Python backend with Logfire. You can see every FastAPI request, every database query, every external API call. But what happens before that request arrives? What did the user click? How long did they wait? What was the state of the application when things went wrong?

If your application has a JavaScript frontend—and statistically, it almost certainly does—there's a whole layer of your stack you're not seeing.

JavaScript powers 98.9% of websites on the client side. Even teams that are Python-first typically have JavaScript somewhere in their stack: a React dashboard, a Next.js marketing site, an admin panel built with Vue.

But it's not just browsers. JavaScript runs in:

  • Node.js backends — over 4.6 million websites use Node.js server-side
  • Edge functions — Cloudflare Workers, Vercel Edge Functions, Deno Deploy
  • Desktop apps — Electron powers VS Code, Slack, Discord
  • Mobile apps — React Native brings JavaScript to iOS and Android

And increasingly, these JavaScript layers serve as the interface to Python backends—the dominant choice for AI and machine learning workloads. Your React dashboard calls your PydanticAI-powered API. Your Next.js app talks to your FastAPI inference service. The user experience lives in JavaScript; the intelligence lives in Python.

For Python developers building modern AI-powered applications, JavaScript observability isn't optional—it's the missing piece of the puzzle.

Backend monitoring tells you what happened on your servers. But Google's research shows that 53% of mobile users abandon sites that take longer than 3 seconds to load, and case studies from companies like Vodafone and Lazada demonstrate that even modest performance improvements lead to measurable revenue gains. These problems often originate in the browser, not the backend.

When a user reports "the app is slow," backend metrics might show normal response times. But what if the slowness is in the browser? Maybe a heavy JavaScript bundle is blocking rendering. Maybe a third-party script is competing for resources. Maybe the user's interaction triggers multiple redundant API calls.

With client-side observability, you see document load times, user interactions, network requests, and how they all connect to your backend traces.

Here's a real example: we were receiving malformed payloads on a certain API endpoint. The backend validation was rejecting them, but we couldn't figure out why users were sending bad data. Only after instrumenting the client-side code path did we discover that a certain account was producing OTel traces with multiple root-level spans, resulting in a miscalculated payload that was far removed from the actual endpoint call. Detecting and fixing this issue would have been impossible without full-stack tracing.

If you already know Logfire in Python, you already know it in JavaScript:

# Python
logfire.info('User {user_id} logged in', user_id=123)
// JavaScript - same pattern
logfire.info('User {user_id} logged in', { user_id: 123 })

Message templates, log levels, spans—they all work the same way. The concepts you've learned transfer directly.

Pydantic Logfire provides JavaScript SDKs for different runtime environments:

  • Node.js — Full auto-instrumentation for HTTP, databases, and web frameworks
  • Browser — Automatic tracing of fetch requests, page loads, and user interactions
  • Cloudflare Workers — Edge function instrumentation

Just like logfire.instrument_fastapi() in Python, the JavaScript SDKs automatically instrument common libraries. Under the hood, Logfire uses OpenTelemetry's auto-instrumentation packages, which support 30+ libraries out of the box: web frameworks like Express, Fastify, Koa, Hapi, and NestJS; databases including PostgreSQL, MySQL, MongoDB, and Redis; plus GraphQL, gRPC, Kafka, and the AWS SDK. In the browser, every fetch() call and page load is captured automatically.

You focus on instrumenting your business logic. The plumbing is handled for you.

There's one important difference for browser instrumentation: you can't put your Logfire token in client-side code—it would be visible to anyone who opens DevTools. Instead, browser traces are sent to your own backend, which forwards them to Logfire with the token attached server-side.

It's a simple pattern, and the documentation walks through the setup for Express, Next.js, and other frameworks.

This is where JavaScript observability really shines. When a user clicks a button in your React app, that click triggers a fetch() call. The browser SDK automatically attaches a trace context header to the request. Your Python backend receives that header and continues the same trace.

The result? A single trace that shows:

[Browser] Button click
    └── [Browser] fetch /api/orders
            └── [Python] POST /api/orders
                    └── [Python] SELECT * FROM orders
                    └── [Python] Redis cache lookup

You see the complete journey from user action to database query, with timing at every step. When something is slow, you know exactly where.

This is how distributed client-to-server traces from the nextjs example appears in the Logfire UI. You can interact with the example above by clicking on the spans.

Enable console output locally (console: true in the configuration) to see your traces in the terminal as you develop. It's a fast feedback loop that helps you understand what's being captured before you deploy. Keeping Logfire's live view on your second monitor is also a great way to spot issues early.

Don't manually instrument every HTTP call—that's already covered. Focus your manual spans on business-critical paths: checkout flows, authentication steps, data synchronization. Instrument the code where bugs would be most painful.

The metrics that matter are the ones users feel:

  • Page load time — How long until the page is interactive?
  • Interaction latency — How long between click and response?
  • API timing from the browser — Not server processing time, but the full round-trip including network latency

Everything you know from Python Logfire applies:

  • Message templates extract attributes automatically
  • Sensitive data scrubbing is built-in (passwords, tokens, API keys)
  • Log levels work the same way (trace, debug, info, warn, error)

The Logfire JavaScript SDK is open source and available on npm. Setup takes just a few minutes:

  1. Read the docs: logfire.pydantic.dev/docs/integrations/javascript
  2. Explore the examples: Express, Next.js, browser, and Cloudflare Workers examples in the GitHub repository
  3. Try it free: If you're not already using Logfire, sign up and get started

Full-stack observability means seeing your entire application—Python backend and JavaScript frontend—in one place, with traces that flow seamlessly between them. No more blind spots. No more guessing what happened in the browser.