Docs
DocumentationQuery ReferenceAPI Reference
Open Console→→
DocumentationQuery ReferenceAPI Reference

Platform overview

What is Axiom?QuickstartArchitectureFeatures
Fundamentals
Datasets
Edge deployments
Limits
Performance
Optimize usage
Requirements
Semantic conventions
Glossary
Tour
SecurityRoadmap

Send data

Reference architecturesMethods

Understand data

Console
Query
Builder
Editor
Query results
Visualize
Traces
Metrics
Correlations
Save queries
Stream
Dashboard
Create
Elements
Create
Configure
Element types
Gauge
Heatmap
Log stream
Monitor list
Note
Pie chart
Scatter plot
Statistic
Table
Time series
Sections
Configure
Filter
Annotate
Monitor
Overview
View status
Configure
Examples
Monitor types
Anomaly
Match
Threshold
Alerting
Overview
Configure
Notifier types
Custom Webhook
Discord
Email
Microsoft Teams
Opsgenie
PagerDuty
Slack
Manage
Datasets
Overview
Views
Virtual fields
Access
RBAC
Tokens
CLI
Organization
Audit log
Settings
Usage and billing
Profile
Extend
Overview
AWS Lambda
AWS PrivateLink
Cloudflare Workers
Cloudflare Logpush
Convex
Grafana
Hex
Netlify
Supabase
Tailscale
Terraform
Unkey
Vercel
Intelligence
Overview
Spotlight
AI agents
Overview
MCP Server
Query cost limits
Agent-created orgs
Skills
Overview
Axiom alerting
Build dashboards
Control costs
Query metrics
SRE
Translate SPL to APL
Splunk
Overview
Splunk app
Install and configure
Commands
Examples
Portal
How it works
Set up standard mode
Set up transparent mode
Observability Cloud
SPL command support
Examples
Monitor and troubleshoot

Use cases

ObservabilityProduct analytics
LLM observability
Overview
Use Axiom AI SDK
Manual instrumentation
GenAI attributes
Redaction policies

Miscellaneous

LLMs
Overview
List of docs pages
Full docs
Query reference
FAQs
Legal
Acceptable use policy
Cookies
Data processing
HIPAA
Partner agreement
Partner program guide
Privacy policy
SLA
Terms of service
Terms of use

OpenTelemetry using Nuxt.js

This page explains how to configure OpenTelemetry in a Nuxt.js app to send telemetry data to Axiom.

OpenTelemetry provides a unified approach to collecting telemetry data from your Nuxt.js and TypeScript apps. This page demonstrates how to configure OpenTelemetry in a Nuxt.js app to send telemetry data to Axiom using OpenTelemetry SDK.

Prerequisites

  • Create an Axiom account.
  • Create a dataset in Axiom where you send your data.
  • Create an API token in Axiom with permissions to ingest data to the dataset you have created.
  • Install Node.js version 18 or newer.
  • Use your own app written in Nuxt.js, or follow this guide to create a new one.

Create new Nuxt.js app

Run the following command to create a new Nuxt.js app. Accept the default options during the initialization.

shell
npx nuxi@latest init my-nuxt-app
cd my-nuxt-app

Install dependencies

Install the required OpenTelemetry packages:

shell
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-proto @opentelemetry/sdk-trace-base @opentelemetry/resources @opentelemetry/semantic-conventions

Configure environment variables

Create a .env file in the root of your project to store your Axiom credentials:

dotenv
AXIOM_TOKEN=API_TOKEN
AXIOM_DATASET=DATASET_NAME
Info

Replace API_TOKEN with the Axiom API token you have generated. For added security, store the API token in an environment variable.

Replace DATASET_NAME with the name of the Axiom dataset where you send your data.

Replace AXIOM_DOMAIN with the base domain of your edge deployment. For more information, see Edge deployments.

Configure Nuxt.js app

Configure your Nuxt app in nuxt.config.ts to expose the environment variables to the runtime:

typescript
export default defineNuxtConfig({
  compatibilityDate: '2026-01-05',
  devtools: { enabled: true },

  runtimeConfig: {
    axiomToken: process.env.AXIOM_TOKEN,
    axiomDataset: process.env.AXIOM_DATASET,
  },

  nitro: {
    experimental: {
      openAPI: true
    }
  }
});

