npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@steadphast/connector-nextjs

v0.5.4

Published

Next.js Middleware and Proxy connector for Steadphast: captures request metadata before it reaches your app and sends it to Steadphast for AI and bot traffic classification, without touching the response.

Readme

@steadphast/connector-nextjs

The Next.js connector for Steadphast. It runs in your Next.js Middleware (Next.js 15) or Proxy (Next.js 16), captures request metadata before the request reaches your application, and sends a bounded, sanitized record of each request to Steadphast in the background. Steadphast classifies the traffic server-side: the connector never reads a request body, never runs any classification, and never changes the response your visitor receives.

The package is one connector with two modes: Next.js on Vercel (kind: "vercel") and Next.js self-hosted (kind: "self-hosted").

 Visitor / bot                Your Next.js deployment                      Steadphast
 ─────────────                ───────────────────────                      ──────────
      │  request                       │                                        │
      ├───────────────────────────────►│ middleware.ts / proxy.ts               │
      │                                │  1. skip static assets                 │
      │                                │  2. read method, URL, headers only     │
      │                                │  3. drop recognized credential headers │
      │                                │     + your excludedHeaders             │
      │                                │  4. build one bounded record           │
      │                                │  5. waitUntil(POST record) ───────────►│ classify
      │                                │  6. run your handler, then the app     │ + store
      │◄───────────────────────────────┤ response (unchanged by the connector)  │
      │                                │                                        │
                                                       Event appears in Explore ◄┘

Licensed under Apache-2.0. The LICENSE and NOTICE files shipped with the package are the authoritative terms.

Requirements

  • Next.js 15 and 16. Next.js is the only peer dependency (^15.0.0 || ^16.0.0), so the package installs against the Next.js version your application already pins. Tested with Next.js 15.5.23 (middleware.ts) and 16.3.2 (proxy.ts); other releases on those two lines are expected to work. Next.js 14 and earlier are not supported.
  • A Steadphast API key, created in the dashboard under Settings → API keys with Used with set to the mode you deploy: Next.js on Vercel or Next.js self-hosted. A key is issued for one deployment mode and is rejected by the other.

Install

npm install @steadphast/connector-nextjs

Or, with pnpm:

pnpm add @steadphast/connector-nextjs

The package has no runtime dependencies; install no other Steadphast package. On Next.js 14 or earlier, npm install stops with ERESOLVE and pnpm add warns about an unmet peer: upgrade Next.js rather than forcing the install.

Let a coding agent do the setup

If a coding agent (Claude Code, Codex, Cursor, or similar) has access to your application's repository, paste the prompt for your deployment mode into it. The prompt sends the agent to this README, has it install the package, write the entry file, propose the routes to exclude from capture, and run the build, and it stops before anything that needs your account: it never creates, asks for, or writes an API key, and it does not deploy. Review the routes it excluded before you deploy. In the self-hosted prompt, replace https://www.example.com and www.example.com with your public origin and host first.

Prompt: Next.js on Vercel

Integrate the Steadphast Next.js connector into this application. The site is deployed on Vercel.

The integration guide is the package README. Follow it exactly and do not invent configuration options it does not document.

Steps:
1. Before installing anything, check the Next.js version in package.json. The connector supports Next.js 15 (entry file middleware.ts) and Next.js 16 (entry file proxy.ts). If the app is on an older version, stop and tell me; do not upgrade Next.js.
2. Install @steadphast/connector-nextjs with the package manager this repo already uses, then read node_modules/@steadphast/connector-nextjs/README.md in full before changing anything. If your package manager does not create node_modules, print the README with: npm view @steadphast/connector-nextjs readme
3. Create the entry file for our Next.js version beside the app or pages directory (or under src/ if the app lives there). Default-export withDiscover with kind: "vercel", apiUrl: "https://api.steadphast.ai", excludedHeaders: ["cookie"], and a recordIdPrefix that names this deployment. Export a config with a matcher that excludes _next/static, _next/image, favicon.ico, and every route that handles form submissions, authentication, payments, or other sensitive actions in this app. List the routes you excluded and why so I can review them.
4. Run the production build and fix any errors. Do not start a dev server.
5. Do not deploy. Do not create, request, or write an API key anywhere; never put a key in a file or in a NEXT_PUBLIC_ variable. I will generate the key in Steadphast under Settings, API keys, with "Used with" set to "Next.js on Vercel", and set STEADPHAST_API_KEY in the Vercel project's environment myself.

