What it sends, and what it never does
Uncaught errors, unhandled rejections and failed requests. Never form values or request bodies.
The script tag reports half of page loads; the package reports every one by default. 60 events per minute per app. About 1.5 KB gzipped. Messages are shortened in the page and redacted on arrival, before anything is stored. It cannot throw into your app or block it.
Your keys are under Integrations › Error capture in your workspace: a public key for the browser, matched to an application by the page’s hostname, and one key per application for a server, which has no page to match on.
The package
Prefer the dependency where you can: pasted code never gets the fix, and an agency with thirty applications would be maintaining thirty copies.
pnpm add keelnest npm install keelnest yarn add keelnest bun add keelnest
Next.js
export { register, onRequestError } from "keelnest/next";import { init } from "keelnest";
init({
key: process.env.NEXT_PUBLIC_KEELNEST_KEY,
host: process.env.NEXT_PUBLIC_KEELNEST_HOST,
});Vite, Astro or Node
import { init } from "keelnest";
init({ key: KEELNEST_KEY, host: KEELNEST_HOST });Cloudflare Workers
import { wrap } from "keelnest";
export default {
fetch: wrap(async (request, env) => {
/* … */
}),
};The keys
# The browser half: public by design, matched to an app by the page's hostname. NEXT_PUBLIC_KEELNEST_KEY=pk_live_… NEXT_PUBLIC_KEELNEST_HOST=https://keelnest.com # The server half: this key names one application. Get it under Server. KEELNEST_KEY=pk_live_… KEELNEST_HOST=https://keelnest.com
The script tag
For an application you cannot add a dependency to — a site a client edits by hand, a builder that owns package.json, a page inside a CMS. Paste it in the <head> of the site; events are attributed to the application whose production URL matches the page.
<script async src="https://keelnest.com/e.js" data-key="pk_live_…" data-sample="0.5"></script>
A server without the package
A process has no page, so it sends its application’s own key. Import once at startup — in Next.js, instrumentation.ts.
// Keelnest server error capture. Import once at startup
// (Next.js: instrumentation.ts — otherwise your server entry file).
const KEY = process.env.KEELNEST_KEY;
const URL = "https://keelnest.com/api/ingest/errors";
export async function reportError(error, kind = "error") {
if (!KEY) return;
try {
await fetch(URL, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
key: KEY,
events: [{
runtime: "server",
kind,
message: String(error?.message ?? error),
stack: String(error?.stack ?? ""),
at: new Date().toISOString(),
}],
}),
});
} catch {
// Reporting an error must never become one.
}
}
process.on("uncaughtException", (e) => reportError(e, "uncaught"));
process.on("unhandledRejection", (e) => reportError(e, "unhandled"));Prompts for a builder
If Lovable, Bolt, Cursor or Claude Code builds the app, hand it one of these instead of the steps above.
Add Keelnest error capture to my app as a dependency: install keelnest and wire it up. If this is a Next.js app, re-export register and onRequestError from "keelnest/next" in instrumentation.ts, and call init({ key: process.env.NEXT_PUBLIC_KEELNEST_KEY, host: process.env.NEXT_PUBLIC_KEELNEST_HOST }) in instrumentation-client.ts. Otherwise call init({ key, host }) once at the top of the entry file, and on Cloudflare Workers wrap the fetch handler with wrap() from the same package. Set NEXT_PUBLIC_KEELNEST_KEY=pk_live_… and NEXT_PUBLIC_KEELNEST_HOST=https://keelnest.com in the environment; leave the server-side KEELNEST_KEY for me to fill in. Do not change anything else, and do not add any other monitoring.Add the Keelnest error capture snippet to my app. Put this script tag in the <head> of the root HTML (or the root layout): <script async src="https://keelnest.com/e.js" data-key="pk_live_…" data-sample="0.5"></script>. Do not change anything else. It must not capture form values or request bodies.
Uninstalling
Remove the dependency, or the script tag, from the application. Events stop with the next page load or the next deploy; the app’s history stays. The package itself is keelnest, MIT-licensed, with no dependencies of its own. All docs.