@active-reach/web-sdk

中文文档
1.48.0发布于 2026/10/27MITTypeScriptESM + CJS零依赖近 30 天下载 2635

Web SDK for Active Reach Intelligence — event tracking, identity resolution, in-app messaging, web push, and placements

原始使用文档
文档目录37 节
  1. Prerequisites
  2. Installation
  3. NPM (Recommended)
  4. CDN (Async Loader)
  5. Quick Start
  6. NPM / ES Modules
  7. React
  8. Next.js
  9. Configuration
  10. Core API
  11. aegis.track(eventName, properties?)
  12. aegis.identify(userId, traits?)
  13. aegis.page(name?, properties?)
  14. aegis.group(groupId, traits?)
  15. aegis.alias(newUserId)
  16. aegis.reset()
  17. aegis.flush()
  18. E-Commerce Tracking
  19. All E-Commerce Methods
  20. React Hooks
  21. Consent Management
  22. Third-Party Integrations
  23. Web Push Notifications
  24. In-App Messaging & Widgets
  25. Drive triggers & identity from your app
  26. Placement — how a campaign reaches the customer
  27. Cart state — one store, fed the CEP-standard way
  28. Plugin System
  29. TypeScript Support
  30. Cookies & Storage
  31. Content Security Policy (CSP)
  32. Security
  33. What NOT to track
  34. Debugging
  35. Subpath Exports
  36. Browser Support
  37. License

@active-reach/web-sdk

Web SDK for Active Reach Intelligence — lightweight event tracking, identity resolution, in-app messaging (overlays, embedded cards, interactive widgets), and web push.

12KB gzipped | <1KB async loader | Zero impact on page load


Prerequisites

Before integrating, you need:

  1. Write Key — Retrieve from your Active Reach Intelligence dashboard under Settings > Developer > API Keys.
  2. API Host — Your cell endpoint URL (provided during onboarding).

Note: The write key is a publishable identifier (like a Stripe publishable key). It is safe to include in client-side code. It can only send events — it cannot read data, modify configuration, or access other tenants. Never use your Secret Key in client-side code.


Installation

npm install @active-reach/web-sdk

CDN (Async Loader)

Add this snippet to your <head> tag. The async loader queues all calls until the full SDK loads — zero blocking.

<script>
  !function(){var e=window.aegis=window.aegis||[];if(!e.invoked){e.invoked=!0,e.methods=["init","track","identify","page","group","alias","reset","flush","use","debug","setCell","getCellInfo","getAnonymousId","getUserId","getSessionId","setConsent","grantConsent","denyConsent","hasConsent","getConsentPreferences","onConsentChange"],e.factory=function(t){return function(){var n=Array.prototype.slice.call(arguments);return n.unshift(t),e.push(n),e}};for(var t=0;t<e.methods.length;t++){var n=e.methods[t];e[n]=e.factory(n)}e.load=function(t,n){var o=document.createElement("script");o.type="text/javascript",o.async=!0,o.src=n&&n.cdnUrl?n.cdnUrl:"https://platform.active-reach.ai/sdk/aegis.min.js",o.onerror=function(){window.console&&console.error("Aegis SDK failed to load")};var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(o,r),e._loadOptions={key:t,options:n}},e.SNIPPET_VERSION="1.0.0"}}();

  aegis.load('YOUR_WRITE_KEY');
  aegis.init('YOUR_WRITE_KEY', {
    api_host: 'https://YOUR_CELL.activereach.ai'
  });
</script>

Quick Start

NPM / ES Modules

import aegis from '@active-reach/web-sdk';

await aegis.init('YOUR_WRITE_KEY', {
  api_host: 'https://YOUR_CELL.activereach.ai',
  auto_page_view: true,
});

// Track an event
aegis.track('Purchase Completed', {
  order_id: 'ORD-123',
  revenue: 99.99,
  currency: 'INR',
});

// Identify a user
aegis.identify('user_123', {
  email: '[email protected]',
  name: 'Priya Sharma',
  plan: 'premium',
});

React

import { AegisProvider, useAegis, useTrackEvent } from '@active-reach/web-sdk/react';

function App() {
  return (
    <AegisProvider
      writeKey="YOUR_WRITE_KEY"
      config={{ api_host: 'https://YOUR_CELL.activereach.ai', auto_page_view: true }}
    >
      <Dashboard />
    </AegisProvider>
  );
}