Finish with a short handoff that tells me: the files you changed, the routes excluded from capture, the exact remaining manual steps (set the variable, redeploy), and how to verify: request the production domain with an AI crawler user agent, for example curl -A GPTBot, then check Explore in the Steadphast dashboard, which shows AI traffic by default.

Prompt: Next.js self-hosted

Integrate the Steadphast Next.js connector into this application in self-hosted mode. The site runs with next start on our own server behind nginx, and visitors reach it at https://www.example.com.

The integration guide is the package README. Follow it exactly and do not invent configuration options it does not document.

Steps:
1. Before installing anything, check the Next.js version in package.json. The connector supports Next.js 15 (entry file middleware.ts, which must also export runtime: "nodejs" in its config) and Next.js 16 (entry file proxy.ts, which takes no runtime option). If the app is on an older version, stop and tell me; do not upgrade Next.js.
2. Install @steadphast/connector-nextjs with the package manager this repo already uses, then read node_modules/@steadphast/connector-nextjs/README.md in full before changing anything. If your package manager does not create node_modules, print the README with: npm view @steadphast/connector-nextjs readme
3. Create the entry file for our Next.js version beside the app or pages directory (or under src/ if the app lives there). Default-export withDiscover with kind: "self-hosted", publicOrigin: "https://www.example.com", apiUrl: "https://api.steadphast.ai", excludedHeaders: ["cookie"], and a recordIdPrefix that names this deployment. Export a config with a matcher that excludes _next/static, _next/image, favicon.ico, and every route that handles form submissions, authentication, payments, or other sensitive actions in this app. List the routes you excluded and why so I can review them.
4. Run the production build and fix any errors. Do not start a dev server. On Next.js 15 with runtime: "nodejs", the build output shows no Middleware line and .next/server/middleware-manifest.json stays empty; that is expected. The middleware is registered in .next/server/functions-config-manifest.json instead. Keep runtime: "nodejs".
5. Copy the reference nginx configuration from the README's Next.js self-hosted section into deploy/nginx/nginx.conf and change only the values its table lists: the public host and port (www.example.com on 443, in every occurrence, keeping the [.] spelling inside the map regular expression), the certificate paths, and the proxy_pass listener (127.0.0.1:39515). Keep every other directive exactly as written; it is what sets X-Steadphast-Client-Ip from $remote_addr and X-Steadphast-Request-Id from $request_id on every proxied request and answers 421 to any other host. Do not run nginx, systemctl, certbot, or sudo, and do not connect to any server; I will apply this on the host.
6. Do not deploy. Do not create, request, or write an API key anywhere; never put a key in a file or in a NEXT_PUBLIC_ variable. I will generate the key in Steadphast under Settings, API keys, with "Used with" set to "Next.js self-hosted", and set STEADPHAST_API_KEY in the environment of the next start process myself.

Finish with a short handoff that tells me: the files you changed, the routes excluded from capture, the exact remaining manual steps on the host (install the nginx config, the key, restart), and how to verify: request the site with an AI crawler user agent, for example curl -A GPTBot, then check Explore in the Steadphast dashboard, which shows AI traffic by default.

Quick start: Next.js on Vercel

Next.js 15: middleware.ts

Place middleware.ts beside the root app or pages directory, or at src/middleware.ts when the application lives under src/. Vercel mode runs on the Edge or Node.js runtime.

import { withDiscover } from "@steadphast/connector-nextjs";

export default withDiscover({
  kind: "vercel",
  apiUrl: "https://api.steadphast.ai",
  excludedHeaders: ["cookie"],
  recordIdPrefix: "vercel-production",
});

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Next.js 16: proxy.ts

Place proxy.ts beside the root app or pages directory, or at src/proxy.ts when the application lives under src/. Proxy runs on Node.js.

import { withDiscover } from "@steadphast/connector-nextjs";

export default withDiscover({
  kind: "vercel",
  apiUrl: "https://api.steadphast.ai",
  excludedHeaders: ["cookie"],
  recordIdPrefix: "vercel-production",
});

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Set the API key

Add STEADPHAST_API_KEY to every Vercel environment where capture should be enabled. It is a server-only secret: never give it a NEXT_PUBLIC_* name. When no key is set, the connector ships nothing and the visitor response is unaffected; it logs one warning per running instance, on the first matched request that is not a skipped static asset, that begins Steadphast connector skipped event. Look for it in the deployment's runtime logs. Adding the variable takes effect on the next deployment, so redeploy after you set it.