Server setup

Create server directories

Create the necessary directories for your server-side code:

shell
mkdir -p server/api

mkdir -p server/plugins

Instrumentation plugin

Create the OpenTelemetry instrumentation plugin in server/plugins/instrumentation.ts. This file sets up the OpenTelemetry SDK and configures it to send traces to Axiom.

Info

In Nuxt.js, you must initialize OpenTelemetry in a Nitro plugin, not in the nuxt.config.ts hooks, because API endpoints run in the Nitro server runtime.

This example uses the ATTR_SERVICE_NAME constant instead of the deprecated SemanticResourceAttributes.SERVICE_NAME, and resourceFromAttributes() instead of new Resource() for compatibility with newer OpenTelemetry versions.

typescript
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';

export default defineNitroPlugin((nitroApp) => {
  console.log('Initializing OpenTelemetry in Nitro server...');
  console.log('- AXIOM_TOKEN:', process.env.AXIOM_TOKEN ? `${process.env.AXIOM_TOKEN.substring(0, 10)}...` : 'NOT SET');
  console.log('- AXIOM_DATASET:', process.env.AXIOM_DATASET || 'NOT SET');

  const traceExporter = new OTLPTraceExporter({
    url: 'https://api.axiom.co/v1/traces',
    headers: {
      'Authorization': `Bearer ${process.env.AXIOM_TOKEN}`,
      'X-Axiom-Dataset': process.env.AXIOM_DATASET || ''
    },
  });

  // Add export success/error logging for debugging
  const originalExport = traceExporter.export.bind(traceExporter);
  traceExporter.export = (spans, resultCallback) => {
    console.log(`Exporting ${spans.length} span(s) to Axiom...`);
    originalExport(spans, (result) => {
      if (result.code === 0) {
        console.log(' Spans exported successfully to Axiom');
      } else {
        console.error(' Export failed:', result.error);
      }
      resultCallback(result);
    });
  };

  const resource = resourceFromAttributes({
    [ATTR_SERVICE_NAME]: 'my-nuxt-app',
  });

  const sdk = new NodeSDK({
    spanProcessor: new BatchSpanProcessor(traceExporter),
    resource: resource,
    instrumentations: [getNodeAutoInstrumentations()],
  });

  sdk.start();

  console.log('OpenTelemetry started in Nitro server');
});

Example API endpoint

Create an example API endpoint in server/api/hello.ts to test your OpenTelemetry setup.

The example endpoint below demonstrates manual span creation. Each request to /api/hello creates a trace span and sends it to Axiom.

typescript
import { trace } from '@opentelemetry/api';

export default defineEventHandler((event) => {
  console.log('API endpoint hit: /api/hello');

  // Get the tracer from the global tracer provider
  const tracer = trace.getTracer('my-nuxt-app');

  // Create a manual span for this API request
  const span = tracer.startSpan('api.hello');
  span.setAttribute('http.method', 'GET');
  span.setAttribute('http.path', '/api/hello');

  const response = {
    message: 'Hello from Nuxt API!',
    timestamp: new Date().toISOString(),
    path: event.path
  };

  span.end();

  console.log('Manual span created and ended');

  return response;
});

Run instrumented app

In development mode

To run your Nuxt app with OpenTelemetry instrumentation in development mode:

shell
npm run dev

You see the following output in the console:

text
Nuxt 4.2.2 (with Nitro 2.12.9, Vite 7.3.0 and Vue 3.5.26)

  ➜ Local:    http://localhost:3000/

Initializing OpenTelemetry in Nitro server...
- AXIOM_TOKEN: xaat-xxxxx...
- AXIOM_DATASET: nuxt-traces
OpenTelemetry started in Nitro server

Test setup

Test your API endpoint to generate traces:

shell
curl http://localhost:3000/api/hello

You get the following response from the API endpoint:

JSON
{
  "message": "Hello from Nuxt API!",
  "timestamp": "2026-01-05T22:30:00.000Z",
  "path": "/api/hello"
}

After making 5-10 requests, you see the following output in the console:

text
Exporting 5 span(s) to Axiom...
Spans exported successfully to Axiom

In production mode

To build and run in production:

shell
# Build the application
npm run build

# Start the production server
npm run preview

