tracwell 0.2.0 → 0.3.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 +49 -5
- package/dist/npm/server.d.ts +18 -0
- package/dist/npm/server.js +1 -0
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -13,12 +13,33 @@ The production browser artifact is served from the existing Collector domain:
|
|
|
13
13
|
src="https://collect.tracwell.app/script.js"
|
|
14
14
|
data-project-key="tw_live_..."
|
|
15
15
|
data-collection-mode="private"
|
|
16
|
-
data-consent="granted"
|
|
17
|
-
data-respect-do-not-track="true"
|
|
18
16
|
></script>
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
### Optional script attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Values | Default |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| `data-project-key` | Your public project key (never a server key) | Required |
|
|
24
|
+
| `data-collection-mode` | `private`, `product` | `private` |
|
|
25
|
+
| `data-consent` | `granted`, `required`, `denied` | `granted` |
|
|
26
|
+
| `data-respect-do-not-track` | `true`, `false` | `true` |
|
|
27
|
+
|
|
28
|
+
Keep collection mode explicit and aligned with website settings. The generated
|
|
29
|
+
snippet omits default consent and Do Not Track attributes. Add
|
|
30
|
+
`data-consent="required"` to wait for consent before identity creation or event
|
|
31
|
+
collection. After the script loads, forward the visitor's saved choice and
|
|
32
|
+
subsequent changes using `window.tracwell?.setConsent("granted")` or
|
|
33
|
+
`window.tracwell?.setConsent("denied")`. An early call before the script loads
|
|
34
|
+
has no effect; initialize the consent integration after SDK load.
|
|
35
|
+
|
|
36
|
+
Only these four data attributes are supported. Use the npm SDK for other
|
|
37
|
+
initialization options, including batching, persistence overrides, and a custom
|
|
38
|
+
collector URL. The script reads attributes at load time and does not fetch
|
|
39
|
+
configuration from the dashboard; update the installed snippet when changing
|
|
40
|
+
website settings.
|
|
41
|
+
|
|
42
|
+
When consent and Do Not Track permit collection, loading the script captures the initial page view and exposes the same client
|
|
22
43
|
as `window.tracwell` for custom events:
|
|
23
44
|
|
|
24
45
|
```js
|
|
@@ -85,8 +106,9 @@ batching, retries, consent, and delivery remain in this core package.
|
|
|
85
106
|
- Retry bounded transient failures without changing event IDs.
|
|
86
107
|
- Respect configured consent and Do Not Track behavior before collection.
|
|
87
108
|
|
|
88
|
-
The SDK must remain browser-only, small, non-blocking, and unable
|
|
89
|
-
collector fields. It must not contain secrets or connect to
|
|
109
|
+
The default SDK entry must remain browser-only, small, non-blocking, and unable
|
|
110
|
+
to set trusted collector fields. It must not contain secrets or connect to
|
|
111
|
+
ClickHouse. The separate server entry accepts a server-side key as documented below.
|
|
90
112
|
|
|
91
113
|
## Identity and attribution
|
|
92
114
|
|
|
@@ -213,3 +235,25 @@ pnpm --filter {packages/sdk} test
|
|
|
213
235
|
pnpm --filter {packages/sdk} build:cdn
|
|
214
236
|
pnpm --filter {packages/sdk} check:package
|
|
215
237
|
```
|
|
238
|
+
|
|
239
|
+
## Server-only AI crawler entry
|
|
240
|
+
|
|
241
|
+
`tracwell/server` exports `trackAiCrawler(request, { serverKey, statusCode?,
|
|
242
|
+
collectorUrl? })`. Import only on your backend; never expose `tw_sk_`
|
|
243
|
+
keys in browser code. This separate bundle adds nothing to the default browser
|
|
244
|
+
entry or CDN script. Available starting with npm package version 0.3.0. The unchanged browser
|
|
245
|
+
transport continues reporting browser SDK version 0.2.0.
|
|
246
|
+
|
|
247
|
+
Call from Next.js proxy/middleware or another server/edge handler. Pass the
|
|
248
|
+
promise to the hosting runtime's `waitUntil` (and inspect its result), or await
|
|
249
|
+
on a persistent server. Keep existing request handling intact. The helper ignores
|
|
250
|
+
ordinary traffic, API paths and common static assets. Robots, sitemap and Markdown
|
|
251
|
+
requests remain trackable. Handler/cache placement determines coverage.
|
|
252
|
+
|
|
253
|
+
Results are `ignored`, `accepted` (matching Queue receipt), or `failed` with a
|
|
254
|
+
non-sensitive error code. Three total attempts use the same event ID, timestamp
|
|
255
|
+
and sanitized URL. Retries are in memory only. Do not treat acceptance as confirmed
|
|
256
|
+
database persistence. Queries/fragments are stripped; no IP, cookies or other
|
|
257
|
+
request headers are sent. Raw UA is sent solely for collector classification and
|
|
258
|
+
is not stored. Current provider matches are user-agent based, not IP verified.
|
|
259
|
+
See the public `/docs/ai-crawlers` guide for setup and direct POST integration.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface CrawlerTrackingOptions {
|
|
2
|
+
/** Secret tw_sk_ key. Never include in browser code. */
|
|
3
|
+
serverKey: string;
|
|
4
|
+
collectorUrl?: string;
|
|
5
|
+
statusCode?: number;
|
|
6
|
+
}
|
|
7
|
+
export type CrawlerTrackingResult = {
|
|
8
|
+
status: "ignored";
|
|
9
|
+
} | {
|
|
10
|
+
status: "accepted";
|
|
11
|
+
eventId: string;
|
|
12
|
+
} | {
|
|
13
|
+
status: "failed";
|
|
14
|
+
eventId: string;
|
|
15
|
+
code: "CONFIGURATION" | "DELIVERY_REJECTED" | "DELIVERY_UNAVAILABLE";
|
|
16
|
+
};
|
|
17
|
+
/** Await on a persistent server, or pass the promise to the runtime's waitUntil. */
|
|
18
|
+
export declare function trackAiCrawler(request: Request, options: CrawlerTrackingOptions): Promise<CrawlerTrackingResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=[{token:"ChatGPT-User",provider:"OpenAI",category:"answers"},{token:"OAI-SearchBot",provider:"OpenAI",category:"indexing"},{token:"GPTBot",provider:"OpenAI",category:"training"},{token:"Claude-User",provider:"Anthropic",category:"answers"},{token:"Claude-SearchBot",provider:"Anthropic",category:"indexing"},{token:"ClaudeBot",provider:"Anthropic",category:"training"},{token:"Perplexity-User",provider:"Perplexity",category:"answers"},{token:"PerplexityBot",provider:"Perplexity",category:"indexing"}];function p(n){return l.find(r=>new RegExp(`(?:^|[\\s;(])${r.token}(?:/|[\\s;)]|$)`,"i").test(n))}async function h(n,r){let c=n.headers.get("user-agent")??"";if(!["GET","HEAD"].includes(n.method)||!p(c))return{status:"ignored"};let o=new URL(n.url);if(/\.(?:js|css|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|mp4|map)$/i.test(o.pathname)||/^\/(?:api|_next)(?:\/|$)/.test(o.pathname))return{status:"ignored"};let a=crypto.randomUUID(),e;try{if(e=new URL(r.collectorUrl??"https://collect.tracwell.app/v1/server/crawlers"),e.username||e.password||e.search||e.hash||e.protocol!=="https:"&&!(e.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(e.hostname))||!/^tw_sk_[A-Za-z0-9_-]+$/.test(r.serverKey))throw new Error("Invalid configuration")}catch{return{status:"failed",eventId:a,code:"CONFIGURATION"}}o.search="",o.hash="",o.username="",o.password="";let d=JSON.stringify({schema_version:1,event_id:a,timestamp:new Date().toISOString(),url:o.href,user_agent:c.slice(0,1024),...r.statusCode===void 0?{}:{status_code:r.statusCode}});for(let i=0;i<3;i++){try{let s=await fetch(e,{method:"POST",redirect:"error",signal:AbortSignal.timeout(2e3),headers:{"content-type":"application/json",authorization:`Bearer ${r.serverKey}`},body:d});if(s.status===202){let t=await s.json();return t&&typeof t=="object"&&"batch_id"in t&&t.batch_id===a&&"accepted_events"in t&&t.accepted_events===1&&"receipt_version"in t&&t.receipt_version===1?{status:"accepted",eventId:a}:{status:"failed",eventId:a,code:"DELIVERY_REJECTED"}}if(s.status!==408&&s.status!==429&&s.status<500)return{status:"failed",eventId:a,code:"DELIVERY_REJECTED"}}catch{}i<2&&await new Promise(s=>setTimeout(s,150*(i+1)))}return{status:"failed",eventId:a,code:"DELIVERY_UNAVAILABLE"}}export{h as trackAiCrawler};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tracwell",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Privacy-aware browser analytics and optional server-side AI crawler tracking for Tracwell",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"types": "./dist/npm/index.d.ts",
|
|
14
14
|
"import": "./dist/npm/index.js",
|
|
15
15
|
"default": "./dist/npm/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./server": {
|
|
18
|
+
"types": "./dist/npm/server.d.ts",
|
|
19
|
+
"import": "./dist/npm/server.js",
|
|
20
|
+
"default": "./dist/npm/server.js"
|
|
16
21
|
}
|
|
17
22
|
},
|
|
18
23
|
"files": [
|
|
@@ -21,7 +26,9 @@
|
|
|
21
26
|
"dist/npm/config.d.ts",
|
|
22
27
|
"dist/npm/types.d.ts",
|
|
23
28
|
"LICENSE",
|
|
24
|
-
"README.md"
|
|
29
|
+
"README.md",
|
|
30
|
+
"dist/npm/server.js",
|
|
31
|
+
"dist/npm/server.d.ts"
|
|
25
32
|
],
|
|
26
33
|
"keywords": [
|
|
27
34
|
"analytics",
|