SigNoz Cloud - This page is relevant for SigNoz Cloud editions.
Self-Host - This page is relevant for self-hosted SigNoz editions.

GraphQL OpenTelemetry Instrumentation

Use this guide to instrument a Node.js GraphQL server with OpenTelemetry and send traces to SigNoz. The GraphQL instrumentation captures graphql.parse, graphql.validate, per-operation spans named after the operation type (for example, query), and per-resolver graphql.resolve spans without application code changes.

Works with Apollo Server, graphql-http, and any server built on graphql-js.

Prerequisites

Send traces to SigNoz

Step 1. Set environment variables

export OTEL_TRACES_EXPORTER="otlp"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_NODE_RESOURCE_DETECTORS="env,host,os"
export OTEL_SERVICE_NAME="<service-name>"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"

Verify these values:

Step 2. Install OpenTelemetry packages

npm install --save @opentelemetry/api @opentelemetry/auto-instrumentations-node

@opentelemetry/auto-instrumentations-node includes and enables @opentelemetry/instrumentation-graphql.

Step 3. Run your server

node server.js

Validate

Send a query to your GraphQL server, then open SigNoz:

  1. Go to Services and find your service. Click Refresh if it does not appear.
  2. Go to Traces and filter by your service name.
  3. Open a trace to see the operation span (for example, query), and graphql.resolve spans. Depending on your setup, you may also see graphql.parse and graphql.validate spans.
Sample Traces in SigNoz
Sample Traces in SigNoz
Detailed Trace in SigNoz
Detailed Trace in SigNoz

GraphQL-specific configuration

@opentelemetry/auto-instrumentations-node enables GraphQL instrumentation with default settings. To tune those settings, install the GraphQL instrumentation package and configure it in code.

Step 1. Install the package

npm install --save @opentelemetry/instrumentation-graphql

Step 2. Create a tracing file

tracing.js
'use strict'
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { GraphQLInstrumentation } = require('@opentelemetry/instrumentation-graphql');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions');

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'https://ingest.<region>.signoz.cloud:443/v1/traces',
    headers: { 'signoz-ingestion-key': '<your-ingestion-key>' },
  }),
  instrumentations: [
    getNodeAutoInstrumentations({
      // Disable the built-in GraphQL instrumentation so the explicit one below takes effect
      '@opentelemetry/instrumentation-graphql': { enabled: false },
    }),
    new GraphQLInstrumentation({
      // Record resolver spans up to this depth (default: all)
      depth: 2,
      // Merge array resolver spans into one span instead of one per item
      mergeItems: true,
      // Skip resolvers that return a field value without custom logic
      ignoreTrivialResolveSpans: true,
    }),
  ],
  resource: resourceFromAttributes({
    [ATTR_SERVICE_NAME]: '<service-name>',
  }),
});

sdk.start();

Verify these values:

Step 3. Load the tracing file before your server

node -r ./tracing.js server.js

Troubleshooting

No GraphQL spans appearing

  • Confirm graphql-js is installed in your project. The instrumentation patches the graphql package; it does not work if GraphQL is bundled inside another package without a top-level graphql dependency.
  • Set OTEL_LOG_LEVEL=debug and restart. Look for lines mentioning @opentelemetry/instrumentation-graphql to confirm the instrumentation loaded.

Only HTTP spans appear, no resolver spans

ignoreTrivialResolveSpans defaults to false, so GraphQL instrumentation includes trivial resolvers. If you enabled it and resolver spans are missing, disable it to confirm the resolvers are being called.

Enable debug logging

export OTEL_LOG_LEVEL=debug

Look for query, graphql.parse, graphql.validate, or graphql.resolve in the span output.

Service not appearing in SigNoz

  • Verify OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS are set correctly.
  • Check network connectivity to the SigNoz endpoint.
  • Make sure your server receives GraphQL requests. Spans appear after a query runs.

Setup OpenTelemetry Collector (Optional)

What is the OpenTelemetry Collector?

The OTel Collector sits between your application and SigNoz. Your application sends telemetry to the Collector, and the Collector forwards it to SigNoz.

Why use it?

  • Clean up data: Filter noisy traces or remove sensitive fields before telemetry leaves your servers.
  • Keep your app lightweight: Let the Collector handle batching, retries, and compression instead of your application code.
  • Add resource context: Tag telemetry with details such as the Kubernetes pod or cloud region.
  • Route telemetry to more backends: Send data to multiple destinations without changing your app.

See Switch from direct export to Collector for step-by-step instructions.

Next steps

Last updated: May 12, 2026

Edit on GitHub

Was this page helpful?

Your response helps us improve this page.