JavaScript SDK
The Foil JavaScript SDK provides full-featured tracing, logging, and feedback collection for Node.js applications.Installation
Requirements: Node.js 18 or higherConfiguration
Get your API key from the Foil Dashboard under Settings > API Keys.Configuration Options
Debug Mode
Enable debug mode to see detailed logs of all SDK operations:Wizard
The Foil wizard automatically instruments your project. It scans your code, detects LLM providers and application patterns, then adds the right tracing setup.
The wizard creates a
foil.js (or foil.mjs for ESM) config file, adds the Foil import to your entry point, and wraps your agent logic with the appropriate tracing pattern.
Quick Start
The core concept is the trace. A trace represents a complete unit of work (like handling a user request) and contains one or more spans (individual operations like LLM calls, tool executions, or retrieval steps).Nested Spans
The key benefit ofctx.llmCall() is that other spans automatically nest under it, giving you a clear tree in the dashboard:
Convenience Methods
TheTraceContext provides shorthand methods for common span types. Each wraps your async function in a span and automatically records the return value as output:
Tool Tracing
Foil provides two ways to trace tool calls, depending on whether the LLM decides which tools to run or your code decides.ctx.executeTools() — LLM-Driven (Recommended)
Use this when your agent uses OpenAI function calling. The LLM decides which tools to call at runtime — you define the available tools and their implementations, then executeTools() handles everything:
- Reads
tool_callsfrom the OpenAI response - Executes each tool function with the LLM-provided arguments
- Creates a traced TOOL span for each call (name, input, output, duration)
- Returns formatted
toolmessages ready to feed back to the next OpenAI call
response.choices[0].message.tool_calls.
ctx.tool() — Code-Driven (Manual)
Use this for fixed pipeline steps that always run regardless of what the LLM says — like a mandatory database write, a config lookup, or a preprocessing step.
When to Use Which
For most AI agents,
ctx.executeTools() is the right choice. Use ctx.tool() only for operations that aren’t driven by LLM decisions.What Gets Captured
Streaming
Streaming is fully supported:Auto-Instrumentation
Foil supports automatic instrumentation of LLM calls via OpenLLMetry. PassinstrumentModules to the Foil constructor and all calls to supported providers are traced automatically — no manual wrapping needed.
Auto-instrumentation is an optional enhancement. For most use cases,
ctx.llmCall() is the recommended approach — it works with any LLM provider and gives you nested span trees (tools under LLM calls). Auto-instrumentation captures LLM calls automatically; combine it with ctx.executeTools() to also capture tool calls driven by OpenAI function calling.Basic Setup
With foil.trace()
Wrap auto-instrumented calls infoil.trace() to group them under a single trace:
With Tool Calling (executeTools)
Auto-instrumentation captures LLM calls automatically, but tool execution still needsctx.executeTools(). This is the recommended pattern for agentic tool-calling loops with auto-instrumentation:
Supported Libraries
Graceful Shutdown
Always shut down gracefully to flush pending spans:Advanced: Manual OTEL Setup
Advanced: Manual OTEL Setup
Troubleshooting: Spans not appearing
Troubleshooting: Spans not appearing
- Check that your API key is correct
- Ensure
Foilis constructed withinstrumentModulesbefore any LLM calls - Call
await foil.flush()before process exit - Enable debug logging to see export status
Troubleshooting: Missing LLM details (tokens, model)
Troubleshooting: Missing LLM details (tokens, model)
- Ensure
new Foil({ instrumentModules })is called at the top of your app, before importing LLM libraries - Check that the LLM library is supported
- Some details require specific library versions
Troubleshooting: Duplicate spans
Troubleshooting: Duplicate spans
- Don’t use
instrumentModulesandctx.llmCall()for the same LLM calls - Don’t initialize both
Foil.init()from@getfoil/foil-js/otelandnew Foil({ instrumentModules })
Signals and Feedback
Record custom metrics and user feedback tied to your traces:Span Types
Foil supports several span types to categorize different operations:Error Handling
Errors are automatically captured when spans fail:Complete Example
Advanced Patterns
Manual span control with startSpan
Manual span control with startSpan
For advanced flows where you need explicit control over parent-child relationships:
Multi-agent handoffs with createChildContext
Multi-agent handoffs with createChildContext
When one agent delegates to another, use
span.createChildContext() to create nested agent spans:Retrieving traces
Retrieving traces
Fetch completed traces for debugging or analysis:
Trace context propagation
Trace context propagation
Pass trace context to external services via headers:
Fire-and-forget logging
Fire-and-forget logging
For non-critical telemetry without full tracing:
Provider-agnostic usage
Provider-agnostic usage
ctx.llmCall() works with any LLM provider — not just OpenAI:Custom metadata and properties
Custom metadata and properties
Add custom properties to spans for filtering and analysis: