# Connect a Strapi app

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

Source: https://www.apitraffic.io/docs/integrations/strapi

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](https://www.apitraffic.io/docs/integrations/koa), 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](https://www.apitraffic.io/docs/account/api-tokens).
- **Outbound HTTPS** from your servers to `ingest.apitraffic.io` and `api.apitraffic.io`.

## Set up the plugin

**Install the plugin**

```bash npm
npm install @apitraffic/strapi
```

```bash pnpm
pnpm add @apitraffic/strapi
```

```bash yarn
yarn add @apitraffic/strapi
```

```bash bun
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 config/middlewares.js
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 .env
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](https://www.apitraffic.io/docs/integrations/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 config/plugins.js
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](https://www.apitraffic.io/docs/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 src/api/article/controllers/article.js
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](https://www.apitraffic.io/docs/integrations/node#embed-tokens). Tags follow the [tag rules](https://www.apitraffic.io/docs/tags#the-tag-rules); see [Per-request APIs](https://www.apitraffic.io/docs/integrations/configuration#per-request-apis).

## Firewall and APM

The Strapi plugin provides request and outbound capture only. The [web application firewall](https://www.apitraffic.io/docs/waf/overview) and [APM](https://www.apitraffic.io/docs/apm/overview) 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](https://www.apitraffic.io/docs/account/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.

## Related

- [SDK configuration](https://www.apitraffic.io/docs/integrations/configuration):
    Every option and environment variable the plugin accepts.

- [Koa](https://www.apitraffic.io/docs/integrations/koa):
    The adapter the plugin is built on.

- [Redactions](https://www.apitraffic.io/docs/data/redactions):
    Mask sensitive fields before they leave your server.

- [Request log](https://www.apitraffic.io/docs/traffic/request-log):
    See and search the requests Strapi served.