function Dashboard() {
  const { isReady } = useAegis();
  const trackEvent = useTrackEvent();

  return (
    <button onClick={() => trackEvent('Button Clicked', { button: 'CTA' })}>
      Track Event
    </button>
  );
}

Next.js

// app/providers.tsx
'use client';

import { AegisProvider } from '@active-reach/web-sdk/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <AegisProvider
      writeKey={process.env.NEXT_PUBLIC_AEGIS_WRITE_KEY!}
      config={{ api_host: process.env.NEXT_PUBLIC_AEGIS_API_HOST! }}
    >
      {children}
    </AegisProvider>
  );
}

Configuration

await aegis.init('YOUR_WRITE_KEY', {
  // Required
  api_host: string;

  // Batching & Performance
  batch_size?: number;           // default: 10
  batch_interval?: number;       // default: 1000ms

  // Data Capture
  capture_utm?: boolean;         // default: true
  capture_referrer?: boolean;    // default: true
  auto_page_view?: boolean;      // default: false

  // Session
  session_timeout?: number;      // default: 1800000 (30 min)

  // Privacy & Consent
  respect_dnt?: boolean;         // default: true
  enable_consent_mode?: boolean; // default: false
  wait_for_consent?: boolean;    // default: false
  default_consent?: {
    analytics?: boolean;         // default: false
    marketing?: boolean;         // default: false
    functional?: boolean;        // default: true
  };
  integrate_onetrust?: boolean;
  integrate_cookiebot?: boolean;
  integrate_google_consent_mode?: boolean;

  // Cookie
  cross_domain_tracking?: boolean; // default: false
  cookie_domain?: string;
  secure_cookie?: boolean;         // default: true

  // Offline & Retry
  enable_offline_mode?: boolean;   // default: true
  max_offline_events?: number;     // default: 100
  retry_failed_requests?: boolean; // default: true
  max_retries?: number;            // default: 3

  // Regional Cell Selection
  cell_endpoints?: CellEndpoint[];
  preferred_region?: string;
  auto_region_detection?: boolean; // default: true

  // Debug
  debug?: boolean;                 // default: false
});

Core API

aegis.track(eventName, properties?)

Track a custom event.

aegis.track('Product Viewed', {
  product_id: 'SKU-12345',
  product_name: 'Leather Jacket',
  price: 199.99,
  category: 'Outerwear',
});

aegis.identify(userId, traits?)

Identify a user and associate traits.

aegis.identify('user_123', {
  email: '[email protected]',
  name: 'John Doe',
  plan: 'premium',
});

aegis.page(name?, properties?)

Track a page view.

aegis.page('Product Page', { product_id: 'SKU-12345' });

aegis.group(groupId, traits?)

Associate a user with a group (company, organization).

aegis.group('company_789', {
  name: 'Acme Corp',
  industry: 'Technology',
  employees: 500,
});

aegis.alias(newUserId)

Merge two user identities.

aegis.alias('permanent_user_id');

aegis.reset()

Clear user identity on logout. Generates a new anonymous ID.

aegis.reset();

aegis.flush()

Force-send all queued events immediately.

await aegis.flush();

E-Commerce Tracking

Built-in helpers for standardized e-commerce events via aegis.ecommerce:

import aegis from '@active-reach/web-sdk';

// Product discovery
aegis.ecommerce.productViewed({
  product_id: 'SKU-123',
  name: 'Leather Jacket',
  price: 4999,
  currency: 'INR',
  category: 'Outerwear',
  brand: 'Acme',
  variant_id: 'black_xl',
  variant_label: 'Black XL',
});

aegis.ecommerce.productListViewed({
  list_name: 'New Arrivals',
  category: 'Outerwear',
  products: [{ product_id: 'SKU-123', name: 'Leather Jacket', price: 4999 }],
});

aegis.ecommerce.searchPerformed({ query: 'leather jacket', results_count: 12 });

// Cart
aegis.ecommerce.addToCart({
  product_id: 'SKU-123',
  name: 'Leather Jacket',
  price: 4999,
  quantity: 1,
});

aegis.ecommerce.removeFromCart({ product_id: 'SKU-123', name: 'Leather Jacket', price: 4999 });

aegis.ecommerce.cartViewed({
  cart_id: 'cart_456',
  value: 4999,
  products: [{ product_id: 'SKU-123', name: 'Leather Jacket', price: 4999, quantity: 1 }],
});

// Checkout
aegis.ecommerce.checkoutStarted({
  value: 4999,
  products: [{ product_id: 'SKU-123', name: 'Leather Jacket', price: 4999, quantity: 1 }],
  coupon: 'WELCOME10',
  shipping: 99,
  tax: 450,
});

aegis.ecommerce.checkoutStep(2, { payment_method: 'UPI' });

// Order
aegis.ecommerce.orderCompleted({
  order_id: 'ORD-789',
  value: 5548,
  revenue: 4999,
  shipping: 99,
  tax: 450,
  payment_method: 'UPI',
  products: [{ product_id: 'SKU-123', name: 'Leather Jacket', price: 4999, quantity: 1 }],
});

aegis.ecommerce.orderRefunded('ORD-789', 4999);

// Coupons
aegis.ecommerce.couponApplied({ coupon_code: 'WELCOME10', discount_value: 500, discount_type: 'fixed' });
aegis.ecommerce.couponRemoved({ coupon_code: 'WELCOME10' });

// Wishlist
aegis.ecommerce.wishlistItemAdded({
  product: { product_id: 'SKU-123', name: 'Leather Jacket', price: 4999 },
});

// Promotions
aegis.ecommerce.promotionViewed({ name: 'Summer Sale', promotion_id: 'promo_1', creative: 'banner_hero' });
aegis.ecommerce.promotionClicked({ name: 'Summer Sale', promotion_id: 'promo_1' });

All E-Commerce Methods

MethodEvent NameDescription
productViewed(product)product_viewedUser views a product page
productListViewed(list)product_list_viewedUser views a category/collection
searchPerformed(search)search_performedUser searches the catalog
addToCart(product)cart_item_addedItem added to cart
removeFromCart(product)cart_item_removedItem removed from cart
cartViewed(cart)cart_viewedUser views their cart
checkoutStarted(checkout)checkout_startedCheckout flow begins
checkoutStep(step, options?)checkout_stepCheckout step completed
orderCompleted(order)order_completedPurchase completed
orderRefunded(orderId, value?, products?)order_refundedOrder refunded
couponApplied(coupon)coupon_appliedCoupon/discount applied
couponRemoved(coupon)coupon_removedCoupon removed
wishlistItemAdded(wishlist)wishlist_item_addedItem added to wishlist
promotionViewed(promo)promotion_viewedPromotion impression
promotionClicked(promo)promotion_clickedPromotion clicked

React Hooks

Import from @active-reach/web-sdk/react:

HookReturnsDescription
useAegis(){ aegis, isReady }Access SDK instance and readiness state
useTrackEvent()(name, props?) => voidMemoized event tracking callback
usePageView(name?, props?, deps?)—Track page views on mount/dependency change
useIdentifyUser()(userId, traits?) => voidMemoized identify callback

Built-in support for GDPR/CCPA compliance.

// Set preferences
aegis.setConsent({ analytics: true, marketing: false, functional: true });

// Grant / deny
aegis.grantConsent();           // all categories
aegis.grantConsent('analytics'); // specific category

aegis.denyConsent();
aegis.denyConsent('marketing');

// Query
aegis.hasConsent('analytics');   // boolean
aegis.getConsentPreferences();   // full object

// Listen for changes
const unsubscribe = aegis.onConsentChange((prefs) => {
  console.log('Consent updated:', prefs);
});

Third-Party Integrations

// OneTrust
aegis.init('KEY', { enable_consent_mode: true, integrate_onetrust: true });

// Cookiebot
aegis.init('KEY', { enable_consent_mode: true, integrate_cookiebot: true });

// Google Consent Mode v2
aegis.init('KEY', { enable_consent_mode: true, integrate_google_consent_mode: true });

Web Push Notifications

Import from @active-reach/web-sdk/push:

import { AegisWebPush } from '@active-reach/web-sdk/push';

const push = new AegisWebPush({
  writeKey: 'YOUR_WRITE_KEY',
  apiHost: 'https://YOUR_CELL.activereach.ai',
  vapidPublicKey: 'YOUR_VAPID_PUBLIC_KEY',
  contactId: 'user_123',
  organizationId: 'org_456',
  serviceWorkerPath: '/aegis-sw.js',
});

await push.initialize();

Copy dist/aegis-sw.js to your public/ directory so the service worker is served at the root.


In-App Messaging & Widgets

Every in-app format — modals, banners, tooltips, full-screen takeovers, bottom sheets, and interactive widgets (spin-the-wheel, scratch cards, NPS/CSAT surveys, quizzes, countdown offers, star ratings, polls, multi-step forms) — is delivered through a single entry point: AegisMessageRuntime.

import { AegisMessageRuntime } from '@active-reach/web-sdk';

const runtime = new AegisMessageRuntime({
  writeKey: 'YOUR_WRITE_KEY',
  apiHost: 'https://YOUR_CELL.activereach.ai',
  contactId: 'user_123',     // optional — set once the visitor is known
  organizationId: 'org_456',
  propertyId: 'prop_789',    // the SDK install (website/app) this page is
});

await runtime.initialize();

Migrating from an older version? AegisInAppManager, AegisWidgetManager, and AegisPlacementManager are no longer part of the public API — AegisMessageRuntime is the one supported entry point and renders all formats. The standalone "placement" system has been removed; inline content is now delivered as embedded cards (see below).

Campaign content, audience, schedule, and frequency caps are configured server-side in the dashboard (In-App Personalization). The SDK evaluates client-side triggers (scroll depth, time on page, exit intent, inactivity, custom events) and renders the matching campaign automatically.

Drive triggers & identity from your app

runtime.track('added_to_cart');         // fire event-based display triggers
runtime.notifyConversion('purchase');   // suppress a campaign after it converts
await runtime.updateContactId('contact_42'); // re-evaluate once the visitor signs in

Placement — how a campaign reaches the customer

Each campaign picks one or more delivery modes in the dashboard's Placement tab. They are not mutually exclusive:

Delivery modeWhat it isWhat you do on your site
Pop up (overlay)A modal / banner / etc. the SDK renders over the page at runtimeNothing — runtime.initialize() shows it when the trigger matches
Embedded cardThe campaign renders inline, inside a slot you place on the pageAdd an empty <div data-aegis-slot="…"> where you want it
Standalone pageThe campaign gets its own tokenized URL (great for SMS / email / QR)Link to the URL shown in the dashboard

Embedded cards (inline placement)

Drop an empty element wherever you want the card to appear. Its data-aegis-slot value must equal the campaign's category (widget_category in the dashboard). On load, the SDK fills the first eligible campaign for that category:

<!-- Renders the active "promo" campaign here, inline in your page -->
<div data-aegis-slot="promo"></div>

No per-slot script and no manual registration — runtime.initialize() scans for every [data-aegis-slot] element and fills it. It re-scans on each SSE/poll refresh and skips slots it has already filled.

Slot shells — reserve the box before the campaign arrives

An empty slot grows when its campaign lands, which pushes the page down (layout shift), and the hero image request waits for the campaign fetch. The SDK fixes both with a shell: a placeholder of the right size, drawn into each empty slot before it fetches, which the campaign then fills in place. A slot that nothing fills collapses as soon as the fetch answers, so a box never shows and then disappears later.

The SDK takes each slot's shell from the first of these that has one:

  1. Inline shapes your page prints (server-rendered pages): the shapes from GET /v1/in-app/slot-shapes (below), in a script tag. When this tag is present, a slot missing from it is treated as "will not fill".
    <script type="application/json" data-aegis-slot-shapes>{"shapes":[ … ]}</script>
    
  2. The slot's own attributes (any site, by hand):
    <div data-aegis-slot="hero" data-aegis-slot-aspect="8/3"></div>
    <div data-aegis-slot="commerce" data-aegis-slot-min-height="272"></div>
    
    data-aegis-slot-aspect takes w/h (or w:h). data-aegis-slot-min-height takes pixels or a CSS length (300, 20rem, 45vh).
  3. The last visit's shapes: after every fetch, the SDK saves the winning campaigns' shapes in localStorage. The key is the property plus the declared surface, screen and outlet (locationId), and saved shapes expire after 6 hours. If storage is blocked, this step is skipped.

Content you render yourself is left alone. If the slot already has children (a data-aegis-slot-default fallback, or your own <div data-aegis-slot-shell> child), the SDK draws nothing there. It replaces your shell with the campaign, or removes it when the slot will not fill, exactly as it does its own. The SDK never draws a shape marked may_be_empty from data (for example a buy-again rail for a first-time visitor). Only the slot's own attributes can reserve a box for one.

