@trybluemoon/aen npm package (two lines) or a
single self-contained middleware.ts file you paste in. Either way it runs on Vercel Edge. This
page covers both install paths, the settings you can change, and troubleshooting.
This is an edge middleware you install in your own app, not a reverse proxy in front of your
site. On Cloudflare, use the Cloudflare Worker instead.
Prerequisites
- A Next.js project deployed on Vercel (or running locally with
next dev) - An edge token (format
aen_...) from Agent Analytics in the Bluemoon app: choose Next.js / Vercel and click Connect edge, or open Setup if the site is already connected. It works for one site and can be replaced.
Install
- npm package (recommended)
- Copy-paste (no dependency)
1
Install the package
init creates middleware.ts (or proxy.ts on Next.js 16+) wired to the package — a
two-line file. The real logic lives in the package, so you get updates without re-pasting code.2
Add your edge token
In Vercel → your project → Settings → Environment Variables, add
AEN_EDGE_TOKEN with
the edge token from Agent Analytics → Setup. For local dev, add it to .env.local.3
Deploy, then go live
Deploy. It starts in shadow mode (logs only, serves your normal page). Watch for the
first verified hit in Agent Analytics, then set
AEN_SERVE_MODE=default in your env and
redeploy to start serving. See Serve modes.Existing middleware
Already running a middleware — next-intl, auth, redirects? Don’t replace it. The package exports a composablehandle() that returns a Response when it served a verified AI crawler,
or null to fall through to your own code. Add two lines at the top of your middleware:
middleware.ts (next-intl example)
handle() reports crawler hits in every mode and returns null in shadow mode, so your site behaves
exactly as before until you set AEN_SERVE_MODE=default. Running npx @trybluemoon/aen init in a
project that already has a middleware prints this recipe automatically instead of overwriting your file.
The complete middleware.ts
Paste this entire file at the root of your Next.js project, then set AEN_EDGE_TOKEN as an
environment variable (see the step above). This is the drop-in — zero dependencies
beyond next/server, running on Vercel Edge.
middleware.ts
Configuration constants
All configuration lives at the top ofmiddleware.ts. You do not need to touch anything else
in the file.
middleware.ts (configuration section)
This file supports
shadow and default only. See Serve modes for what
each mode does.The config matcher
/_next/— Next.js build assets and hot-reload/api/— your API routes/favicon.ico— the favicon
What the middleware does
On every page request, the middleware:- Does nothing if
AEN_EDGE_TOKENis empty — your site behaves as if the file weren’t there. - Passes through anything that isn’t a known AI crawler.
- Never touches search bots — Googlebot, Bingbot and Applebot always get your real page (the cloaking firewall).
- Serves verified answer-engine crawlers the optimized version of the
page when the serve mode is
default(AEN_SERVE_MODEfor the npm package,SERVE_MODEin the copy-paste file), the crawler’s purpose is enabled, and Bluemoon has an optimized version of that URL. In every other case the crawler gets your normal page. - Reports every crawler hit to Agent Analytics without delaying the response.
Content-Type: text/markdown and the header x-aen-served: variant, so you
can tell it apart from your normal page.
In
shadow mode every hit is recorded as Passthrough, even for crawlers that would be served.
This lets you see how many crawlers would get the optimized version before you switch to
"default".Verified and unverified crawlers
Agent Analytics shows whether each hit was verified:
See Detection & verification for more.
Troubleshooting
No hits appear in Agent Analytics
No hits appear in Agent Analytics
- Confirm the
middleware.tsfile is at the project root, not insidesrc/orapp/. - Confirm
AEN_EDGE_TOKENis set in your Vercel environment and you have redeployed after adding it. - Make sure you triggered a real AI crawler (ChatGPT or Perplexity with browsing), not your
own browser. Unverified (
UA_ONLY) requests are not shown as verified hits.
Middleware is running but the optimized version is never served
Middleware is running but the optimized version is never served
Check that the serve mode is
default, not shadow (AEN_SERVE_MODE=default for the npm
package, SERVE_MODE = "default" in the copy-paste file), and that you redeployed after the
change. Also confirm Bluemoon has an optimized version of the URL you are testing — you can
check this in Agent Analytics.Hits show Passthrough even in default mode
Hits show Passthrough even in default mode
This means the request was not Verified (
IP_VERIFIED), the crawler’s purpose is not in ENABLED, or
there is no optimized version of that URL yet. Verified USER_TRIGGERED / RETRIEVAL crawlers
get the optimized version when one exists. The copy-paste file only verifies crawlers that
connect over IPv4; a crawler that reaches you over IPv6 is recorded as Unverified (UA_ONLY).Can I use this outside Vercel?
Can I use this outside Vercel?
The file uses the
NextRequest / NextResponse API and the Web Crypto API (crypto.subtle).
Vercel Edge is the supported target for this file. For Cloudflare, use the
Cloudflare Worker; for other stacks, see
Custom integration.