Mask sensitive data and exclude requests from logging with the Apitally SDK for JavaScript.
When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don’t want to log.
The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named password, token, secret, or headers like Authorization are masked by default.To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as /robots.txt or /healthz.See the data privacy page for complete lists of default masking and exclusion patterns.
You can extend the default masking rules by providing additional regular expressions via the maskQueryParams, maskHeaders, and maskBodyFields parameters. Patterns match anywhere within the name. Use ^ and $ anchors for exact matches, and the i flag for case-insensitive matching.For more control over request and response body masking, you can provide callback functions via the maskRequestBodyCallback and maskResponseBodyCallback parameters. The functions receive the captured request and response data as arguments (see callback arguments below) and should return the masked body as Buffer, or null to mask the entire body.
import { Hono } from "hono";import { useApitally } from "apitally/hono";const app = new Hono();useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, },});
import { NestFactory } from "@nestjs/core";import { useApitally } from "apitally/nestjs";import { AppModule } from "./app.module";async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, }, });}
import express from "express";import { useApitally } from "apitally/express";const app = express();useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, },});
import Fastify from "fastify";import { apitallyPlugin } from "apitally/fastify";const fastify = Fastify({ logger: true });await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, },});
Callback function examples
function maskRequestBody(request) { // Mask entire request body for admin endpoints if (request.path?.startsWith("/admin/")) { return null; } // Otherwise, return the original request body return request.body;}function maskResponseBody(request, response) { // Mask entire response body for admin endpoints if (request.path?.startsWith("/admin/")) { return null; } // Mask specific fields in user profile responses if (request.path?.startsWith("/users/") && response.body) { try { const data = JSON.parse(response.body.toString()); if (typeof data === "object" && data !== null) { if ("email" in data) { data.email = "******"; } if ("phone" in data) { data.phone = "******"; } return Buffer.from(JSON.stringify(data)); } } catch { // If parsing fails, return original body } } // Otherwise, return the original response body return response.body;}
Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom maskBodyFields patterns.
You can exclude requests from logging using path patterns (regular expressions) via the excludePaths parameter. Like the masking patterns, these match anywhere within the request path. Use ^ and $ anchors for exact matches, and the i flag for case-insensitive matching.Alternatively, you can provide a callback function with custom exclusion logic via the excludeCallback parameter. The function receives the captured request and response data as arguments (see callback arguments below) and should return true to exclude the request from logging, or false to include it.
import { Hono } from "hono";import { useApitally } from "apitally/hono";const app = new Hono();useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, },});
import { NestFactory } from "@nestjs/core";import { useApitally } from "apitally/nestjs";import { AppModule } from "./app.module";async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, }, });}
import express from "express";import { useApitally } from "apitally/express";const app = express();useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, },});
import Fastify from "fastify";import { apitallyPlugin } from "apitally/fastify";const fastify = Fastify({ logger: true });await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, },});
Callback function example
function excludeRequest(request, response) { // Exclude requests from a specific consumer if (request.consumer === "internal-service") { return true; } // Exclude successful requests (only log failures) if (response.statusCode < 400) { return true; } return false;}
Excluded requests won’t be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the dashboard.