Connect a Strapi app

Add the @apitraffic/strapi plugin to a Strapi 5 app: install, register the middleware, configure credentials, verify and troubleshoot.

This page as Markdown

The ApiTraffic plugin for Strapi captures every request your Strapi app serves and the calls Strapi makes to other APIs. It is built on the Koa adapter, since Strapi runs on Koa, and is configured through environment variables.

Before you begin

  • Strapi 5, on Node.js 20 or later.
  • An ingest token and a bucket ID. The setup page in ApiTraffic creates the token for you if you are an owner or admin; see API tokens.
  • Outbound HTTPS from your servers to ingest.apitraffic.io and api.apitraffic.io.

Set up the plugin

Install the plugin

bash
npm install @apitraffic/strapi
bash
pnpm add @apitraffic/strapi
bash
yarn add @apitraffic/strapi
bash
bun add @apitraffic/strapi

Add the middleware

Add plugin::apitraffic.apitraffic to the array in config/middlewares.js. Leave the middlewares Strapi ships with in place and add it after them:

javascript
module.exports = [
  'strapi::logger',
  'strapi::errors',
  'strapi::security',
  'strapi::cors',
  'strapi::poweredBy',
  'strapi::query',
  'strapi::body',
  'strapi::session',
  'strapi::favicon',
  'strapi::public',
  'plugin::apitraffic.apitraffic'
];

Installing the plugin is not enough on its own: without this entry, nothing is captured.

Set your credentials

Add your token and bucket ID to Strapi’s .env file, or set them wherever you set your other environment variables. Strapi loads .env itself.

bash
API_TRAFFIC_TOKEN=your-ingest-token
API_TRAFFIC_BUCKET=your-bucket-id

Restart Strapi and make a request

Restart Strapi so it reads the variables, then call any endpoint, for example GET /api/articles. The setup page in ApiTraffic shows SDK connected - waiting for a request once the plugin connects and Traffic is flowing when the request arrives.

Configure the plugin

The plugin reads API_TRAFFIC_TOKEN and API_TRAFFIC_BUCKET by default. Every other API_TRAFFIC_* variable from SDK configuration applies as well, for example API_TRAFFIC_DEBUG=true or API_TRAFFIC_INTERCEPT_OUTBOUND=false.

To set options in code instead, add them to the plugin’s configuration in config/plugins.js. Any option from the SDK configuration reference can go here:

javascript
module.exports = ({ env }) => ({
  apitraffic: {
    config: {
      token: env('API_TRAFFIC_TOKEN'),
      bucket: env('API_TRAFFIC_BUCKET'),
      debug: env.bool('API_TRAFFIC_DEBUG', false)
    }
  }
});

If the token or bucket is missing, Strapi logs [apitraffic] token (API_TRAFFIC_TOKEN) … not set; request capture is disabled. at startup and the middleware passes requests through untouched. It never stops Strapi from starting or serving.

What is captured

  • Every request that reaches the middleware, including ones whose controller throws (reported with the status Strapi’s error handling sends) and ones the client abandons (reported as 499).
  • The request body as Strapi parsed it, and the response body as your controller set it - not a compressed form of it. Streamed responses such as file downloads are recorded as a placeholder.
  • The route Strapi matched, with its /api prefix, so GET /api/articles/42 is grouped as /api/articles/{id}.
  • Outbound calls your Strapi code makes with http, https or fetch. See Outbound requests.
  • Each request once, even if the middleware is listed twice.

Tags, traces and spans

The plugin exposes the Koa adapter’s request helpers through its sdk service. Use them in controllers, services and policies:

javascript
const { factories } = require('@strapi/strapi');

module.exports = factories.createCoreController('api::article.article', ({ strapi }) => ({
  async find(ctx) {
    const apitraffic = strapi.plugin('apitraffic').service('sdk');

    apitraffic.tag('tenant', String(ctx.state.user?.tenantId ?? 'public'));
    return apitraffic.span('db.query', 'load articles', () => super.find(ctx));
  }
}));

The service also offers trace, startSpan, embedToken, flush and shutdown. embedToken() mints with an Administrator API token set as API_TRAFFIC_EMBED_TOKEN, not the ingest token; see Embed tokens. Tags follow the tag rules; see Per-request APIs.

Firewall and APM

The Strapi plugin provides request and outbound capture only. The web application firewall and APM spans, which @apitraffic/node adds for Express, Fastify, Koa and hapi, are not part of it.

Shut down

The plugin stops the SDK in Strapi’s destroy phase: it delivers what was captured, waiting up to 2 seconds, then releases the realtime connection and hooks, so Strapi’s shutdown and strapi develop restarts are not held up. You do not need to call shutdown() yourself. Use strapi.plugin('apitraffic').service('sdk').flush() to deliver captured requests before a process is frozen or recycled.

Troubleshooting

Nothing is captured after installing the plugin

  • Check that plugin::apitraffic.apitraffic is in config/middlewares.js.
  • Look for [apitraffic] … not set; request capture is disabled. in the Strapi log: the token or bucket did not reach the process.
  • Restart Strapi after changing .env or the configuration files.

The log says the token was rejected

ApiTraffic: token rejected (HTTP 401) or (HTTP 403) means the token is invalid or cannot access the bucket in API_TRAFFIC_BUCKET. Check both values; a token belongs to one environment. See API tokens.

Routes are grouped by raw path

The route is sent by plugin builds that use @apitraffic/koa 2.0 or later. Update the plugin, and its @apitraffic/koa dependency, to the latest version.

  • SDK configuration: Every option and environment variable the plugin accepts.

  • Koa: The adapter the plugin is built on.

  • Redactions: Mask sensitive fields before they leave your server.

  • Request log: See and search the requests Strapi served.