Skip to content

Repository files navigation

Apitally logo

API monitoring & analytics made simple

Metrics, logs, traces, and alerts for your APIs — with just a few lines of code.


Apitally dashboard


Apitally SDK for JavaScript

Tests Codecov npm

Apitally is a simple API monitoring and analytics tool that makes it easy to understand API usage, monitor performance, and troubleshoot issues. Get started in minutes by just adding a few lines of code. No infrastructure changes required, no dashboards to build.

The SDK is an OpenTelemetry distribution and works alongside an existing OpenTelemetry setup.

Learn more about Apitally on our 🌎 website or check out the 📚 documentation.

Important

Upgrading from 0.x? Version 1.0 is a full rewrite with a new setup API. See the migration guide for how to upgrade.

Key features

  • API analytics: Traffic, error and performance metrics for your API, each endpoint, and per API consumer. Drill down from metrics to individual API requests.
  • Request logs and traces: Every request as a searchable log entry, with optional capture of headers and request/response bodies. Requests are exported as OpenTelemetry spans, including spans from any other instrumentations you have.
  • Application logs: Logs written via console and other supported loggers are captured automatically and correlated with the requests they belong to.
  • Error tracking: Validation errors and exceptions with stack traces for server errors, automatically linked to Sentry events if you use Sentry.
  • Server metrics: CPU and memory usage of your app's processes.
  • API monitoring & alerts: Get notified if something isn't right using custom alerts, synthetic uptime checks and heartbeat monitoring. Alert notifications can be delivered via email, Slack and Microsoft Teams.

Supported frameworks

The SDK supports Node.js ^20.16 or >= 22.3 and Bun >= 1.2.0.

Framework Supported versions Setup guide
AdonisJS >= 6.3, < 8 Link
Elysia >= 1.1, < 2 Link
Express >= 4.18.2, < 6 Link
Fastify >= 4.10.2, < 6 Link
H3 >= 2.0.1-rc.26, < 3 Link
Hapi 21.x Link
Hono * >= 4.8.4, < 5 Link
Koa 2.x, 3.x Link
NestJS 10.x, 11.x, 12.x Link

* For Hono on Cloudflare Workers use our Serverless SDK instead.

Apitally also supports many other web frameworks in Python, Go and .NET via our other SDKs.

Getting started

If you don't have an Apitally account yet, first sign up here. Then create an app in the Apitally dashboard. You'll see detailed setup instructions with code snippets you can copy and paste. These also include your write token.

Install the SDK in your project:

npm install apitally

AdonisJS

Run the Ace add command from your application directory:

node ace add apitally

The command installs Apitally, asks for your write token and environment, and sets up the provider, middleware, and exception handling. To change settings later, edit config/apitally.ts.

For further instructions, see our setup guide for AdonisJS.

Elysia

Register apitallyPlugin() immediately after creating the app, before registering plugins and routes:

import { Elysia } from "elysia";
import { apitallyPlugin } from "apitally/elysia";

const app = new Elysia().use(
  apitallyPlugin({
    writeToken: "your-write-token",
    env: "dev",
  }),
);

// register plugins and routes below this point

For further instructions, see our setup guide for Elysia.

Express

Import apitally/express/register on the first line of your entry module, then call useApitally(app) anywhere after creating the app:

import "apitally/express/register"; // must be the first import

import express from "express";
import { useApitally } from "apitally";

const app = express();

useApitally(app, {
  writeToken: "your-write-token",
  env: "dev",
});

For further instructions, see our setup guide for Express.

Fastify

Call useApitally(app) immediately after creating the app, before registering plugins and routes:

import Fastify from "fastify";
import { useApitally } from "apitally";

const app = Fastify();

useApitally(app, {
  writeToken: "your-write-token",
  env: "dev",
});

// register plugins and routes below this point

For further instructions, see our setup guide for Fastify.

H3

Add apitallyPlugin() to the plugins of your root H3 app:

import { H3 } from "h3";
import { apitallyPlugin } from "apitally/h3";

const app = new H3({
  plugins: [
    apitallyPlugin({
      writeToken: "your-write-token",
      env: "dev",
    }),
  ],
});

For further instructions, see our setup guide for H3.

Hapi

Register apitallyPlugin() immediately after creating the server, before registering other plugins and routes:

import Hapi from "@hapi/hapi";
import { apitallyPlugin } from "apitally/hapi";

const server = Hapi.server({ port: 3000 });

await server.register(
  apitallyPlugin({
    writeToken: "your-write-token",
    env: "dev",
  }),
);

// register other plugins and routes below this point
await server.start();

For further instructions, see our setup guide for Hapi.

Hono

Call useApitally(app) immediately after creating the app, before registering middleware and routes:

import { Hono } from "hono";
import { useApitally } from "apitally";

const app = new Hono();

useApitally(app, {
  writeToken: "your-write-token",
  env: "dev",
});

// register middleware and routes below this point

For further instructions, see our setup guide for Hono.