Deploy, make a request to a matched path on your production domain (deployment-specific *.vercel.app URLs are protected by Vercel Deployment Protection by default), and open Explore in the Steadphast dashboard. The event normally appears within about 60 seconds. Explore opens on AI traffic only, so a request from your own browser is hidden until you switch the traffic filter to all traffic; a request sent with an AI crawler's user agent, such as curl -A GPTBot, appears in the default view.

Keep your own Middleware or Proxy logic

withDiscover(config, handler?) composes one application handler. The wrapper schedules capture and delivery, then calls your handler once and preserves its response, rewrite, redirect, undefined result, or thrown error:

import { NextResponse } from "next/server";
import { withDiscover } from "@steadphast/connector-nextjs";

export default withDiscover(
  { kind: "vercel", apiUrl: "https://api.steadphast.ai", excludedHeaders: ["cookie"] },
  (request) => {
    if (request.nextUrl.pathname === "/old") {
      return NextResponse.redirect(new URL("/new", request.url));
    }
  },
);

Keep the wrapper as the file's default export so Next.js calls it with both the request and the NextFetchEvent; delivery is scheduled through event.waitUntil. Do not call the wrapper from a route handler, and do not drop the event argument.

Next.js self-hosted

Self-hosted mode is for a Next.js application started with next start on a server, virtual machine, or container you operate, with nginx terminating client TLS directly in front of it. It is the same package configured with kind: "self-hosted". Use it in either entry file; for Next.js 15 middleware.ts also add runtime: "nodejs" to the exported config (Next.js 16 proxy.ts is already Node-only and does not accept the runtime option). The full setup guide is in the dashboard at https://app.steadphast.ai/docs/integrations/nextjs-self-hosted; the reference nginx configuration it uses is reproduced below.

import { withDiscover } from "@steadphast/connector-nextjs";

export default withDiscover({
  kind: "self-hosted",
  publicOrigin: "https://www.example.com",
  apiUrl: "https://api.steadphast.ai",
  excludedHeaders: ["cookie"],
  recordIdPrefix: "nextjs-self-hosted-production",
});

