{"id":16886,"library":"readmeio","title":"ReadMe Metrics SDK for Node.js","description":"The `readmeio` package provides a Node.js SDK for integrating server-side API metrics with ReadMe.com's API Metrics Dashboard. This library, currently at version 6.2.1, allows developers to track API usage, troubleshoot issues, and gain deep insights into API performance. It supports both generic Node.js integrations and specific middleware for frameworks like Express.js, enabling the capture of incoming request and outgoing response details. Key differentiators include its tight integration with the ReadMe.com platform for centralized API documentation and metrics visualization, and robust features for redacting sensitive parameters or headers before logs are sent. The SDK helps teams monitor aggregate usage data and analyze specific API calls within the ReadMe ecosystem. While no explicit release cadence is published, the project is actively maintained, receiving regular updates to support new features and address issues.","status":"active","version":"6.2.1","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/readmeio/metrics-sdks","tags":["javascript","api-metrics","readme","typescript"],"install":[{"cmd":"npm install readmeio","lang":"bash","label":"npm"},{"cmd":"yarn add readmeio","lang":"bash","label":"yarn"},{"cmd":"pnpm add readmeio","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The `Metrics` class is the primary entry point for manual API logging. While CommonJS `require` might work in some environments due to Node.js 14+ compatibility layers, ESM `import` is the recommended and more modern approach, especially in TypeScript projects.","wrong":"const Metrics = require('readmeio');","symbol":"Metrics","correct":"import { Metrics } from 'readmeio';"},{"note":"This named export provides a convenient middleware function for Express.js applications. Prefer destructuring for named exports. Direct property access on `require()` is a CommonJS pattern.","wrong":"const expressMiddleware = require('readmeio').expressMiddleware;","symbol":"expressMiddleware","correct":"import { expressMiddleware } from 'readmeio';"},{"note":"For type definitions in TypeScript, use `import type` to ensure they are removed during compilation, preventing potential runtime issues and ensuring proper tree-shaking.","wrong":"import { MetricsOptions } from 'readmeio';","symbol":"MetricsOptions","correct":"import type { MetricsOptions } from 'readmeio';"}],"quickstart":{"code":"import { Metrics } from 'readmeio';\nimport http from 'http';\n\n// Initialize the ReadMe Metrics SDK\n// In a real application, retrieve process.env.README_API_KEY and process.env.NODE_ENV securely\nconst metrics = new Metrics({\n  apiKey: process.env.README_API_KEY ?? 'your_readme_api_key_here',\n  development: process.env.NODE_ENV !== 'production',\n});\n\n// Create a simple HTTP server to simulate API calls\nconst server = http.createServer(async (req, res) => {\n  // Simulate an incoming request\n  const requestBody = { user: 'testuser', data: 'some data', sensitive_id: '12345' };\n  const requestHeaders = {\n    'content-type': 'application/json',\n    'x-api-key': 'super-secret-internal-key', // Example of a header that might be redacted\n    'user-agent': 'node-http-client',\n  };\n\n  // Simulate an outgoing response\n  const responseBody = { status: 'success', message: 'Hello from API', internal_ref: 'xyz' };\n  const responseHeaders = {\n    'content-type': 'application/json',\n    'x-response-id': 'uuid-12345',\n  };\n\n  // Log the request and response to ReadMe\n  try {\n    await metrics.log({\n      // Full URL is important for ReadMe metrics to categorize endpoints\n      url: new URL(`http://localhost:3000${req.url}`),\n      method: req.method ?? 'GET',\n      api: {\n        key: 'user-id-123', // Identifier for the user making the API call\n        // label: 'Optional label for this user/API key'\n      },\n      // Redaction example: prevent 'x-api-key' header from being sent to ReadMe\n      // and prevent 'user' field in request body\n      redact: {\n        headers: ['x-api-key'],\n        body: ['user', 'sensitive_id'],\n      },\n      request: {\n        headers: requestHeaders,\n        body: JSON.stringify(requestBody),\n      },\n      response: {\n        status: 200,\n        headers: responseHeaders,\n        body: JSON.stringify(responseBody),\n      },\n    });\n  } catch (error) {\n    console.error('Failed to log metrics:', error);\n  }\n\n  res.writeHead(200, { 'Content-Type': 'application/json' });\n  res.end(JSON.stringify(responseBody));\n});\n\nserver.listen(3000, () => {\n  console.log('Server running on http://localhost:3000');\n  console.log('Send a request, e.g., curl http://localhost:3000/api/test');\n  console.log('Check your ReadMe.com dashboard for metrics.');\n});\n\n// Example of how to shut down cleanly\nprocess.on('SIGINT', () => {\n  console.log('Shutting down server...');\n  server.close(async () => {\n    // Ensure any buffered logs are sent before exiting\n    try {\n      await metrics.sendQueue();\n      console.log('Buffered logs sent.');\n    } catch (error) {\n      console.error('Failed to send remaining logs:', error);\n    }\n    console.log('Server gracefully shut down.');\n    process.exit(0);\n  });\n});","lang":"typescript","description":"Demonstrates how to initialize the ReadMe Metrics SDK, create a basic HTTP server, and log simulated API requests and responses, including data redaction for sensitive fields, to the ReadMe.com dashboard. Includes graceful shutdown."},"warnings":[{"fix":"Store `apiKey` in environment variables and access them securely at runtime. Never hardcode sensitive credentials.","message":"Always protect your `apiKey` and ensure it's not exposed client-side or committed directly into source control. Use environment variables (e.g., `process.env.README_API_KEY`) and secure secret management practices.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Carefully define `redact.headers` and `redact.body` arrays to include all sensitive fields. Regularly audit the data sent to ReadMe.com to confirm redaction is working as intended.","message":"Improperly configured `redact` options can lead to sensitive data (like PII, authentication tokens, or internal IDs) being sent to ReadMe.com. Thoroughly test your redaction rules.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure `metrics.sendQueue()` is called during application shutdown hooks (e.g., `SIGINT`, `SIGTERM` handlers in Node.js, or before a serverless function completes) to flush any pending metrics. Handle potential `sendQueue` failures gracefully.","message":"The SDK buffers logs and sends them in batches. If your application terminates abruptly without calling `metrics.sendQueue()`, some logs might be lost. This is particularly relevant in serverless or short-lived processes.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Adopt ESM `import` syntax for all package imports. If using TypeScript, ensure your `tsconfig.json` is configured for `module: 'Node16'` or `module: 'ES2022'` and `moduleResolution: 'Node16'` or `Bundler`.","message":"While Node.js >=14 supports both CommonJS and ESM, future major versions of this SDK (or Node.js itself) may enforce ESM-only. Relying solely on `require()` could lead to breaking changes.","severity":"breaking","affected_versions":">=6.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure `apiKey` is passed to the `Metrics` constructor, typically from an environment variable (e.g., `new Metrics({ apiKey: process.env.README_API_KEY })`).","cause":"The `apiKey` option was not provided or was empty during the `Metrics` class instantiation.","error":"Error: You must provide an API key. Please visit https://dash.readme.com/project/YOUR_PROJECT/v1.0/api-metrics to get one."},{"fix":"Ensure you are using `import { Metrics } from 'readmeio';` for named imports. Verify your bundler configuration correctly handles ESM and CJS interop, especially if your project is `type: 'module'`.","cause":"This error often occurs in bundled environments (like Webpack or Vite) when mixing CommonJS `require` semantics with ESM `import` syntax, or incorrectly trying to import a named export as a default export.","error":"TypeError: (0 , readmeio__WEBPACK_IMPORTED_MODULE_0__.Metrics) is not a constructor"},{"fix":"Double-check that `new Metrics({ ... })` was successfully called and that the resulting instance is available when `log` is invoked. Ensure there are no asynchronous initialization issues preventing `metrics` from being assigned.","cause":"The `metrics` object was not correctly instantiated, or `log` was called before the object was fully initialized.","error":"TypeError: metrics.log is not a function"},{"fix":"Migrate your import statements from `const { Metrics } = require('readmeio');` to `import { Metrics } from 'readmeio';`. Ensure your project and build tools are configured to handle ESM.","cause":"Attempting to use `require('readmeio')` in a pure ESM context (e.g., in a Node.js project with `\"type\": \"module\"` in `package.json` where `readmeio` might not provide a CommonJS entry point for that specific environment).","error":"ERR_REQUIRE_ESM"}],"ecosystem":"npm","meta_description":null}