Koa

Call useApitally(app) immediately after creating the app, before registering middleware and routes:

import Koa from "koa";
import { useApitally } from "apitally";

const app = new Koa();

useApitally(app, {
  writeToken: "your-write-token",
  env: "dev",
});

// register middleware and routes below this point

For further instructions, see our setup guide for Koa.

NestJS

Call useApitally(app) immediately after creating the app, before calling app.init() or app.listen():

import { NestFactory } from "@nestjs/core";
import { useApitally } from "apitally/nestjs";
import { AppModule } from "./app.module.js";

const app = await NestFactory.create(AppModule);

useApitally(app, {
  writeToken: "your-write-token",
  env: "dev",
});

await app.listen(3000);

For further instructions, see our setup guide for NestJS.

Configuration

Pass configuration options to useApitally(), or to apitallyPlugin() for Elysia, H3, and Hapi. For AdonisJS, set them in config/apitally.ts. See the SDK reference for all available options.

Environment variables

To keep configuration out of your code, set these environment variables instead of passing the matching options:

  • APITALLY_WRITE_TOKEN: the write token (writeToken)
  • APITALLY_ENV: the environment name (env), defaults to dev
  • APITALLY_DISABLED: set to true to disable Apitally (disabled)

Request and response data

Apitally captures response headers by default. To also capture request headers and request and response bodies, pass these options:

useApitally(app, {
  writeToken: "your-write-token",
  env: "dev",
  captureRequestHeaders: true,
  captureRequestBody: true,
  captureResponseBody: true,
});

Apitally automatically masks common sensitive values, such as password fields and the Authorization header. To mask additional values, pass regular expressions to maskQueryParams, maskHeaders, and maskBodyFields. See our documentation on masking for details.

Exclusions and sampling

Apitally automatically excludes common health checks and static assets, such as /healthz and /robots.txt, from logs and traces. To exclude additional paths, pass regular expressions to excludePaths.

To capture logs and traces for only a fraction of the remaining requests, set sampleRate, for example to 0.1 for 10%. To decide for each request individually, pass a callback to sampleOnRequest or sampleOnResponse.

Metrics always include all requests. See our documentation on sampling for details.

Application logs

Apitally captures logs written with these loggers and correlates them with the requests they belong to:

  • console
  • Pino
  • Winston
  • NestJS Logger
  • Hapi request.log()

To mask or drop individual log records, pass a callback to maskLogRecord. To turn off log capture, set captureLogs: false.

See our documentation on masking for details.

Adding context to requests

The following functions add context to the current request. Call them while handling a request, for example in a route handler, middleware, or authentication code.

Consumers

To associate the request with the API consumer making it, call setConsumer. Only identifier is required. You can also pass it as a string, for example setConsumer(user.identifier).

import { setConsumer } from "apitally";

setConsumer({
  identifier: user.identifier,
  name: user.name,
  group: user.group,
  attributes: { plan: user.plan },
});

Custom attributes

To attach custom data to the request's trace, call setRequestAttribute. The sampleOnResponse, maskRequestBody, and maskResponseBody callbacks can also read these attributes.

import { setRequestAttribute } from "apitally";

setRequestAttribute("tenant.id", tenantId);

See our documentation on attributes for details.

Handled exceptions

To capture an exception that your code handles itself, call captureException. Unhandled exceptions are captured automatically.

import { captureException } from "apitally";

try {
  processOrder();
} catch (error) {
  captureException(error);
}

Existing OpenTelemetry setup

If your app already registers its own tracer provider, for example with NodeSDK, add ApitallySpanProcessor to its span processors. Apitally then uses your tracer provider instead of registering its own, and keeps your existing exporters.

import { NodeSDK } from "@opentelemetry/sdk-node";
import { ApitallySpanProcessor } from "apitally";

const sdk = new NodeSDK({
  spanProcessors: [new ApitallySpanProcessor()],
  // ...your existing configuration
});

If you use version 10.x of the Sentry SDK, which registers its own tracer provider, add ApitallySpanProcessor to the openTelemetrySpanProcessors option in Sentry.init() and enable Sentry tracing.

Your tracer provider's sampler also applies to Apitally. Requests it drops have no request logs or traces in Apitally, but still count in metrics.

Graceful shutdown

If your code calls process.exit(), await shutdown() before it so Apitally can send any remaining telemetry:

import { shutdown } from "apitally";

process.on("SIGTERM", () => {
  server.close(async () => {
    await shutdown();
    process.exit(0);
  });
});

Trusted proxies

If your app runs behind a reverse proxy or load balancer, configure trusted proxies in your framework, for example with Express's trust proxy setting or Fastify's trustProxy option. Apitally records the client IP your framework reports and uses it for GeoIP.

Getting help

If you need help please create a new discussion on GitHub or email us at support@apitally.io. We'll get back to you as soon as possible.

License

This library is licensed under the terms of the MIT license.

Releases

Used by

Contributors

Languages