export const config = {
  // Next.js 15 middleware.ts only; remove this line in Next.js 16 proxy.ts.
  runtime: "nodejs",
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

publicOrigin is the public scheme, host, and port your visitors use, and it is the only source of the captured request URL's origin. It must be one HTTPS origin with no credentials, path, query, or fragment, and it must match the public authority nginx serves exactly. It is separate from apiUrl. The API key comes from the STEADPHAST_API_KEY environment variable of the next start process, issued with Used with set to Next.js self-hosted.

The nginx trust boundary

In this mode the connector trusts exactly two request headers, X-Steadphast-Client-Ip and X-Steadphast-Request-Id, and only because nginx overwrites both on every proxied request from facts nginx itself established. The connector never falls back to X-Forwarded-For, X-Real-IP, the public x-request-id, any x-vercel-* header, or the socket address. A Next.js listener that is reachable without nginx, or a proxy that passes client headers through, lets any client forge the IP recorded for its requests.

The supported topology is exactly one nginx directly in front of the application, and the supported configuration is the reference nginx configuration below. Start from that file and change only the values it lists (public host and port, certificate paths, and the loopback proxy_pass address). It:

  • terminates client TLS directly on TLS 1.2 or 1.3 and refuses a handshake without the configured server name;
  • accepts exactly one public host and port and answers 421 to every other Host or absolute-form request target;
  • overwrites Host, X-Forwarded-Host, and X-Forwarded-Proto from validated routing and transport facts;
  • overwrites X-Steadphast-Client-Ip with the direct TCP peer ($remote_addr) and X-Steadphast-Request-Id with nginx's own $request_id, replacing every client-supplied copy;
  • appends its peer to X-Forwarded-For, which the connector keeps only as untrusted evidence.

Bind the application to loopback (for example next start -H 127.0.0.1 -p 3000) and confirm from outside the host that the Next.js port is not reachable. A CDN, load balancer, or second proxy in front of nginx, a public direct Next.js port, and pass-through internal headers are unsupported: the connector cannot detect them, and a CDN in front makes the recorded client IP that CDN's address. No TLS fingerprint is available in this mode.

Reference nginx configuration

This is the complete nginx.conf Steadphast tests with, reproduced exactly. It replaces the distribution's nginx.conf and everything it includes from conf.d or sites-enabled rather than being added beside them. Install it as nginx.conf in a directory of its own (for example /etc/steadphast/nginx/) so its relative paths resolve there, check it with nginx -t -p /etc/steadphast/nginx/ -c nginx.conf, and start nginx as root with nginx -e stderr -p /etc/steadphast/nginx/ -c nginx.conf -g "daemon off;". It needs nginx 1.25.1 or later.

# Steadphast Next.js connector: reference nginx configuration for self-hosted mode.
#
# nginx is the only process that terminates client TLS. It accepts exactly one public host,
# sets the two internal connector headers from facts it established itself, and proxies to a
# Next.js `next start` listener bound to loopback. The public scheme, host, and port served
# here must equal the connector's `publicOrigin` exactly. The placeholder host and port used
# below are replaced with your own; see the values table in the setup guide.
#
# This is a complete nginx.conf. Install it as `nginx.conf` inside an explicit prefix so the
# relative TLS and temp paths resolve there, then run
# `nginx -e stderr -p <prefix>/ -c nginx.conf -g "daemon off;"`.
#
# Trust boundary (do not weaken):
#   * x-steadphast-client-ip   <- $remote_addr, the direct TCP peer. Nothing may sit in front
#     of nginx: no CDN and no load balancer.
#   * x-steadphast-request-id  <- $request_id, the request identifier nginx generates itself.
#   * Host / X-Forwarded-Host / X-Forwarded-Proto <- the routing and transport facts nginx checked.
#   * X-Forwarded-For          <- the client's value plus $remote_addr, kept only as untrusted
#     evidence.
#   * Anything else the client sends (X-Real-IP, x-vercel-*, a public x-request-id, ...) is
#     passed through as ordinary request data; the connector never uses it as the client IP or
#     request ID in self-hosted mode.

worker_processes 1;
pid nginx.pid;
error_log stderr warn;

events {
    worker_connections 1024;
}

http {
    access_log off;
    server_tokens off;
    client_body_temp_path client_body_temp;
    proxy_temp_path proxy_temp;
    fastcgi_temp_path fastcgi_temp;
    uwsgi_temp_path uwsgi_temp;
    scgi_temp_path scgi_temp;

    # `$request` retains the raw HTTP/1 request-target. Accept origin-form only with exactly one
    # leading slash; an absolute-form target must spell this listener's complete HTTPS authority.
    map $request $steadphast_request_target_ok {
        default 0;
        "~^[^ ]+ /(?:[^/ ][^ ]*)? HTTP/[0-9.]+$" 1;
        "~^[^ ]+ https://connector[.]steadphast[.]test:39516(?:/[^ ]*|[?][^ ]*)? HTTP/[0-9.]+$" 1;
    }

    # Handshake policy belongs to the shared/default context: nginx selects a virtual server only
    # after the ClientHello, so the default and named handshakes must inherit the same minimum.
    ssl_protocols TLSv1.2 TLSv1.3;

    # Catch-all: a handshake without the configured SNI is refused outright.
    server {
        listen 39516 ssl default_server;
        server_name _;
        ssl_reject_handshake on;
        return 421;
    }

    server {
        listen 39516 ssl;
        http2 on;
        server_name connector.steadphast.test;

        ssl_certificate steadphast/tls.crt;
        ssl_certificate_key steadphast/tls.key;
        ssl_prefer_server_ciphers off;

        # Require the raw request-target and complete wire authority, then independently check
        # nginx's normalized host. `$host` drops an absolute-form target's port.
        if ($steadphast_request_target_ok = 0) {
            return 421;
        }
        if ($http_host != "connector.steadphast.test:39516") {
            return 421;
        }
        if ($host != "connector.steadphast.test") {
            return 421;
        }

        location / {
            # The private Next.js listener: `next start -H 127.0.0.1 -p 39515`.
            proxy_pass http://127.0.0.1:39515;
            proxy_http_version 1.1;
            proxy_set_header Connection "";

            # Validated external facts replace whatever the client sent.
            proxy_set_header Host "connector.steadphast.test:39516";
            proxy_set_header X-Forwarded-Host "connector.steadphast.test:39516";
            proxy_set_header X-Forwarded-Proto "https";

            # Internal connector headers: always overwritten, never preserved. `proxy_set_header`
            # replaces every client-supplied occurrence, so duplicates cannot leak through.
            proxy_set_header X-Steadphast-Client-Ip $remote_addr;
            proxy_set_header X-Steadphast-Request-Id $request_id;

            # Untrusted evidence only: the client chain with our direct peer appended.
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

The reference is written for a placeholder public host and port and a Next.js listener on loopback. Adapt it by changing only these values and keep every directive. In the map block the host is a regular expression, so each dot is written [.] to match a literal dot; keep that spelling when you substitute your own host, for example www[.]example[.]com:

| Reference value | Replace with | |---|---| | connector.steadphast.test:39516 (the absolute-form request-target map, the $http_host check, and both the proxy_set_header Host and X-Forwarded-Host lines) | Your public authority, identical in every occurrence and identical to publicOrigin. On the default port 443 clients send a bare Host, so use www.example.com with no port in all of these and set publicOrigin to https://www.example.com; on any other port keep the host:port form in all of them and in publicOrigin | | connector.steadphast.test (server_name and the $host check) | Your public host | | listen 39516 ssl in both server blocks | Your public port | | ssl_certificate and ssl_certificate_key | Your certificate and key paths | | proxy_pass http://127.0.0.1:39515 | The loopback address and port of your next start process |

Configuration reference

type DiscoverNextConfig = (
  | { kind: "vercel" }
  | { kind: "self-hosted"; publicOrigin: string }
) & {
  apiUrl: string;
  apiKeyEnvVar?: string;
  captureAllPaths?: boolean;
  excludedHeaders?: ReadonlyArray<string>;
  recordIdPrefix?: string;
  timeoutMs?: number;
};

| Option | Required | Description | |---|---|---| | kind | Yes | "vercel" or "self-hosted". The mode is never inferred from headers, environment variables, host names, or runtime globals. | | publicOrigin | Self-hosted only | The public HTTPS origin nginx serves. See Next.js self-hosted. | | apiUrl | Yes | The Steadphast API origin, https://api.steadphast.ai. See Destination rules. | | apiKeyEnvVar | No | Name of the server-only environment variable holding the API key. Defaults to STEADPHAST_API_KEY (DISCOVER_API_KEY is still read as a deprecated fallback; migrate to STEADPHAST_API_KEY). When set, only the named variable is read. A NEXT_PUBLIC_* name is rejected. | | captureAllPaths | No | Static assets (scripts, styles, images, fonts, and similar) are skipped by default, except robots.txt and sitemap.xml. Set true to capture every path the matcher allows. | | excludedHeaders | No | Header names (case-insensitive) to remove from the captured header map. Cookies are captured unless you exclude them. | | recordIdPrefix | No | A short label that prefixes the record IDs Steadphast assigns, useful for telling deployments apart. Defaults to vercel-routing-middleware or nextjs-self-hosted. Limit: 128 UTF-8 bytes. A longer value is not rejected at startup but makes every capture drop silently. | | timeoutMs | No | Delivery timeout in milliseconds. Defaults to 5000. |

kind, publicOrigin, apiUrl, and the NEXT_PUBLIC_* rule for apiKeyEnvVar are validated when the entry file is evaluated: an invalid value throws a DiscoverConfigError, so those misconfigurations fail at startup rather than silently shipping nothing. The other options are not checked at startup.

Route exclusion runs before any header is inspected. The Next.js matcher decides whether the connector runs at all: exclude routes there when none of their path, query, or header metadata should be captured (form submissions, authentication callbacks, and similar action endpoints are common candidates).

Destination rules

apiUrl accepts only:

  • an absolute HTTPS origin whose pathname is exactly / (https://api.steadphast.ai), which resolves to the connector endpoint /v1/connectors/nextjs/events; or
  • that exact endpoint URL, https://api.steadphast.ai/v1/connectors/nextjs/events.

It must have a non-empty host and no credentials, query, or fragment. Plain HTTP, any other path, and redirects are rejected, so your API key is never sent over plaintext or to a redirected host.

What is captured

Each captured request produces one strict JSON record containing the deployment mode, capture timestamp, your recordIdPrefix, request metadata, and platform metadata:

  • Request: method, URL, and headers. The connector reads nothing else. It never reads, clones, buffers, or transmits the request body, so every downstream body consumer in your application remains callable.
  • Platform (Vercel): Vercel's protected client IP, request ID (x-vercel-id), and the JA4 and JA3 TLS-fingerprint digests when Vercel supplies them.
  • Platform (self-hosted): the client IP and request ID nginx sets in X-Steadphast-Client-Ip and X-Steadphast-Request-Id. Those two headers are never copied into the captured header map.
  • Signature evidence: signature and signature-input headers are copied verbatim so Steadphast can verify RFC 9421 Web Bot Auth signatures server-side.

Ordinary x-forwarded-for travels as untrusted evidence only; the connector never parses it into a client identity.

Privacy exclusions

Headers pass through two filters before anything is serialized:

 incoming headers
       │
       ▼
 built-in exclusions ── a fixed list of recognized credential header names
       │                and a few name patterns (see below)
       ▼
 your excludedHeaders ── e.g. cookie, and every application-specific credential header
       │
       ▼
 captured header map  (everything else, cookies included unless excluded)

The built-in filter is a limited, fixed set, not a general secret detector. Names are compared case-insensitively with separators removed (x-api-key, X_Api_Key, and xapikey are the same name). The exact set is:

  • authorization, x-authorization, and proxy-authorization (but not x-proxy-authorization);
  • api-key, api-token, auth-key, access-key, secret-key, auth-token, access-token, bearer-token, refresh-token, id-token, session-token, and csrf-token, each with or without an x- prefix;
  • the bare names token and key (but not x-token or x-key);
  • any name ending in apikey, authtoken, or accesstoken, and any name containing cryptogram or networktoken;
  • agentic-payment-container and Vercel's x-vercel-protection-bypass.

Every other header is captured, including custom credential headers such as x-token, x-github-token, x-openai-key, x-internal-secret, or x-<vendor>-signature. Audit the headers your application, its upstream proxies, and its third-party integrations attach, and list every credential-bearing name in excludedHeaders.

Other headers, including cookies, are captured by default, so exclude them explicitly wherever that is not acceptable. Excluding a header removes it from the generic header map only; it does not remove a value that a dedicated field separately carries (for example the user agent). Query strings can contain sensitive values, so avoid placing secrets or personal data in public URLs.

Size limits

Every per-field, per-header, header-count, and whole-record limit is enforced before anything is sent. A value that cannot be represented exactly is either omitted, when omission preserves meaning, or the whole observation is dropped. Nothing is ever truncated and presented as observed data.

Delivery behavior

Each captured request schedules exactly one POST to Steadphast through waitUntil, with a bounded timeout. There is no batching, no retry, and no client-side queue. A delivery that fails, times out, or is rejected drops that single event, and nothing about the request, response, or credential is logged.

Delivery does not block the visitor response: the connector serializes the record, schedules the POST through waitUntil, and then calls your handler. A drop, timeout, or rejection never changes the response status, headers, or body, and never propagates an error into your composed handler.

Troubleshooting

  • No events appear: switch the Explore traffic filter to all traffic first, because the default view shows AI traffic only. Then confirm the API key was issued for the mode you set in kind (Next.js on Vercel or Next.js self-hosted), that STEADPHAST_API_KEY is set in the deployed environment and the process or deployment was restarted after you set it, that the entry file default-exports the wrapper, that recordIdPrefix is within its 128-byte limit, and that the matcher or static-asset filter did not skip the path. A Steadphast connector skipped event line in the runtime logs means no key reached the process.
  • The deployment fails at startup: apiUrl is not HTTPS or its path is neither / nor /v1/connectors/nextjs/events, publicOrigin is not a bare HTTPS origin, or apiKeyEnvVar names a NEXT_PUBLIC_* variable. The thrown DiscoverConfigError names the setting.
  • Nothing ships from a local next dev or next start: in Vercel mode only HTTPS request URLs are captured, so a plain http://localhost server never ships. Front the server with an HTTPS proxy or send X-Forwarded-Proto: https, which Next.js honors when building the request URL.
  • Self-hosted events have no client IP: nginx is not overwriting X-Steadphast-Client-Ip, or the request bypassed nginx. Compare your configuration with the reference nginx configuration and confirm the Next.js port is not reachable from outside.
  • Self-hosted requests answer 421: nginx received a Host or absolute-form request target that does not match its configured public authority. Make the server_name, the Host checks, the proxy_set_header Host lines, and publicOrigin agree with each other.
  • Self-hosted URLs show the wrong host: publicOrigin does not match the public scheme, host, and port nginx serves; it is never derived from request headers.
  • Cookies still appear: confirm excludedHeaders: ["cookie"] is present in the deployed entry file.
  • Your site response fails: inspect your own handler and application route. Steadphast delivery failures are swallowed and never change the response.

Upgrading

  • 0.5.4 Documentation only: this README now carries the reference nginx configuration and the coding-agent setup prompts; no runtime change.
  • 0.5.3 Documentation and metadata only; no runtime change.
  • 0.5.2 changes documentation and package metadata only; the shipped code is identical to 0.5.1, and no upgrade action is needed.
  • 0.5.1 is the first published version of this package.

License

Apache-2.0. See the LICENSE and NOTICE files shipped with the package.