After generating some traces by visiting your API endpoints, go to the Stream tab in Axiom, and then click your dataset. You see the traces appearing in the stream.

Project directory structure

Your Nuxt.js project has the following structure:

text
my-nuxt-app/
├── server/
│   ├── api/
│   │   └── hello.ts          # Example API endpoint
│   └── plugins/
│       └── instrumentation.ts # OpenTelemetry configuration
├── .env                       # Environment variables
├── nuxt.config.ts            # Nuxt configuration
├── package.json              # Dependencies and scripts
└── tsconfig.json             # TypeScript configuration (auto-generated)

Root-level files

  • .env: Stores environment variables (API token, dataset name)
  • nuxt.config.ts: Nuxt configuration file that exposes environment variables to the runtime
  • package.json: Lists dependencies and npm scripts
  • tsconfig.json: TypeScript configuration (auto-generated by Nuxt)

Server directory

The server/ directory contains all server-side code that runs in Nitro, Nuxt's server engine.

  • server/api/ directory contains API route handlers. Each file becomes an API endpoint:

    • server/api/hello.ts → /api/hello
    • server/api/users.ts → /api/users
    • server/api/posts/[id].ts → /api/posts/:id
  • server/plugins/ directory contains Nitro plugins that run when the server starts:

    • server/plugins/instrumentation.ts: Initializes OpenTelemetry SDK

Manual instrumentation

Manual instrumentation in Nuxt.js allows you to create custom spans for specific operations.

Initialize tracer

Import the OpenTelemetry API in any server file, such as server/api/hello.ts:

typescript
import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('my-nuxt-app');

Create spans

Wrap operations you want to trace:

typescript
export default defineEventHandler(async (event) => {
  const span = tracer.startSpan('database.query');

  try {
    // Your code here
    const data = await fetchDataFromDatabase();

    span.setStatus({ code: 0 }); // Success
    span.end();

    return data;
  } catch (error) {
    span.recordException(error);
    span.setStatus({ code: 2, message: error.message }); // Error
    span.end();

    throw error;
  }
});

Annotate spans

Add metadata to your spans, such as order.id, user.id, and order.amount:

typescript
const span = tracer.startSpan('process.order');

span.setAttribute('order.id', orderId);
span.setAttribute('user.id', userId);
span.setAttribute('order.amount', amount);

span.addEvent('payment_processed', {
  paymentMethod: 'credit_card',
  processorResponse: 'approved'
});

span.end();

Create nested spans

Create parent-child relationships between spans:

typescript
import { trace, context } from '@opentelemetry/api';

export default defineEventHandler(async (event) => {
  const tracer = trace.getTracer('my-nuxt-app');

  const parentSpan = tracer.startSpan('process.checkout');

  // Make parentSpan the active span
  await context.with(trace.setSpan(context.active(), parentSpan), async () => {
    // This span will be a child of parentSpan
    const childSpan = tracer.startSpan('validate.payment');
    await validatePayment();
    childSpan.end();

    // Another child span
    const childSpan2 = tracer.startSpan('create.order');
    await createOrder();
    childSpan2.end();
  });

  parentSpan.end();
});

Automatic instrumentation

Automatic instrumentation is already set up in the server/plugins/instrumentation.ts file:

typescript
instrumentations: [getNodeAutoInstrumentations()]

This automatically traces:

  • HTTP requests and responses
  • Database queries (MySQL, PostgreSQL, MongoDB, etc.)
  • Redis operations
  • File system operations
  • DNS lookups
  • And many more Node.js operations

Reference

List of OpenTelemetry Trace Fields

