everfound-tracker 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +63 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# everfound-tracker
|
|
2
|
+
|
|
3
|
+
See which AI agents actually read your site — GPTBot, ClaudeBot, Perplexity, and friends — plus the human visitors AI assistants send you. Reports to your [Everfound](https://everfound.ai) dashboard.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install everfound-tracker
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Use (Vercel, any framework)
|
|
12
|
+
|
|
13
|
+
Create `middleware.ts` in your project root:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { everfound } from "everfound-tracker";
|
|
17
|
+
|
|
18
|
+
export default everfound({ key: "your-site-key" });
|
|
19
|
+
export const config = { matcher: "/((?!_next/|.*\\.(?:js|css|png|jpg|svg|ico|woff2?)$).*)" };
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Your site key is in the Everfound dashboard under **AI agents on your site → Install the tracker**. It's safe to commit — it only authorizes reporting traffic for your own site.
|
|
23
|
+
|
|
24
|
+
Already have a `middleware.ts`? Call the tracker from it instead:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { everfound } from "everfound-tracker";
|
|
28
|
+
|
|
29
|
+
const track = everfound({ key: "your-site-key" });
|
|
30
|
+
|
|
31
|
+
export default function middleware(request: Request, context: { waitUntil(p: Promise<unknown>): void }) {
|
|
32
|
+
track(request, context);
|
|
33
|
+
// ...your existing middleware logic
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## How it works
|
|
38
|
+
|
|
39
|
+
- Fires only on AI/bot user agents and on human visits referred from AI surfaces (ChatGPT, Perplexity, Gemini, Copilot, …) — ordinary traffic never leaves your infrastructure.
|
|
40
|
+
- Fire-and-forget: never blocks, never throws, never breaks a request.
|
|
41
|
+
- The Everfound server does the authoritative classification and crawler-IP verification. New AI agents are added server-side — you don't need to update this package to track them.
|
|
42
|
+
- The client IP is forwarded on bot hits only (to verify crawlers against their operators' published IP ranges) and never on human referral clicks.
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT © Digital Bar LLC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type EverfoundOptions = {
|
|
2
|
+
/** Per-site key from your Everfound dashboard. Safe to commit — it only authorizes reporting traffic for your own site. */
|
|
3
|
+
key: string;
|
|
4
|
+
/** Override the tracked host. Defaults to the request's hostname (www-stripped). */
|
|
5
|
+
host?: string;
|
|
6
|
+
/** Override the ingest endpoint. Defaults to the Everfound API. */
|
|
7
|
+
endpoint?: string;
|
|
8
|
+
};
|
|
9
|
+
type EdgeContext = {
|
|
10
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Create the Everfound tracking middleware.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* // middleware.ts
|
|
17
|
+
* import { everfound } from "everfound-tracker";
|
|
18
|
+
*
|
|
19
|
+
* export default everfound({ key: "your-site-key" });
|
|
20
|
+
* export const config = { matcher: "/((?!_next/|.*\\.(?:js|css|png|jpg|svg|ico|woff2?)$).*)" };
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Fire-and-forget by design: it never blocks or breaks a request, and it
|
|
24
|
+
* forwards the client IP on bot hits only (crawler verification) — never on
|
|
25
|
+
* human referral clicks.
|
|
26
|
+
*/
|
|
27
|
+
export declare function everfound(options: EverfoundOptions): (request: Request, context?: EdgeContext) => void;
|
|
28
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// everfound-tracker — drop-in middleware that reports AI crawler traffic and
|
|
2
|
+
// AI referral clicks to your Everfound dashboard.
|
|
3
|
+
//
|
|
4
|
+
// The middleware is a thin forwarder: it pre-filters with broad, stable shape
|
|
5
|
+
// patterns (bot-ish user agents, AI chat referrers) purely to avoid sending
|
|
6
|
+
// ordinary human traffic, and the Everfound server does the authoritative
|
|
7
|
+
// per-agent classification, crawler-IP verification, and quarantine of agents
|
|
8
|
+
// it doesn't recognize yet. New AI agents are picked up by the server-side
|
|
9
|
+
// catalog — sites do not need to update this package when the catalog grows.
|
|
10
|
+
// Broad shapes, not an agent catalog: generic crawler tokens, AI vendor names,
|
|
11
|
+
// and vendor prefixes. Deliberately over-inclusive — the server classifies and
|
|
12
|
+
// quarantines; this only keeps ordinary human page views off the wire.
|
|
13
|
+
const BOTISH = /bot\b|crawler|spider|scrape|fetch|agent\b|gpt|claude|gemini|mistral|llm|anthropic|perplexity|openai|google-|googleother|openclaw|moltbot|cohere|omgili|bytespider|petalbot|youbot|timpibot/i;
|
|
14
|
+
// AI chat surfaces that send human visitors (referer header or utm_source).
|
|
15
|
+
const AI_REFS = /chatgpt|chat\.openai\.com|perplexity|claude\.ai|gemini\.google|bard\.google|copilot\.microsoft|\bmeta\.ai|grok\.com|chat\.mistral\.ai|\byou\.com/i;
|
|
16
|
+
// Static assets are never interesting — skipped even without a matcher.
|
|
17
|
+
const ASSET = /\.(?:js|mjs|css|map|png|jpe?g|gif|svg|ico|webp|avif|woff2?|ttf|otf|mp4|webm|pdf)$/i;
|
|
18
|
+
/**
|
|
19
|
+
* Create the Everfound tracking middleware.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* // middleware.ts
|
|
23
|
+
* import { everfound } from "everfound-tracker";
|
|
24
|
+
*
|
|
25
|
+
* export default everfound({ key: "your-site-key" });
|
|
26
|
+
* export const config = { matcher: "/((?!_next/|.*\\.(?:js|css|png|jpg|svg|ico|woff2?)$).*)" };
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Fire-and-forget by design: it never blocks or breaks a request, and it
|
|
30
|
+
* forwards the client IP on bot hits only (crawler verification) — never on
|
|
31
|
+
* human referral clicks.
|
|
32
|
+
*/
|
|
33
|
+
export function everfound(options) {
|
|
34
|
+
const endpoint = options.endpoint ?? "https://everfound.ai/api/track";
|
|
35
|
+
return function middleware(request, context) {
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(request.url);
|
|
38
|
+
if (url.pathname.startsWith("/_next/") || ASSET.test(url.pathname)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const ua = request.headers.get("user-agent") ?? "";
|
|
42
|
+
const ref = request.headers.get("referer") ?? "";
|
|
43
|
+
const utm = url.searchParams.get("utm_source") ?? "";
|
|
44
|
+
const isBot = BOTISH.test(ua);
|
|
45
|
+
if (!isBot && !AI_REFS.test(`${ref} ${utm}`)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const ip = isBot ? (request.headers.get("x-forwarded-for") ?? "").split(",")[0].trim() : "";
|
|
49
|
+
const host = options.host ?? url.hostname.replace(/^www\./, "");
|
|
50
|
+
const send = fetch(endpoint, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "content-type": "application/json" },
|
|
53
|
+
body: JSON.stringify({ host, key: options.key, path: url.pathname, ua, ref, utm, ip }),
|
|
54
|
+
}).then(() => undefined, () => undefined);
|
|
55
|
+
if (context && typeof context.waitUntil === "function") {
|
|
56
|
+
context.waitUntil(send);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Tracking must never break the site.
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "everfound-tracker",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "See which AI agents read your site — drop-in middleware that reports AI crawler traffic and AI referral clicks to your Everfound dashboard.",
|
|
5
|
+
"keywords": ["ai", "analytics", "crawler", "gptbot", "claudebot", "middleware", "vercel", "everfound"],
|
|
6
|
+
"homepage": "https://everfound.ai",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": ["dist", "README.md"],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.7.0"
|
|
25
|
+
}
|
|
26
|
+
}
|