DefinitelyTyped icon, indicating that this package has TypeScript declarations provided by the separate @types/optics-agent package

1.1.9 • Public • Published


Apollo Optics agent for GraphQL-js

Here are the steps to enable Apollo Optics agent in your app. See below for details on each step:

  • Install the NPM package in your app: npm install optics-agent --save
  • Import the package in your main js file: import OpticsAgent from 'optics-agent';
  • Get an API key from the Optics web interface and configure the agent. Either:
    • Set the OPTICS_API_KEY environment variable to your API key
    • Set the API key and more with OpticsAgent.configureAgent({ options });
  • Instrument your app. In any order:
    • Instrument your schema: OpticsAgent.instrumentSchema(executableSchema);
    • Add the middleware: expressServer.use(OpticsAgent.middleware());
    • Add to your GraphQL context object: context.opticsContext = OpticsAgent.context(req);

Version requirements

Apollo Optics Agent supports:


First, install the package

npm install optics-agent --save


Next, set up the agent in your main server file.

Import the package

var OpticsAgent = require('optics-agent');

or in ES2015+

import OpticsAgent from 'optics-agent';

[optional] Configure the Agent

OpticsAgent.configureAgent({ configOptions })

Normally you do not need to call this function -- just set the OPTICS_API_KEY environment variable. Call this function if you set the API key in code instead of through the environment variable, or if you need to set specific non-default values for other options. Call this before any calls to instrumentation functions below.

Options include:

  • apiKey: String. Your API key for the Optics service. This defaults to the OPTICS_API_KEY environment variable, but can be overridden here.

  • reportTraces: Boolean. Send detailed traces along with usage reports. Defaults to true.

  • reportVariables: Boolean. Send the query variables along with traces. Defaults to true.

  • printReports: Boolean. Print a JSON version of reports as they are sent. This may be useful for debugging. Defaults to false.

  • normalizeQuery: Function(GraphQLResolveInfo)⇒String. Called to determine the query shape for for a GraphQL query. You shouldn't need to set this unless you are debugging.

  • endpointUrl: String. Where to send the reports. Defaults to the production Optics endpoint, or the OPTICS_ENDPOINT_URL environment variable if it is set. You shouldn't need to set this unless you are debugging.

  • proxyUrl: String. HTTP proxy to use when sending reports. Default to no proxying, or the HTTPS_PROXY environment variable if it is set. You should only set this when your servers cannot connect directly to the Optics service.

  • reportIntervalMs: Number. How often to send reports in milliseconds. Defaults to 1 minute. Minimum 10 seconds. You shouldn't need to set this unless you are debugging.

  • shutdownGracefully: Boolean. Send statistics when the process exits. Defaults to true.

Instrument your schema

Call instrumentSchema on the same executable schema object you pass to the graphql function from graphql-js:


You should only call this once per agent. If you have multiple or dynamic schemas, create a separate agent per schema (see below).

Add the middleware

Set up middleware:


Tell your server to run the Optics Agent middleware:


This must run before the handler that actually executes your GraphQL queries. For the most accurate timings, avoid inserting unnecessary middleware between the Optics Agent middleware and your GraphQL middleware.




Koa is not officially supported, but thanks to community contributions should work with:

const schema = OpticsAgent.instrumentSchema(executableSchema);
  graphqlKoa(async ctx => {
    // create an optic context
    const opticsContext = OpticsAgent.context(ctx.request);
    // create a context for each request
    const context = { opticsContext };
    return {

Add a context to each graphql request

Inside your request handler, if you are calling graphql directly, add a new field to the context object sent to graphql:

{ opticsContext: OpticsAgent.context(req) }

If you are using apolloExpress, this will be a field on the context object on the ApolloOptions value that you return.

If you are using HAPI you must explicitly use the raw request object:

{ opticsContext: OpticsAgent.context(request.raw.req) }


Here's an example diff:


diff --git a/api/index.js b/api/index.js
index 43ee586..f1a27a6 100644
--- a/api/index.js
+++ b/api/index.js
@@ -19,6 +19,11 @@ import { subscriptionManager } from './subscriptions';
 import schema from './schema';
+import OpticsAgent from 'optics-agent';
 let PORT = 3010;
 if (process.env.PORT) {
   PORT = parseInt(process.env.PORT, 10) + 100;
@@ -33,6 +38,7 @@ app.use(bodyParser.json());
+app.use('/graphql', OpticsAgent.middleware());
 app.use('/graphql', apolloExpress((req) => {
   // Get the query, the same way express-graphql does it
   // https://github.com/graphql/express-graphql/blob/3fa6e68582d6d933d37fa9e841da5d2aa39261cd/src/index.js#L257
@@ -70,6 +76,7 @@ app.use('/graphql', apolloExpress((req) => {
       Users: new Users({ connector: gitHubConnector }),
       Entries: new Entries(),
       Comments: new Comments(),
+      opticsContext: OpticsAgent.context(req),
diff --git a/package.json b/package.json
index 98df047..b110fac 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@ 
     "graphql-tools": "0.7.2",
     "knex": "0.12.3",
     "lodash": "4.16.4",
+    "optics-agent": "0.0.33",
     "passport": "0.3.2",
     "passport-github": "1.1.0",
     "request-promise": "4.1.1",

Advanced Usage

If you need to have more than one Agent per process, you can manually construct an Agent object instead of using the default global Agent. Call new OpticsAgent.Agent(options) to instantiate the object, and then call methods directly on the object instead of on OpticsAgent. Here is an example:

var OpticsAgent = require('optics-agent');
var agent = new OpticsAgent.Agent({ apiKey: '1234' });


The Optics agent is designed to allow your application to continue working, even if the agent is not configured properly.

No data in Optics

If there is no data being sent to Optics, check your application logs to look for the following messages:

Message: Please check the API key in the Optics agent configuration.

Solution: Get a valid API key from Optics and configure it in your GraphQL server.

Message: no API key specified. Set the apiKey option or set the OPTICS_API_KEY environment variable

Solution: Check the API key provided for this endpoint in Optics, and set it in your GraphQL server configuration

Message: schema not instrumented. Make sure instrumentSchema is called

Solution: In your server code, call instrumentSchema on the schema object you pass to the graphql function from graphql-js. OpticsAgent.instrumentSchema(executableSchema);

Message: Optics context not found. Make sure optics middleware is installed.

Solution: In your server code, set up the Optics middleware. app.use(OpticsAgent.middleware())



Package Sidebar


npm i optics-agent

Weekly Downloads






Last publish


  • glasser
  • pcarrier
  • timbotnik
  • martijnwalraven
  • nim
  • apollo-bot