Add Security Monitoring to a Next.js App with SecureNow — Traces, Logs, and Body Capture on AWS
Step-by-step guide to integrating SecureNow into a self-hosted Next.js application on AWS EC2. Covers installation, instrumentation, environment configuration, verifying traces and logs, enabling request body capture, and creating alert rules.

Add Security Monitoring to a Next.js App with SecureNow — Traces, Logs, and Body Capture on AWS
Skip the tutorial — paste this into Cursor, Copilot, or any AI assistant and it will wire SecureNow into your Next.js app in one shot:
1. Run: npm install securenow
2. Read the package docs at node_modules/securenow/README.md
3. In next.config.ts, add serverExternalPackages for:
securenow, @vercel/otel, @opentelemetry/api, @opentelemetry/sdk-node,
@opentelemetry/exporter-trace-otlp-http, @opentelemetry/exporter-logs-otlp-http,
@opentelemetry/auto-instrumentations-node
4. Create src/instrumentation.ts:
- import { registerSecureNow } from "securenow/nextjs" and call it
- import "securenow/nextjs-auto-capture" for body capture
5. Add these env vars to .env:
SECURENOW_APPID=<my-app-key>
SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
SECURENOW_LOGGING_ENABLED=1
SECURENOW_CAPTURE_BODY=1
SECURENOW_NO_UUID=1
6. Rebuild and restart the app
Get your app key by running npx securenow login then npx securenow apps create my-app. Read on for the full walkthrough.
You have a Next.js application running on AWS. Users are logging in, submitting data, calling API routes. But you have no visibility into what those requests contain, who is making them, or whether the patterns look normal.
SecureNow fixes that by plugging into Next.js's built-in instrumentation hook. Every server-side request becomes an OpenTelemetry trace — with full HTTP metadata, client IPs, headers, database timings, and optionally the request and response bodies. Those traces feed into a security analysis engine that lets you run forensic queries, detect anomalies, and trigger alerts.
This guide walks through integrating SecureNow into a real application: a Hacker News clone running on EC2 with PostgreSQL. The same steps apply to any self-hosted Next.js app.
Live demo: https://hn.securenow.ai
What SecureNow Captures
Once integrated, every request to your application generates a trace containing:
- HTTP metadata — method, URL, status code, response time
- Client identity — IP address (proxy-aware via
X-Forwarded-For,X-Real-IP), User-Agent, Referer, Origin - Security signals — auth presence, CSRF tokens, request IDs
- Infrastructure context — protocol, host, port, geographic data
- Database timings — Prisma/pg query durations via auto-instrumentation
- Console logs —
console.log,warn,errorforwarded as structured OTLP log records - Request/response bodies — with automatic redaction of sensitive fields
No code changes to your route handlers. No middleware wrappers. Just one file and a few environment variables.
Prerequisites
- A Next.js 13.4+ application (App Router or Pages Router)
- Node.js 18+
- A terminal and a browser (for CLI authentication)
Step 1: Install SecureNow
npm install securenow
During installation, the postinstall script detects your Next.js project and offers to create the instrumentation file automatically. You can accept that or set it up manually in the next step.
Step 2: Configure next.config.ts
Add serverExternalPackages so webpack does not bundle the OpenTelemetry packages — they need to run as native Node.js requires for runtime instrumentation to work:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
// If deploying to a VM (EC2, etc.), standalone is recommended
output: "standalone",
serverExternalPackages: [
"securenow",
"@vercel/otel",
"@opentelemetry/api",
"@opentelemetry/sdk-node",
"@opentelemetry/exporter-trace-otlp-http",
"@opentelemetry/exporter-logs-otlp-http",
"@opentelemetry/auto-instrumentations-node",
],
};
export default nextConfig;
If you are deploying to Vercel instead of a VM, you can omit output: "standalone" — the rest stays the same.
Step 3: Create the Instrumentation File
Create src/instrumentation.ts (or instrumentation.ts at the project root if you do not use a src/ directory):
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
const { registerSecureNow } = await import("securenow/nextjs");
registerSecureNow();
await import("securenow/nextjs-auto-capture");
}
}
This is the standard Next.js instrumentation hook. When the Node.js server starts:
registerSecureNow()initializes the OpenTelemetry SDK with trace and log exporters pointed at your SecureNow instance. On EC2/PM2 it uses the vanilla@opentelemetry/sdk-node; on Vercel it automatically switches to@vercel/otel.securenow/nextjs-auto-capturepatchesNextRequestto intercept request and response bodies and attach them as span attributes — no wrapper functions needed around your route handlers.
If you only want traces and logs without body capture, omit the second import.
Step 4: Authenticate with the CLI
npx securenow login your@email.com
This opens a browser window. Complete authentication and the CLI stores a session token locally. Verify it worked:
npx securenow whoami
Current Session
Email your@email.com
User ID abc123...
API https://api.securenow.ai
Expires in 30 days
Step 5: Create an Application
Each monitored app needs an application entry in SecureNow. Create one from the CLI:
npx securenow apps create my-nextjs-app
Application created
Name my-nextjs-app
Key dc645fcd-ef8a-4b5e-a841-10e6d8a62619
Instance Free Trial (https://freetrial.securenow.ai:4318)
The Key is your SECURENOW_APPID. The Instance URL is the OTLP endpoint where traces and logs are sent.
Optionally set it as the default for CLI commands:
npx securenow config set defaultApp dc645fcd-ef8a-4b5e-a841-10e6d8a62619
Step 6: Set Environment Variables
Add the following to your .env (or .env.local for local development):
# SecureNow — required
SECURENOW_APPID="dc645fcd-ef8a-4b5e-a841-10e6d8a62619"
SECURENOW_INSTANCE="https://freetrial.securenow.ai:4318"
# SecureNow — enable logs and body capture
SECURENOW_LOGGING_ENABLED=1
SECURENOW_CAPTURE_BODY=1
SECURENOW_NO_UUID=1
What each variable does:
| Variable | Purpose |
|---|---|
SECURENOW_APPID | Links all telemetry data to your application in the dashboard |
SECURENOW_INSTANCE | OTLP collector endpoint — the free trial or your own ClickHouse instance |
SECURENOW_LOGGING_ENABLED=1 | Forwards console.log, warn, error as OTLP log records |
SECURENOW_CAPTURE_BODY=1 | Captures request/response JSON bodies on traces (with auto-redaction) |
SECURENOW_NO_UUID=1 | Uses the APPID directly as the OpenTelemetry service name, without appending a random UUID |
Optional tuning variables:
| Variable | Default | Purpose |
|---|---|---|
SECURENOW_MAX_BODY_SIZE | 10240 | Max body size in bytes to capture (larger bodies are truncated) |
SECURENOW_SENSITIVE_FIELDS | — | Comma-separated extra field names to redact (added to built-in defaults like password, token, secret) |
OTEL_LOG_LEVEL | warn | OpenTelemetry SDK log verbosity (debug, info, warn, error) |
SECURENOW_TEST_SPAN | — | Set to 1 to emit a test span on startup for connectivity verification |
Step 7: Build and Deploy
If you are deploying to a self-hosted server (EC2, DigitalOcean, etc.), build the standalone output and copy the env file into it:
npm run build
cp -r .next/static .next/standalone/.next/static
mkdir -p .next/standalone/public && cp -r public/* .next/standalone/public/
cp .env .next/standalone/.env
Start with PM2:
cd .next/standalone
PORT=3000 pm2 start server.js --name my-app
On Vercel, just add the environment variables in the Vercel dashboard and deploy normally.
Step 8: Verify the Integration
Check the application logs to confirm SecureNow loaded correctly:
pm2 logs my-app --lines 20 --nostream
You should see output like this:
[securenow] Next.js integration loading (pid=8977)
[securenow] 🖥️ Self-hosted environment detected (EC2/PM2) - using vanilla SDK
[securenow] 🎯 Vanilla SDK initialized for self-hosted environment
[securenow] 📋 Logging: ENABLED → https://freetrial.securenow.ai:4318/v1/logs
[securenow] 📋 HTTP request logging: ENABLED
[securenow] ✅ OpenTelemetry started for Next.js → https://freetrial.securenow.ai:4318/v1/traces
[securenow] 📊 Auto-capturing comprehensive request metadata:
[securenow] • IP addresses (x-forwarded-for, x-real-ip, socket)
[securenow] • User-Agent, Referer, Origin, Accept headers
[securenow] • Protocol, Host, Port (proxy-aware)
[securenow] • Geographic data (Vercel/Cloudflare)
[securenow] • Request IDs, CSRF tokens, Auth presence
[securenow] • Response status, content-type, content-length
[securenow] ✅ Auto-capture: Patched Next.js Request for automatic body capture
[securenow] 📝 Automatic body capture: ENABLED
[securenow] 💡 No code changes needed - bodies captured automatically!
Key lines to confirm:
Self-hosted environment detected— SecureNow chose the right SDK modeLogging: ENABLED— console output is being forwarded as OTLP logsOpenTelemetry started— traces are being exported to your endpointAutomatic body capture: ENABLED— request/response bodies are being captured
As requests come in, you will also see per-request log lines:
[securenow] GET / 200 17ms
[securenow] GET /api/stories 200 9ms
[securenow] POST /api/vote 200 23ms
Step 9: Explore the Dashboard
Open the SecureNow dashboard to see your data:
- Traces — every HTTP request with full metadata, timings, and body content
- Logs — structured log records from
console.log/warn/error - API Map — auto-discovered endpoints and their traffic patterns
- Forensics — natural-language queries across your trace data (e.g., "Show me all POST requests to /api/auth with status 401 in the last hour")
You can also use the CLI to inspect data:
# Check dashboard overview
npx securenow status
# View recent traces
npx securenow traces list --limit 10
# View logs
npx securenow logs --limit 10
# Run forensic queries
npx securenow forensics "requests with status 500 in the last 24 hours"
Step 10: Set Up Alert Rules
With traces flowing, you can create alert rules that run on a schedule and notify you when something looks wrong.
1. Create a Notification Channel
Go to Dashboard → Notifications and add a channel — Email, Slack, Discord, or a webhook URL. This is where alerts get delivered.
2. Save a Forensic Query
Go to Dashboard → Forensics, write a query, and click Save to Library. Examples:
Show me all requests with status code 500 in the last hourIPs making more than 100 requests per minutePOST requests to /api/auth/register from the same IP in the last 30 minutesRequests with SQL injection patterns in the request body
3. Create an Alert Rule
Go to Dashboard → Alerting → Rules and create a rule:
- Query — select one of your saved forensic queries
- Schedule — how often to check (every 5 min, 15 min, hourly, daily)
- Channels — which notification channels to alert
- Applications — scope to specific apps
- Throttle — minimum minutes between repeated alerts
Example rules worth setting up:
| Rule | Query | Schedule |
|---|---|---|
| Error spike | http.status_code >= 500 | Every 5 min |
| Auth brute force | POST /api/auth with status 401, grouped by IP | Every 15 min |
| Suspicious user-agent | Requests with bot/scanner/sqlmap in User-Agent | Every 15 min |
| High request rate | IPs with more than 200 requests in 5 minutes | Every 5 min |
| Unusual payload | Requests containing script tags or SQL keywords in body | Every 15 min |
Troubleshooting
Traces work but no logs appear
Make sure SECURENOW_LOGGING_ENABLED=1 is in your .env. For self-hosted Next.js with standalone output, the .env file must be copied into the .next/standalone/ directory. After changing env vars, clear the build cache and rebuild:
rm -rf .next && npm run build
Body capture shows as disabled
If the logs show Body capture DISABLED at HTTP instrumentation level, make sure you have the auto-capture import in your instrumentation.ts:
await import("securenow/nextjs-auto-capture");
This line must come after registerSecureNow(). The auto-capture module patches NextRequest at the framework level, which is why it works without wrapping individual route handlers.
Sensitive data in body capture
Body capture automatically redacts fields named password, token, secret, authorization, cookie, credit_card, and similar patterns. To add your own:
SECURENOW_SENSITIVE_FIELDS="ssn,date_of_birth,bank_account"
OpenTelemetry debug output
To see detailed SDK diagnostics, set:
OTEL_LOG_LEVEL=debug
This will log every span export, batch flush, and connection attempt — useful for verifying the OTLP endpoint is reachable.
Summary
Integrating SecureNow into a Next.js app takes three things:
- One npm package —
npm install securenow - One file —
instrumentation.tswithregisterSecureNow()and optionallynextjs-auto-capture - A few env vars —
SECURENOW_APPID,SECURENOW_INSTANCE, and your feature flags
From there, every request is traced with full HTTP metadata, client identity, database timings, and optionally request bodies — all feeding into a dashboard where you can query, alert, and investigate security events without touching your application code.
Frequently Asked Questions
Does SecureNow add latency to my API routes?
No. OpenTelemetry instrumentation adds less than 1% overhead. Traces and logs are exported asynchronously in batches, so request handling is never blocked by telemetry export.
What's the difference between Vercel and self-hosted?
SecureNow auto-detects the environment. On Vercel it uses @vercel/otel under the hood. On EC2 or any self-hosted setup it uses the vanilla @opentelemetry/sdk-node with full auto-instrumentation. The developer-facing API is identical — same instrumentation.ts file, same env vars.
What data does body capture collect?
When SECURENOW_CAPTURE_BODY is enabled, request and response JSON bodies are attached as span attributes. Sensitive fields like password, token, secret, authorization, and credit card numbers are automatically redacted. You can add custom fields to redact via the SECURENOW_SENSITIVE_FIELDS env var.
Can I use this with Express or Fastify instead of Next.js?
Yes. For non-Next.js apps, use the register entry point: node -r securenow/register app.js. It initializes the same OpenTelemetry SDK with auto-instrumentation for HTTP, database clients, and more.
What alerts can I set up with SecureNow?
SecureNow supports query-based alert rules. You can alert on status code spikes (5xx errors), suspicious IPs, unusual request patterns, SQL injection attempts, credential stuffing, high request rates from a single IP, and more. Alerts can be sent to Email, Slack, Discord, and webhooks.
Recommended reading
A hands-on walkthrough for adding security observability to a Nuxt 3 app using the securenow npm package and official Nuxt module. Covers installation, nuxt.config.ts setup, environment variables, optional tuning, deployment targets, CLI verification, and troubleshooting.
Apr 2Stop juggling --require and --import flags. securenow/register now auto-registers the ESM loader hook via module.register() on Node >=20.6, so a single -r flag is all you need for both CommonJS and ESM apps.
Apr 2Step-by-step guide to adding security monitoring to your Fastify API with the securenow npm package. Covers CLI setup, instrumentation, body capture caveats, PM2, Docker, and dashboard verification.
Mar 26