tracwell 0.2.0 → 0.3.1

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 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
- Loading the script captures the initial page view and exposes the same client
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 to set trusted
89
- collector fields. It must not contain secrets or connect to ClickHouse.
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,29 @@ 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.
260
+
261
+ Use 0.3.1 or newer on Cloudflare Workers: crawler delivery uses manual redirect
262
+ handling because Workers does not support the fetch redirect error mode. Redirect
263
+ responses are rejected without forwarding the server key.
@@ -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(s){return l.find(r=>new RegExp(`(?:^|[\\s;(])${r.token}(?:/|[\\s;)]|$)`,"i").test(s))}async function h(s,r){let c=s.headers.get("user-agent")??"";if(!["GET","HEAD"].includes(s.method)||!p(c))return{status:"ignored"};let o=new URL(s.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 n=await fetch(e,{method:"POST",redirect:"manual",signal:AbortSignal.timeout(2e3),headers:{"content-type":"application/json",authorization:`Bearer ${r.serverKey}`},body:d});if(n.status===202){let t=await n.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(n.status!==408&&n.status!==429&&n.status<500)return{status:"failed",eventId:a,code:"DELIVERY_REJECTED"}}catch{}i<2&&await new Promise(n=>setTimeout(n,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.2.0",
4
- "description": "Small, privacy-aware browser analytics SDK for Tracwell",
3
+ "version": "0.3.1",
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",