{"_id":"@absmartly/managed-component","name":"@absmartly/managed-component","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@absmartly/managed-component","version":"0.1.0","description":"ABsmartly Managed Component for Cloudflare Zaraz and WebCM - Flicker-free A/B testing at the edge","main":"dist/index.js","bin":{"absmartly-mc":"bin/cli.js"},"scripts":{"lint":"eslint --ext .ts src","lint:fix":"eslint --ext .ts src --fix","bundle":"node esbuild.js","build":"npm run typecheck && npm run lint && npm run bundle","build:dev":"npm run typecheck && npm run bundle","typecheck":"tsc --project tsconfig.build.json --noEmit","test":"vitest run --globals --passWithNoTests","test:watch":"vitest --globals --passWithNoTests","test:ui":"vitest --ui --globals --passWithNoTests","deploy:zaraz":"npm run build && npm run deploy:worker","deploy:worker":"cp dist/index.js worker/src/component.js && cp manifest.json worker/src/ && cp -r assets worker/src/ && cd worker && npm install && wrangler deploy","release":"npm run build && npm version patch && npm publish"},"repository":{"type":"git","url":"git+https://github.com/absmartly/absmartly-managed-component.git"},"keywords":["webcm","managed-components","absmartly","ab-testing","experiments","cloudflare","zaraz","edge-computing"],"author":{"name":"ABsmartly Team","email":"support@absmartly.com"},"license":"MIT","bugs":{"url":"https://github.com/absmartly/absmartly-managed-component/issues"},"homepage":"https://github.com/absmartly/absmartly-managed-component#readme","dependencies":{"@absmartly/javascript-sdk":"^1.13.2","@absmartly/sdk-plugins":"*","linkedom":"^0.18.12","xss":"^1.0.15"},"devDependencies":{"@managed-components/types":"^1.3.1","@types/dompurify":"^3.0.5","@types/node":"^20.0.0","@typescript-eslint/eslint-plugin":"^5.27.0","@vitest/ui":"^0.34.0","cheerio":"^1.0.0-rc.12","esbuild":"^0.19.0","eslint":"^8.16.0","eslint-config-prettier":"^8.5.0","eslint-plugin-prettier":"^5.0.0","typescript":"^5.0.0","vitest":"^0.34.0"},"_id":"@absmartly/managed-component@0.1.0","gitHead":"8cf3e8d485802f0cfd5241937c73034f6cb17a21","_nodeVersion":"22.15.0","_npmVersion":"11.3.0","dist":{"integrity":"sha512-OhG/c9Nf2IQa0ApzYvEkBYUXMeokOxpTMVl+NiQQi7nmnbrksIGwf53zgt1E+LphbwNesAZ2znStUCtWQ6Lf2g==","shasum":"142f5568c294f5659ff096e4b38de48db3730df7","tarball":"https://registry.npmjs.org/@absmartly/managed-component/-/managed-component-0.1.0.tgz","fileCount":10,"unpackedSize":2139190,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCWXopZKiQttJSAUdTSAvO4PMQXR4oci8s0+KUBiif5DwIgFNjtw8ptx4ohz/9TB1k2TxLk3nnco9nFU7fDDmGf4GM="}]},"_npmUser":{"name":"joalves","email":"jonas@absmartly.com"},"directories":{},"maintainers":[{"name":"marcioapm","email":"marcioapm@gmail.com"},{"name":"joalves","email":"jonas@absmartly.com"},{"name":"caltheabtester","email":"cal@absmartly.com"},{"name":"marcioabs","email":"marcio@absmartly.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/managed-component_0.1.0_1769089641404_0.42378053844472885"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-22T13:47:21.290Z","0.1.0":"2026-01-22T13:47:21.551Z","modified":"2026-01-22T13:47:21.847Z"},"maintainers":[{"name":"marcioapm","email":"marcioapm@gmail.com"},{"name":"joalves","email":"jonas@absmartly.com"},{"name":"caltheabtester","email":"cal@absmartly.com"},{"name":"marcioabs","email":"marcio@absmartly.com"}],"description":"ABsmartly Managed Component for Cloudflare Zaraz and WebCM - Flicker-free A/B testing at the edge","homepage":"https://github.com/absmartly/absmartly-managed-component#readme","keywords":["webcm","managed-components","absmartly","ab-testing","experiments","cloudflare","zaraz","edge-computing"],"repository":{"type":"git","url":"git+https://github.com/absmartly/absmartly-managed-component.git"},"author":{"name":"ABsmartly Team","email":"support@absmartly.com"},"bugs":{"url":"https://github.com/absmartly/absmartly-managed-component/issues"},"license":"MIT","readme":"# ABsmartly Managed Component\n\nFlicker-free A/B testing at the edge with ABsmartly - powered by Cloudflare Zaraz and WebCM.\n\n## Features\n\n- 🚀 **Edge-based context creation** - 60-70% faster than client-only SDK\n- ⚡ **Zero flicker** - Server-side HTML processing in both Zaraz and WebCM modes\n- 🎨 **Visual Editor support** - All 10 DOM change types\n- 🔧 **Two deployment modes** - Zaraz (Cloudflare) or WebCM (custom infrastructure)\n- 🍪 **Persistent user identity** - Cookie-based tracking\n- 🧪 **QA override support** - URL params + Browser Extension\n- 📊 **Event tracking** - Goals, ecommerce, web vitals\n- 📱 **SPA compatible** - Works with React, Vue, Angular via ABsmartly SDK\n- 🎯 **Treatment tags** - React-like HTML syntax for inline experiments\n- 👁️ **Viewport tracking** - Client-side exposure on element visibility\n- 🔍 **Full CSS selectors** - Complex selectors with linkedom (both modes)\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Deployment Modes](#deployment-modes)\n- [Configuration](#configuration)\n- [Usage](#usage)\n  - [Automatic Mode](#automatic-mode-no-html-changes)\n  - [Treatment Tags](#treatment-tags-new)\n  - [Legacy Embeds](#legacy-embeds-zaraz)\n  - [QA Mode](#testing-experiments-qa-mode)\n- [Supported DOM Change Types](#supported-dom-change-types)\n- [Performance](#performance)\n- [Documentation](#documentation)\n- [Development](#development)\n\n## Quick Start\n\n### Option A: Cloudflare Zaraz (Recommended)\n\n1. **Deploy the Worker**\n   ```bash\n   npm install\n   npm run deploy:zaraz\n   ```\n\n2. **Add to Zaraz**\n\n   See the complete setup guide: **[ZARAZ_SETUP.md](./ZARAZ_SETUP.md)**\n\n   Quick summary:\n   - Go to Cloudflare Dashboard → Zaraz → Third-party tools\n   - Click \"Add new tool\" → \"Custom Managed Component\"\n   - Select `custom-mc-absmartly` worker\n   - Configure ABsmartly settings\n   - Grant permissions and publish\n   - Add triggers (Pageview is automatic)\n\n3. **Done!** Your experiments will now run with minimal flicker.\n\n### Option B: WebCM Proxy (Custom Infrastructure)\n\n1. **Install WebCM**\n   ```bash\n   npm install -g webcm\n   ```\n\n2. **Create `webcm.config.json`**\n   ```json\n   {\n     \"hostname\": \"localhost\",\n     \"port\": 1337,\n     \"target\": \"http://localhost:3000\",\n     \"components\": [{\n       \"name\": \"absmartly\",\n       \"path\": \"./dist/index.js\",\n       \"settings\": {\n         \"DEPLOYMENT_MODE\": \"webcm\",\n         \"ABSMARTLY_API_KEY\": \"your-api-key\",\n         \"ABSMARTLY_ENDPOINT\": \"https://api.absmartly.io/v1\",\n         \"ABSMARTLY_ENVIRONMENT\": \"production\",\n         \"ABSMARTLY_APPLICATION\": \"website\"\n       }\n     }]\n   }\n   ```\n\n3. **Run WebCM**\n   ```bash\n   webcm --config webcm.config.json\n   ```\n\n4. **Deploy to production** (nginx → WebCM → Origin)\n\n## Deployment Modes\n\n### Zaraz Mode (Server-Side with Request Interception)\n\n**Architecture**: Edge modifies HTML → Browser receives final version\n\n**Best for**:\n- Easy deployment via Cloudflare Dashboard\n- Websites already using Cloudflare Zaraz\n- When you need flexibility to switch between modes\n- Zero-flicker experiments with server-side DOM changes\n\n**How it works**:\n1. Edge intercepts HTTP requests and creates ABsmartly context\n2. Modifies HTML response with Treatment tags and DOM changes\n3. Browser receives final HTML (zero flicker!)\n4. Optional: Client-side JavaScript for on-view tracking and SPA support\n\n**Flicker**: 0ms (HTML is modified server-side before reaching browser)\n\n### WebCM Mode (Server-Side)\n\n**Architecture**: Edge modifies HTML → Browser receives final version\n\n**Best for**:\n- When you control the infrastructure (nginx, etc.)\n- Custom routing and filtering requirements\n- Integration with existing proxies\n- Complex CSS selectors (with linkedom support)\n\n**How it works**:\n1. Edge creates ABsmartly context\n2. Modifies HTML response directly using linkedom\n3. Browser receives final HTML (no JavaScript needed)\n4. Optional: SPA bridge for client-side navigation\n\n**Flicker**: 0ms (HTML is already modified)\n\n### Mode Comparison\n\n|  Feature               | Zaraz Mode                              | WebCM Mode                            |\n|------------------------|-----------------------------------------|---------------------------------------|\n| **Deployment**         | Via Cloudflare Dashboard                | Custom proxy/infrastructure           |\n| **Setup Complexity**   | Easy (few clicks)                       | Advanced (req. proxy setup)           |\n| **HTML Processing**    | Server-side (linkedom)                  | Server-side (linkedom)                |\n| **CSS Selectors**      | Full support                            | Full support                          |\n| **DOM Changes**        | Server-side                             | Server-side                           |\n| **Treatment Tags**     | Server-side                             | Server-side                           |\n| **Flicker**            | 0ms                                     | 0ms                                   |\n| **On-View Tracking**   | Yes                                     | Yes                                   |\n| **Client-side Bundle** | ~2-2.5KB (anti-flicker, trigger-on-view)| ~2-2.5KB (same bundle)                |\n| **Event Tracking**     | Pageview, track, event, ecommerce       | track, event, ecommerce               |\n| **Use Case**           | Easy deployment, Zaraz users            | Custom infrastructure, zero client JS |\n\n### Key Differences Explained\n\n**🎉 Both modes now have COMPLETE feature parity for A/B testing:**\n- ✅ Both use linkedom for full CSS selector support\n- ✅ Both process HTML server-side (zero flicker)\n- ✅ Both support Treatment tags and DOM changes identically\n- ✅ Both support on-view exposure tracking (ExperimentView events)\n- ✅ Both inject the same lightweight client bundle (~2-2.5KB for anti-flicker + trigger-on-view)\n- ✅ Both handle the same event types\n\n**The ONLY differences are:**\n\n1. **Deployment Method**\n   - **Zaraz**: Deploy via Cloudflare Dashboard in minutes (no infrastructure changes)\n   - **WebCM**: Deploy via custom proxy infrastructure (nginx → WebCM → origin)\n\n2. **Event Handling**\n   - **Zaraz**: Full event ecosystem including `pageview` event\n   - **WebCM**: `track`, `event`, `ecommerce` events (no pageview)\n\n3. **Client SDK Integration**\n   - **Zaraz**: Optional client SDK injection for client-side A/B testing (SPA navigation)\n   - **WebCM**: Use ABsmartly SDK directly for SPA support (no bridge needed)\n\n**Choose Zaraz if:**\n- You already use Cloudflare and want easy 1-click setup\n- You want experiments running without infrastructure changes\n- You need built-in client SDK support for client-side A/B testing\n\n**Choose WebCM if:**\n- You control your own infrastructure (nginx, reverse proxy, etc.)\n- You need custom request routing or filtering logic\n- You want to integrate with an existing edge proxy\n- You prefer to manage the deployment yourself\n\n## Configuration\n\n### Required Settings\n\n| Setting | Type | Description |\n|---------|------|-------------|\n| `ABSMARTLY_API_KEY` | string | ABsmartly API key from dashboard |\n| `ABSMARTLY_ENDPOINT` | string | API endpoint (e.g., `https://api.absmartly.io/v1`) |\n| `ABSMARTLY_ENVIRONMENT` | string | Environment name (e.g., `production`, `development`) |\n| `ABSMARTLY_APPLICATION` | string | Application name from ABsmartly |\n\n### Deployment Settings\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `DEPLOYMENT_MODE` | string | `\"zaraz\"` | Deployment mode: `\"zaraz\"` or `\"webcm\"` |\n\n### Cookie Settings\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `COOKIE_NAME` | string | `\"absmartly_id\"` | Cookie name for user ID |\n| `COOKIE_MAX_AGE` | number | `365` | Cookie lifetime in days |\n\n### Anti-Flicker Settings (Both Modes)\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `ENABLE_ANTI_FLICKER` | boolean | `true` | Enable anti-flicker CSS injection |\n| `HIDE_SELECTOR` | string | `\"body\"` | CSS selector to hide during loading |\n| `HIDE_TIMEOUT` | number | `3000` | Maximum hide time in milliseconds |\n| `TRANSITION_MS` | string | `\"300\"` | Fade-in duration in milliseconds |\n\n### Client-Side Features (Both Modes)\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `INJECT_CLIENT_BUNDLE` | boolean | `true` | Inject client bundle (anti-flicker + trigger-on-view) |\n| `ENABLE_TRIGGER_ON_VIEW` | boolean | `true` | Enable viewport exposure tracking with IntersectionObserver |\n\n### Client SDK Injection (Zaraz Only)\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `INJECT_CLIENT_SDK` | boolean | `true` | Inject ABsmartly SDK for client-side A/B testing (SPAs) |\n| `CLIENT_SDK_STRATEGY` | string | `\"zaraz-bundle\"` | SDK injection strategy: `\"zaraz-bundle\"` (served from /_zaraz/absmartly-sdk.js), `\"cdn\"` (from CDN), or `\"custom\"` |\n| `CLIENT_SDK_CDN_PROVIDER` | string | `\"unpkg\"` | CDN provider for external SDK: `\"unpkg\"` or `\"jsdelivr\"` (used when strategy is `\"cdn\"`) |\n| `CLIENT_SDK_VERSION` | string | `\"latest\"` | SDK version to load from CDN (e.g., `\"1.15.0\"`, `\"latest\"`) (used when strategy is `\"cdn\"`) |\n| `CLIENT_SDK_URL` | string | - | Custom SDK URL (only used if `CLIENT_SDK_STRATEGY` is `\"custom\"`) |\n| `PASS_SERVER_PAYLOAD` | boolean | `true` | Pass server-side context data to client SDK (avoids CDN fetch on pageload) |\n\n### Feature Flags\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `ENABLE_WEB_VITALS` | boolean | `false` | Track Core Web Vitals (CLS, LCP, FID, etc.) |\n| `ENABLE_EMBEDS` | boolean | `true` | Enable server-side Treatment tag processing |\n| `INJECT_CLIENT_DATA` | boolean | `false` | Inject experiment data into page (WebCM only) |\n| `ENABLE_DEBUG` | boolean | `false` | Enable debug logging in browser console |\n\n### Advanced Settings\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `VARIANT_MAPPING` | object | `{}` | Map variant names to treatment numbers (e.g., `{\"control\": 0, \"variant\": 1}`) |\n| `EXCLUDED_PATHS` | array | `[]` | Paths to exclude from manipulation (WebCM only) |\n\n### Configuration Examples\n\n#### Zaraz Mode - Basic\n```javascript\n{\n  \"DEPLOYMENT_MODE\": \"zaraz\",\n  \"ABSMARTLY_API_KEY\": \"your-api-key\",\n  \"ABSMARTLY_ENDPOINT\": \"https://api.absmartly.io/v1\",\n  \"ABSMARTLY_ENVIRONMENT\": \"production\",\n  \"ABSMARTLY_APPLICATION\": \"website\"\n}\n```\n\n#### Zaraz Mode - With Treatment Tags\n```javascript\n{\n  \"DEPLOYMENT_MODE\": \"zaraz\",\n  \"ABSMARTLY_API_KEY\": \"your-api-key\",\n  \"ABSMARTLY_ENDPOINT\": \"https://api.absmartly.io/v1\",\n  \"ABSMARTLY_ENVIRONMENT\": \"production\",\n  \"ABSMARTLY_APPLICATION\": \"website\",\n  \"ENABLE_EMBEDS\": true,\n  \"VARIANT_MAPPING\": {\n    \"control\": 0,\n    \"variant_a\": 1,\n    \"variant_b\": 2\n  }\n}\n```\n\n#### WebCM Mode - Basic\n```javascript\n{\n  \"DEPLOYMENT_MODE\": \"webcm\",\n  \"ABSMARTLY_API_KEY\": \"your-api-key\",\n  \"ABSMARTLY_ENDPOINT\": \"https://api.absmartly.io/v1\",\n  \"ABSMARTLY_ENVIRONMENT\": \"production\",\n  \"ABSMARTLY_APPLICATION\": \"website\"\n}\n```\n\n#### Zaraz Mode - With Client SDK (SPAs)\n```javascript\n{\n  \"DEPLOYMENT_MODE\": \"zaraz\",\n  \"ABSMARTLY_API_KEY\": \"your-api-key\",\n  \"ABSMARTLY_ENDPOINT\": \"https://api.absmartly.io/v1\",\n  \"ABSMARTLY_ENVIRONMENT\": \"production\",\n  \"ABSMARTLY_APPLICATION\": \"website\",\n  \"INJECT_CLIENT_SDK\": true,\n  // CLIENT_SDK_STRATEGY defaults to \"zaraz-bundle\" (served from /_zaraz/absmartly-sdk.js)\n  \"PASS_SERVER_PAYLOAD\": true\n}\n```\n\n#### Zaraz Mode - Client SDK from CDN\n```javascript\n{\n  \"DEPLOYMENT_MODE\": \"zaraz\",\n  \"ABSMARTLY_API_KEY\": \"your-api-key\",\n  \"ABSMARTLY_ENDPOINT\": \"https://api.absmartly.io/v1\",\n  \"ABSMARTLY_ENVIRONMENT\": \"production\",\n  \"ABSMARTLY_APPLICATION\": \"website\",\n  \"INJECT_CLIENT_SDK\": true,\n  \"CLIENT_SDK_STRATEGY\": \"cdn\",\n  \"CLIENT_SDK_CDN_PROVIDER\": \"jsdelivr\",\n  \"CLIENT_SDK_VERSION\": \"1.15.0\",\n  \"PASS_SERVER_PAYLOAD\": true\n}\n```\n\n## Usage\n\n### Automatic Mode (No HTML Changes)\n\nJust enable the component - it handles everything automatically:\n\n1. Creates ABsmartly context on the edge\n2. Assigns users to experiment treatments\n3. Applies DOM changes from Visual Editor\n4. Tracks exposures and goals\n\n**No code changes required!**\n\n### Treatment Tags (NEW)\n\nReact-like HTML syntax for defining experiment variants inline. Works in both Zaraz and WebCM modes.\n\n#### Basic Example\n\n```html\n<Treatment name=\"hero_test\">\n  <TreatmentVariant variant=\"0\">Hello World</TreatmentVariant>\n  <TreatmentVariant variant=\"1\">Ola Mundo</TreatmentVariant>\n</Treatment>\n```\n\n**Server-side output for user in treatment 1:**\n```html\nOla Mundo\n```\n\n#### Alphabetic Variants\n\nUse letters instead of numbers for better readability:\n\n```html\n<Treatment name=\"hero_test\">\n  <TreatmentVariant variant=\"A\">Version A</TreatmentVariant>\n  <TreatmentVariant variant=\"B\">Version B</TreatmentVariant>\n  <TreatmentVariant variant=\"C\">Version C</TreatmentVariant>\n</Treatment>\n```\n\nAutomatic mapping: A=0, B=1, C=2, ...\n\n#### Named Variants\n\nUse custom variant names with `VARIANT_MAPPING`:\n\n```html\n<Treatment name=\"pricing_test\">\n  <TreatmentVariant variant=\"control\">$99/month</TreatmentVariant>\n  <TreatmentVariant variant=\"discount\">$79/month</TreatmentVariant>\n</Treatment>\n```\n\n**Configuration:**\n```javascript\n{\n  \"VARIANT_MAPPING\": {\n    \"control\": 0,\n    \"discount\": 1\n  }\n}\n```\n\n#### Default Fallback\n\nVariant 0 or A serves as the control/default when no treatment is assigned:\n\n```html\n<Treatment name=\"promo_banner\">\n  <TreatmentVariant variant=\"A\">Limited Time: 50% Off!</TreatmentVariant>\n  <TreatmentVariant variant=\"0\">Shop Now</TreatmentVariant>\n</Treatment>\n```\n\n**Note:** The parser implicitly uses variant `0` (numeric) or variant `A` (alphabetic) as the default when no matching treatment is found. You must explicitly specify `variant=\"0\"` or `variant=\"A\"` to define control content.\n\n#### Trigger-on-View (Viewport Tracking)\n\nTrack exposure only when content enters the viewport:\n\n```html\n<Treatment name=\"below_fold_cta\" trigger-on-view>\n  <TreatmentVariant variant=\"A\">Sign Up Free</TreatmentVariant>\n  <TreatmentVariant variant=\"B\">Get Started</TreatmentVariant>\n</Treatment>\n```\n\n**Server-side output:**\n```html\n<span trigger-on-view=\"below_fold_cta\">Get Started</span>\n```\n\n**Client-side behavior:**\n- IntersectionObserver watches for element visibility\n- Tracks exposure when element is 50% visible\n- Prevents SRM from never-seen variants\n\n#### Complex Example\n\n```html\n<section class=\"hero\">\n  <Treatment name=\"hero_headline\" trigger-on-view>\n    <TreatmentVariant variant=\"A\">\n      <h1>Grow Your Business</h1>\n      <p class=\"subheadline\">Join 10,000+ companies</p>\n    </TreatmentVariant>\n    <TreatmentVariant variant=\"B\">\n      <h1>Scale with Confidence</h1>\n      <p class=\"subheadline\">Trusted by industry leaders</p>\n    </TreatmentVariant>\n    <TreatmentVariant variant=\"0\">\n      <h1>Welcome</h1>\n    </TreatmentVariant>\n  </Treatment>\n\n  <Treatment name=\"hero_cta\">\n    <TreatmentVariant variant=\"A\">\n      <button class=\"btn-primary\">Start Free Trial</button>\n    </TreatmentVariant>\n    <TreatmentVariant variant=\"B\">\n      <button class=\"btn-primary\">Get Started Free</button>\n    </TreatmentVariant>\n  </Treatment>\n</section>\n```\n\n#### Treatment Tags Reference\n\n**Supported Attributes:**\n\n`<Treatment>`:\n- `name` (required): Experiment name from ABsmartly\n- `trigger-on-view` (optional): Enable viewport tracking\n\n`<TreatmentVariant>`:\n- `variant` (required): Treatment number (0, 1, 2) or letter (A, B, C)\n\n**Variant Rules:**\n- Use **numeric variants only** (0, 1, 2, 3) OR **alphabetic variants only** (A, B, C, D)\n- Do **not mix** numeric and alphabetic variants in the same Treatment tag\n- ❌ Invalid: `<TreatmentVariant variant=\"0\">` and `<TreatmentVariant variant=\"A\">` in same Treatment\n- ✅ Valid: `<TreatmentVariant variant=\"0\">` and `<TreatmentVariant variant=\"1\">` in same Treatment\n- ✅ Valid: `<TreatmentVariant variant=\"A\">` and `<TreatmentVariant variant=\"B\">` in same Treatment\n- Variant 0 (numeric) or A (alphabetic) implicitly serves as the control/default\n\n**Processing:**\n- Server-side: Entire Treatment block is replaced with selected variant\n- Only the selected variant content remains in HTML\n- No loading or client-side rendering needed\n- Works with JavaScript disabled\n\n**Tracking:**\n- Default: Exposure tracked server-side when HTML is generated\n- With `trigger-on-view`: Exposure tracked client-side when visible\n- Sends `ExperimentView` event to ABsmartly\n\n**Availability:**\n- ✅ Zaraz mode\n- ✅ WebCM mode\n\n**More Examples**: See [Treatment Tags Complete Guide](docs/TREATMENT_TAGS_GUIDE.md) for:\n- E-commerce product cards\n- Landing page heroes\n- Pricing page variations\n- Email signup forms\n- Complex multi-variant tests\n- Troubleshooting guide\n- API reference\n\n#### Advanced Treatment Tag Examples\n\n**Named Variants with Mapping:**\n```html\n<!-- HTML -->\n<Treatment name=\"pricing\">\n  <TreatmentVariant variant=\"control\">$9/month</TreatmentVariant>\n  <TreatmentVariant variant=\"premium\">$15/month</TreatmentVariant>\n</Treatment>\n\n<!-- Configuration -->\n{\n  \"VARIANT_MAPPING\": {\n    \"control\": 0,\n    \"premium\": 1\n  }\n}\n```\n\n**Multiple Treatments with Complex HTML:**\n```html\n<div class=\"hero\">\n  <h1>\n    <Treatment name=\"headline\">\n      <TreatmentVariant variant=\"A\">Transform Your Business</TreatmentVariant>\n      <TreatmentVariant variant=\"B\">10x Your Revenue</TreatmentVariant>\n    </Treatment>\n  </h1>\n\n  <Treatment name=\"cta_section\" trigger-on-view>\n    <TreatmentVariant variant=\"0\">\n      <button class=\"btn-primary\">Start Free Trial</button>\n      <p>No credit card required</p>\n    </TreatmentVariant>\n    <TreatmentVariant variant=\"1\">\n      <button class=\"btn-success btn-large\">Get Started Free</button>\n      <p>✓ 30-day money back guarantee</p>\n      <p>✓ Cancel anytime</p>\n    </TreatmentVariant>\n  </Treatment>\n</div>\n```\n\n### Testing Experiments (QA Mode)\n\n#### URL Override\n\nForce specific treatments via URL parameters:\n\n```\nhttps://yoursite.com?absmartly_experiment_name=1\n```\n\nExamples:\n- `?absmartly_hero_test=0` - Force treatment 0\n- `?absmartly_hero_test=1` - Force treatment 1\n- `?absmartly_hero_test=2&absmartly_cta_test=1` - Multiple overrides\n\n#### Browser Extension\n\nInstall the ABsmartly Browser Extension for a better QA experience:\n- Visual treatment picker\n- Experiment list\n- Override management\n- No URL parameters needed\n\nOverrides are automatically detected and applied.\n\n### SPA Support\n\nBoth modes support Single-Page Applications through the **ABsmartly SDK**:\n\n**First Page Load:**\n- Server-side: HTML is manipulated at the edge (0ms flicker)\n- Browser receives final HTML with experiment applied\n\n**Client-Side Navigation:**\n- ABsmartly SDK detects navigation via History API\n- Automatically fetches new context for current URL\n- Applies experiment treatments client-side\n- No managed component action needed\n\n**Configuration:**\n\nSimply use the ABsmartly SDK on your SPA as you would normally:\n\n```javascript\nconst context = await sdk.createContext({ ... })\ncontext.ready().then(() => {\n  const treatment = context.treatment('experiment_name')\n  // Apply treatment in your component\n})\ncontext.publish()\n```\n\nThe managed component handles:\n- Initial page load experiments (server-side)\n- Context creation with correct user identity\n- Exposure tracking via `context.publish()`\n\nThe ABsmartly SDK handles:\n- Client-side navigation detection\n- On-demand context creation during navigation\n- Treatment application in client code\n\n**Why this approach?**\n- Simpler integration (no duplicate logic)\n- Better control over when treatments apply\n- Works with any framework\n- Reduces managed component complexity\n\n## Supported DOM Change Types\n\nAll 10 types from ABsmartly Visual Editor are supported:\n\n### 1. Text Change\nChange text content of elements\n```javascript\n{\n  \"selector\": \"h1.hero-title\",\n  \"type\": \"text\",\n  \"value\": \"New Headline\"\n}\n```\n\n### 2. HTML Change\nReplace innerHTML\n```javascript\n{\n  \"selector\": \".banner\",\n  \"type\": \"html\",\n  \"value\": \"<div class='promo'>Sale!</div>\"\n}\n```\n\n### 3. Style Change\nModify inline styles\n```javascript\n{\n  \"selector\": \".cta-button\",\n  \"type\": \"style\",\n  \"styles\": {\n    \"backgroundColor\": \"#ff0000\",\n    \"fontSize\": \"18px\"\n  }\n}\n```\n\n### 4. Class Change\nAdd or remove CSS classes\n```javascript\n{\n  \"selector\": \".card\",\n  \"type\": \"class\",\n  \"action\": \"add\",\n  \"value\": \"highlighted\"\n}\n```\n\n### 5. Attribute Change\nSet or remove attributes\n```javascript\n{\n  \"selector\": \"img.hero\",\n  \"type\": \"attribute\",\n  \"name\": \"src\",\n  \"value\": \"/images/hero-v2.jpg\"\n}\n```\n\n### 6. Move Element\nRelocate elements in the DOM\n```javascript\n{\n  \"selector\": \".testimonial\",\n  \"type\": \"move\",\n  \"target\": \".sidebar\",\n  \"position\": \"append\"\n}\n```\n\n### 7. Delete Element\nRemove elements from the DOM\n```javascript\n{\n  \"selector\": \".old-banner\",\n  \"type\": \"delete\"\n}\n```\n\n### 8. JavaScript\nExecute custom JavaScript\n```javascript\n{\n  \"selector\": \"body\",\n  \"type\": \"javascript\",\n  \"value\": \"console.log('Experiment loaded');\"\n}\n```\n\n### 9. Create Element\nCreate new DOM elements\n```javascript\n{\n  \"selector\": \".container\",\n  \"type\": \"create\",\n  \"html\": \"<div class='new-feature'>Try it now!</div>\",\n  \"position\": \"beforeend\"\n}\n```\n\n### 10. Style Rules\nAdd global CSS rules\n```javascript\n{\n  \"selector\": \"body\",\n  \"type\": \"styleRules\",\n  \"css\": \".special { color: blue; font-weight: bold; }\"\n}\n```\n\n### Trigger-on-View Support\n\nAdd viewport tracking to any change:\n\n```javascript\n{\n  \"selector\": \".below-fold-section\",\n  \"type\": \"text\",\n  \"value\": \"Visible content\",\n  \"trigger_on_view\": true\n}\n```\n\n**Behavior:**\n- Change is applied immediately\n- Exposure is tracked when element enters viewport\n- Uses IntersectionObserver (50% visibility threshold)\n- Prevents SRM for below-the-fold experiments\n\n## Performance\n\n### Benchmark Comparison\n\n| Metric | Client SDK | Zaraz MC | WebCM MC |\n|--------|-----------|----------|----------|\n| Context Creation | 150-300ms | 50-100ms | 50-100ms |\n| Flicker Duration | 300-500ms | **0ms** | **0ms** |\n| Page Load Impact | +500KB | +2.5KB | +2.5KB |\n| CSS Selectors | Basic | Full (linkedom) | Full (linkedom) |\n| Server Response Time | 0ms | 0ms | +10-30ms |\n\n**Note**: Both Zaraz and WebCM modes are now functionally identical. They share the same server-side HTML processing, client bundle, and performance characteristics. The only difference is deployment method (Cloudflare vs. custom proxy).\n\n### Bundle Sizes\n\n| Mode | Client Bundle | Server Bundle |\n|------|--------------|---------------|\n| Zaraz | ~2-2.5KB (anti-flicker + trigger-on-view) | - |\n| WebCM | ~2-2.5KB (same as Zaraz) | 721KB (includes linkedom) |\n\n**Note**: Client bundle size is minimal and shared between both modes. It includes anti-flicker CSS, trigger-on-view script, and initialization code only. No DOM manipulation code is included.\n\n### Best Practices\n\n**For best performance:**\n\n1. **Minimize DOM changes**: Fewer changes = faster application\n2. **Use specific selectors**: `.hero-title` is faster than `div > h1`\n3. **Avoid JavaScript changes**: Use declarative changes when possible\n4. **Set appropriate timeout**: `HIDE_TIMEOUT` should match your P95 load time\n5. **Both modes deliver zero flicker**: No performance trade-off between Zaraz and WebCM\n\n## Documentation\n\n### Comprehensive Guides\n\n- **[Treatment Tags Complete Guide](docs/TREATMENT_TAGS_GUIDE.md)** - Everything about Treatment Tags\n  - Quick start and basic syntax\n  - Variant identifiers (numeric, alphabetic, named)\n  - Advanced features (trigger-on-view, defaults, mappings)\n  - Configuration and best practices\n  - Troubleshooting and FAQ\n  - API reference and examples\n\n- **[Setup Guide](docs/SETUP_GUIDE.md)** - Production deployment guide\n  - ABsmartly dashboard configuration\n  - Server-side experiment setup\n  - Cloudflare Zaraz configuration\n  - DOM changes reference\n  - End-to-end examples\n  - Migration from original plugin\n\n- **[Future Enhancements](docs/FUTURE_ENHANCEMENTS.md)** - Experimental features and roadmap\n  - JavaScript bundle processing (CSR SPA support)\n  - Advanced targeting rules\n  - Multi-armed bandit algorithms\n  - Edge-Side Includes (ESI)\n  - GraphQL API and real-time updates\n\n### Test Coverage\n\nThe codebase includes comprehensive test coverage:\n\n- **HTML Embed Parser**: 57 test cases covering all edge cases\n  - Parsing (numeric, alphabetic, trigger-on-view, defaults)\n  - Replacement logic (fallbacks, mappings, wrapping)\n  - Processing (multiple treatments, missing experiments)\n  - Validation (duplicates, defaults, structure)\n  - Edge cases (whitespace, entities, malformed HTML)\n\nRun tests:\n```bash\nnpm test\n```\n\nRun specific test suite:\n```bash\nnpm test tests/unit/core/html-embed-parser.test.ts\n```\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Type check\nnpm run typecheck\n\n# Lint\nnpm run lint\n\n# Build\nnpm run build\n\n# Build for development (skip lint)\nnpm run build:dev\n\n# Test\nnpm test\n\n# Test with watch mode\nnpm run test:watch\n\n# Test with UI\nnpm run test:ui\n```\n\n## Project Structure\n\n```\nsrc/\n├── index.ts                      # Main entry point\n├── types.ts                      # TypeScript types\n├── core/                         # Shared core components\n│   ├── context-manager.ts        # ABsmartly SDK integration\n│   ├── cookie-handler.ts         # User identity & cookies\n│   ├── overrides-handler.ts      # QA overrides\n│   └── event-tracker.ts          # Goal & event tracking\n├── zaraz/                        # Zaraz mode\n│   ├── setup.ts                  # Zaraz initialization\n│   ├── client-injector.ts        # Script injection\n│   ├── embed-handler.ts          # Embed processing\n│   ├── html-embed-parser.ts      # Treatment tag parser (NEW)\n│   └── client-bundle/            # Client-side code\n│       ├── dom-manipulator.ts    # DOM changes bundler\n│       ├── initializer.ts        # Initialization bundler\n│       └── scripts/\n│           ├── dom-manipulator.js    # DOM manipulation\n│           ├── init-template.js      # Init template\n│           └── web-vitals-loader.js  # Web vitals\n├── webcm/                        # WebCM mode\n│   ├── setup.ts                  # WebCM initialization\n│   ├── response-manipulator.ts   # HTML manipulation\n│   ├── html-parser.ts            # Regex-based parser\n│   ├── html-parser-linkedom.ts   # Linkedom parser (NEW)\n│   └── spa-bridge.ts             # SPA navigation (NEW)\n└── utils/                        # Utilities\n    ├── logger.ts                 # Logging\n    ├── serializer.ts             # Data serialization\n    └── script-loader.ts          # Script loading\n```\n\n## Documentation\n\n- [Setup Guide](./docs/SETUP_GUIDE.md) - Complete setup instructions\n- [DOM Changes Comparison](/.claude/tasks/dom_changes_comparison.md) - Feature comparison\n- [Implementation Plan](./PLAN.md) - Technical architecture\n- [Session Context](/.claude/tasks/context_session_120868b7-2a7e-4cb9-a027-b45475aabe7c.md) - Development log\n\n## FAQ\n\n### When should I use Zaraz vs WebCM?\n\nBoth modes now have **identical performance and features** (zero flicker, full CSS selector support, etc.).\n\n**Use Zaraz if:**\n- You're already using Cloudflare\n- You want quick deployment via dashboard (no infrastructure changes)\n- You want built-in client SDK support\n\n**Use WebCM if:**\n- You control your own infrastructure\n- You need custom request routing or filtering\n- You prefer managing deployment yourself\n\n### Do Treatment tags work in WebCM mode?\n\nYes! Treatment tags work in both Zaraz and WebCM modes. When `ENABLE_EMBEDS` is true, the HTML embed parser processes Treatment tags server-side and replaces them with the appropriate variant content before sending the response to the browser.\n\n### How does trigger-on-view work?\n\n1. Server replaces Treatment tag with content + `trigger-on-view` attribute\n2. Client injects IntersectionObserver that scans for elements with this attribute\n3. Watches each element with 50% visibility threshold\n4. When element becomes visible, sends `ExperimentView` track event\n5. ABsmartly records the exposure at that moment (solves below-the-fold SRM)\n\n### Can I use Treatment tags with Visual Editor changes?\n\nYes! They work together:\n- Treatment tags: Inline variant content\n- Visual Editor: DOM changes applied on top\n- Both use the same experiment assignments\n\n### What's the difference between Treatment tags and embeds?\n\n- **Treatment tags**: React-like HTML syntax, server-side processing, clean output\n- **Legacy embeds**: Zaraz embed format, attribute-based, backwards compatibility\n\nTreatment tags are recommended for new implementations.\n\n## Migration Guide\n\n### From Client-Side SDK\n\n1. Remove ABsmartly JavaScript SDK from your site\n2. Configure managed component with same API credentials\n3. Keep experiment configurations in ABsmartly dashboard\n4. Visual Editor changes work automatically\n5. Update tracking code to use `zaraz.track()` (Zaraz) or keep existing (WebCM)\n\n### From Original Plugin\n\nSee [DOM Changes Comparison](/.claude/tasks/dom_changes_comparison.md) for detailed feature differences.\n\n**Quick checklist:**\n- ✅ Basic DOM changes (text, html, style, class, etc.) - Full compatibility\n- ✅ On-view tracking - Supported with `trigger_on_view`\n- ⚠️ URL filtering - Not supported (use server-side routing instead)\n- ⚠️ Cross-variant tracking - Not supported (may cause SRM)\n- ⚠️ Style persistence - Not supported (may have issues with React/Vue)\n\n## Troubleshooting\n\n### Experiments not showing\n\n1. Check API credentials in configuration\n2. Verify experiment is running in ABsmartly dashboard\n3. Check browser console for errors (`ENABLE_DEBUG: true`)\n4. Confirm user is eligible (audience filters, etc.)\n5. Try QA override: `?absmartly_experiment_name=1`\n\n### Flicker on page load\n\n1. Increase `HIDE_TIMEOUT` if experiments are slow to load\n2. Use WebCM mode for zero flicker\n3. Reduce number of DOM changes\n4. Optimize `HIDE_SELECTOR` (narrower = better)\n\n### SPA not working\n\n1. Ensure ABsmartly SDK is properly configured on your frontend\n2. Check if framework uses History API (React Router, Vue Router, etc.)\n3. Verify SDK is fetching contexts on navigation (check Network tab)\n4. For hash routing (#/path), ensure SDK is configured with `hashRouting: true`\n5. Check browser console for SDK errors with `ENABLE_DEBUG: true` on the managed component\n\n### Treatment tags not rendering\n\n1. Verify `ENABLE_EMBEDS: true`\n2. Check HTML syntax (closing tags, quotes, etc.)\n3. Ensure experiment name matches ABsmartly dashboard\n4. Check variant identifiers (0, 1, 2 or A, B, C)\n5. Verify `VARIANT_MAPPING` if using custom names\n\n## License\n\nMIT\n\n## Support\n\n- **GitHub Issues**: https://github.com/absmartly/absmartly-managed-component/issues\n- **ABsmartly Docs**: https://docs.absmartly.com\n- **Email**: support@absmartly.com\n","readmeFilename":"README.md","_rev":"1-c453d9fce1263ba592443aebea0adfac"}