Field CategoryField NameDescription
Unique Identifiers
_rowidUnique identifier for each row in the trace data.
span_idUnique identifier for the span within the trace.
trace_idUnique identifier for the entire trace.
Timestamps
_systimeSystem timestamp when the trace data was recorded.
_timeTimestamp when the actual event being traced occurred.
HTTP Attributes
attributes.http.methodHTTP method used for the request.
attributes.http.pathThe API path accessed during the request.
attributes.http.status_codeHTTP response status code.
attributes.http.routeRoute pattern (for example, /api/:id).
attributes.http.schemeProtocol scheme (HTTP/HTTPS).
attributes.http.user_agentUser agent string of the client.
Network Attributes
attributes.net.host.portPort number on the host receiving the request.
attributes.net.peer.ipIP address of the peer in the network interaction.
Operational Details
durationTime taken for the operation in nanoseconds.
kindType of span (server, client, internal, producer, consumer).
nameName of the span (for example, 'api.hello').
scopeInstrumentation scope.
service.nameName of the service generating the trace.
Resource Attributes
resource.process.pidProcess ID of the Nitro server.
resource.process.runtime.nameRuntime name (for example, 'nodejs').
resource.process.runtime.versionNode.js version.
Telemetry SDK Attributes
telemetry.sdk.languageLanguage of the telemetry SDK (javascript).
telemetry.sdk.nameName of the telemetry SDK (opentelemetry).
telemetry.sdk.versionVersion of the telemetry SDK.

List of Imported Libraries

@opentelemetry/sdk-node

The core SDK for OpenTelemetry in Node.js. Provides the primary interface for configuring and initializing OpenTelemetry in a Node.js/Nuxt app. It includes functionalities for managing traces, metrics, and context propagation.

@opentelemetry/auto-instrumentations-node

Offers automatic instrumentation for Node.js apps. Automatically collects telemetry data from common Node.js libraries and frameworks without manual instrumentation. Essential for Nuxt/Nitro server operations.

@opentelemetry/exporter-trace-otlp-proto

Provides an exporter that sends trace data using the OpenTelemetry Protocol (OTLP). Allows Nuxt apps to send collected traces to Axiom or any OTLP-compatible backend.

@opentelemetry/sdk-trace-base

Contains the BatchSpanProcessor and other foundational elements for tracing. The BatchSpanProcessor batches spans before sending them to the exporter, improving performance and reducing network overhead.

@opentelemetry/resources

Provides the resourceFromAttributes() function to create resource objects that identify your service in traces. Resources contain service metadata like service name, version, and environment.

@opentelemetry/semantic-conventions

Provides standard attribute names like ATTR_SERVICE_NAME for consistent telemetry data. Ensures your traces follow OpenTelemetry semantic conventions for better interoperability.

@opentelemetry/api

The OpenTelemetry API package that provides the trace and context APIs for manual instrumentation. This is a peer dependency that other OpenTelemetry packages rely on.

Advanced configurations

Custom span processor

For more control over span processing, use the SimpleSpanProcessor instead of the BatchSpanProcessor:

typescript
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';

const sdk = new NodeSDK({
  spanProcessor: new SimpleSpanProcessor(traceExporter), // Exports immediately
  resource: resource,
  instrumentations: [getNodeAutoInstrumentations()],
});

Sampling

To reduce the volume of traces, use the TraceIdRatioBasedSampler to sample a percentage of traces:

typescript
import { TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base';

const sdk = new NodeSDK({
  spanProcessor: new BatchSpanProcessor(traceExporter),
  sampler: new TraceIdRatioBasedSampler(0.5), // Sample 50% of traces
  resource: resource,
  instrumentations: [getNodeAutoInstrumentations()],
});

Custom resource attributes

Add custom attributes to all traces, such as service.version and deployment.environment:

typescript
const resource = resourceFromAttributes({
  [ATTR_SERVICE_NAME]: 'my-nuxt-app',
  [ATTR_SERVICE_VERSION]: '1.0.0',
  'deployment.environment': process.env.NODE_ENV || 'development',
  'service.namespace': 'production',
});
Was this page helpful?
Suggest edits on GitHub
On this page
Create new Nuxt.js appInstall dependenciesConfigure environment variablesConfigure Nuxt.js appServer setupCreate server directoriesInstrumentation pluginExample API endpointRun instrumented appIn development modeTest setupIn production modeProject directory structureRoot-level filesServer directoryManual instrumentationInitialize tracerCreate spansAnnotate spansCreate nested spansAutomatic instrumentationReferenceList of OpenTelemetry Trace FieldsList of Imported Libraries@opentelemetry/sdk-node@opentelemetry/auto-instrumentations-node@opentelemetry/exporter-trace-otlp-proto@opentelemetry/sdk-trace-base@opentelemetry/resources@opentelemetry/semantic-conventions@opentelemetry/apiAdvanced configurationsCustom span processorSamplingCustom resource attributes