GET /v1/in-app/slot-shapes: for server renderers. It takes the same write-key headers as /v1/in-app/active (X-Aegis-Write-Key, optional X-User-ID / X-Contact-ID / X-Property-Id). The query parameters are property_id (used when the header is absent), surface, screen, page_url (path + search), location_id, device_type, geo and is_new_user. The response carries Cache-Control: private, max-age=60 and the body is {"shapes": [SlotShape, …]}, one shape per slot that will fill. A slot that is absent will not fill. Each campaign in /v1/in-app/active also carries its own slot_shape.

Hosts that print shells themselves. The ACS storefront renders them from display.inapp_slot_shapes. The Shopify theme app extension renders them from the shop metafield aegis.slot_shapes, which the cell keeps in sync (shopify-plugin/theme-app-extension/snippets/aegis-slot-shell.liquid). Both mark their shells data-aegis-slot-shell + data-aegis-shell-owner="host" and print the inline shapes, so the SDK adopts them as described above.

SlotShape:

FieldMeaning
slotThe slot key (data-aegis-slot value = the campaign's widget_category)
campaign_idThe winning campaign
layouthero, rail, grid (columns 2, or 1 for a list), bar (announcement bar / value bar) or card
aspectBox aspect w/h. For a hero this is the desktop aspect (8/3, ≥768px)
aspect_phoneHero only: the phone (<768px) aspect (chrome.aspect_ratio, or 1/1 when a slide has a phone image). Null means use min_height
min_height / max_heightPixels / a CSS length (a hero is capped at 70vh)
card_aspect, card_count, titleRails and grids: each card's image aspect, the number of cards, and the heading (null when absent)
may_be_emptyThe slot may stay empty for this viewer (a rail with nothing to show, or a winner that depends on who is looking: an A/B test or holdout in shapes computed for all anonymous visitors). Draw no box from data alone. Such a shape carries no image or sizes
rotate_countThe slot rotates through this many campaigns. The shape is the first one's
imageHero only: the first slide's image {src, src_phone, alt, aspect, aspect_phone, width, height}. Render it as <img fetchpriority="high"> so it is the page's LCP request

The hero draws slide 0 as <img fetchpriority="high" decoding="async" width height> and lazy-loads the other slides. Rail card images carry decoding="async" plus explicit width/height, and fade in once decoded.

Cart state — one store, fed the CEP-standard way

Every cart-reactive surface — the free-delivery progress card, the standalone progress bar, cart-value targeting rules, and cart-recovery widgets — reads ONE cart store. You feed it the same way you'd feed WebEngage/CleverTap: by firing the ecommerce events you already fire. The SDK derives the live cart from them; no separate cart call.

// 1) Wire the ecommerce tracker into the cart store, once at boot:
runtime.bindEcommerce(aegis.ecommerce);

// 2) Fire ecommerce events as the shopper shops — the cart is derived from these:
aegis.ecommerce.addToCart({ product_id: 'p1', name: 'Cap', price: 499, quantity: 1 });
aegis.ecommerce.cartViewed({ value: 998, currency: 'INR', products: [/* … */] }); // authoritative snapshot

Platform installs need no event wiring — the plugin does it for you. Carts are detected and fed into the same store automatically:

PlatformDetection methodSetup
Shopify/cart.js poll + cart:updated (plugin)Install the Shopify app
WooCommerceaegis_cart + WC Store API on cart events (plugin)Install the WP plugin
Magento 2localStorage['mage-cache-storage']Install the extension
Custom / headless / mobileFire aegis.ecommerce.* (above)runtime.bindEcommerce(...)

Escape hatch — a headless host that doesn't emit ecommerce events can push the cart directly; this writes the same one store:

runtime.setCartState({ total: 149.99, itemCount: 2, currency: 'INR' });

Plugin System

Extend the SDK with custom plugins:

import type { Plugin } from '@active-reach/web-sdk';

const myPlugin: Plugin = {
  name: 'my-plugin',
  version: '1.0.0',

  async init(config) { /* called on SDK init */ },

  async beforeEventCapture(event) {
    // Modify or enrich events before capture
    event.properties = { ...event.properties, enriched: true };
    return event;
  },

  async afterEventCapture(event) {
    // Post-capture logic (external forwarding, logging, etc.)
  },
};

aegis.use(myPlugin);

TypeScript Support

Full type definitions included. Extend for type-safe event tracking:

// types/aegis.d.ts
import '@active-reach/web-sdk';

declare module '@active-reach/web-sdk' {
  interface TrackEventProperties {
    'Purchase Completed': {
      order_id: string;
      revenue: number;
      currency: string;
    };
    'Product Viewed': {
      product_id: string;
      product_name: string;
      price: number;
    };
  }
}

Cookies & Storage

NameTypePurposeDuration
aegis_anon_idCookieAnonymous user identifier365 days
aegis_user_idCookieIdentified user ID365 days
aegis_session_idCookieCurrent session IDSession
aegis_session_timeCookieLast activity timestampSession
aegis_consentCookieConsent preferences365 days
aegis_offline_queuelocalStorageOffline event queuePersistent
aegis_active_celllocalStorageActive regional cell7 days

All cookies: SameSite=Lax, Secure (HTTPS only), domain-scoped (optional).


Content Security Policy (CSP)

If your site uses a Content Security Policy, add these directives:

script-src: 'self' https://platform.active-reach.ai;
connect-src: 'self' https://*.activereach.ai;
style-src: 'self' 'unsafe-inline';
img-src: 'self' https://*.activereach.ai data:;

If using DOMPurify via CDN, also add:

script-src: https://cdnjs.cloudflare.com;

Common error when CSP is missing: Refused to connect to 'https://...activereach.ai' — add the domain to connect-src.


Security

  • Write Key: Publishable client-side identifier. Cannot read data or modify server state. Safe to embed in source code.
  • HTML Sanitization: Uses DOMPurify when available with a strict allowlist. Falls back to text-only rendering.
  • URL Validation: All URLs validated — javascript: and data: protocols blocked.
  • Consent: Events are dropped (not queued) when consent is denied and wait_for_consent is enabled.
  • Transport: All API calls use HTTPS with bearer token authentication.

What NOT to track

Never pass sensitive data as event properties:

// Never do this
aegis.track('Login', { password: '...' });
aegis.identify('user_123', { ssn: '...', credit_card: '...' });

The SDK does not filter or redact properties. You are responsible for ensuring no PII beyond what you intend to collect is included in event payloads.


Debugging

aegis.debug(true);

// Or via init
aegis.init('KEY', { debug: true });

Console output:

[Aegis] Initializing SDK...
[Aegis] Event queued: track { button_name: 'Sign Up' }
[Aegis] Flushing 5 events
[Aegis] Batch sent successfully

Subpath Exports

Import PathDescription
@active-reach/web-sdkCore SDK (track, identify, page, group, alias)
@active-reach/web-sdk/reactReact Provider + hooks
@active-reach/web-sdk/pushWeb Push notification manager
@active-reach/web-sdk/cdnIIFE bundle for <script> tag (window.aegis)
@active-reach/web-sdk/snippetMinified async loader snippet
@active-reach/web-sdk/service-workerPush notification service worker

Browser Support

Chrome 80+, Firefox 78+, Safari 14+, Edge 80+.


License

MIT

版本与发布记录

@active-reach/web-sdk 共发布 84 个版本,首次发布于 2026/04/15;过去 12 个月发布了 84 个版本。

版本发布日期距今
1.48.0latest2026/10/2711 天前
1.47.32026/10/2315 天前
1.47.22026/10/2315 天前
1.47.12026/10/2216 天前
1.47.02026/10/2216 天前
1.46.32026/10/2216 天前

关于 @active-reach/web-sdk 的常见问题

@active-reach/web-sdk 是什么?

Web SDK for Active Reach Intelligence — event tracking, identity resolution, in-app messaging, web push, and placements

如何安装 @active-reach/web-sdk?

在项目目录运行 npm install @active-reach/web-sdk,或使用 pnpm add / yarn add / bun add。

@active-reach/web-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@active-reach/web-sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@active-reach/web-sdk 可以商用吗?

@active-reach/web-sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@active-reach/web-sdk 的下载量有多少?

根据 npm 官方下载统计,@active-reach/web-sdk 在 2026/10/05 – 2026/11/03 这 30 天内被下载 2,635 次,日均约 88 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@active-reach/web-sdk 还在维护吗?

最新版本 1.48.0 发布于 2026/10/27(11 天前);至今共发布 84 个版本,其中过去 12 个月发布了 84 个;首次发布于 2026/04/15。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。