@convex-internal/web-analytics

中文文档
2.3.0发布于 2026/11/07TypeScriptES Module近 30 天下载 1.1万

Shared consent state, consent banner, and analytics setup for Convex websites.

原始使用文档
文档目录13 节
  1. Core
  2. capture
  3. getDistinctId
  4. Consent banner
  5. Consent events
  6. Cookie behavior
  7. React
  8. Consented
  9. useConsent
  10. Svelte
  11. Test in-development changes
  12. Publish a version to npm
  13. Consume a published version

@convex-internal/web-analytics

Shared consent state, consent banner, and analytics setup for Convex websites.

Core

Mount a framework entry at the root (React or Svelte). Analytics start in production, except on localhost. Consent is synced to PostHog. The banner shows when the visitor has not chosen yet.

PostHog already copies standard campaign params (UTMs, gclid, rdt_cid, fbclid, and other common click IDs) from the landing URL onto events. This package also captures dub_id. After consent, PostHog creates an anonymous person profile. Campaign params still available at that point can be stored as $initial_*, supporting person-level attribution before login.

capture

Record an event from client code through the framework-neutral root entry. The optional third argument is PostHog's capture options.

import { capture } from "@convex-internal/web-analytics";

capture("www-login", undefined, {
  transport: "sendBeacon",
  send_instantly: true,
});

getDistinctId

PostHog's identifier for the current visitor. After consent is granted it is stored in a cookie on .convex.dev, so every Convex site in the browser uses the same ID.

When this helper returns a value, consent has been granted. Pass that ID to a third-party tool so you can match that tool's events or sessions, such as a support chat, back to the same visitor in PostHog.

It's expected that a call on first load is always undefined, so call again after consent is granted.

It returns one of:

  • undefined. PostHog is not initialized (localhost, non-production, or still loading), or consent has not been granted. Before consent, PostHog still has a cookieless ID, but it is not stable across sites or even page reloads, so returning it would create noise rather than being useful.
  • Anonymous UUID, such as "019a7d8f-9190-7844-a5c0-73d461a3a5d1". Consent has been granted but this browser has not logged into the dashboard where the user is identified.
  • Convex profile ID, such as "4281". Consent has been granted and this browser has logged into the dashboard.

The banner is visible when consent is "undecided". It is hidden while consent is "unknown", "consented", or "declined".

React and Svelte accept an optional hideBanner prop, defaulting to false.

Theme with --wa-banner-* variables on .wa-banner:

.wa-banner {
  --wa-banner-background-color: var(--color-seashell);
  --wa-banner-font-family: var(--font-primary);
  --wa-banner-accept-background-color: var(--color-plum-p4);
}
  • Background, text, and border: --wa-banner-background-color, --wa-banner-text-color, --wa-banner-border-color, --wa-banner-border-radius, --wa-banner-box-shadow, --wa-banner-backdrop-filter
  • Type and layout: --wa-banner-font-family, --wa-banner-font-size, --wa-banner-padding, --wa-banner-max-width, --wa-banner-action-gap, --wa-banner-z-index
  • Link and focus: --wa-banner-link-color, --wa-banner-focus-color
  • Buttons: --wa-banner-button-border-radius, --wa-banner-button-padding, --wa-banner-button-min-height, --wa-banner-button-font-size, --wa-banner-button-font-weight
  • Accept button: --wa-banner-accept-background-color, --wa-banner-accept-text-color
  • Decline button: --wa-banner-decline-background-color, --wa-banner-decline-text-color

Buttons default to 80% opacity and go to 100% on hover or keyboard focus.

cookie_consent_shown is recorded when the banner appears. cookie_consent_decided is recorded with { decision: "accepted" | "declined", source: "banner" } just before the choice is saved, and with { decision: "declined", source: "gpc" } when the GPC preference is applied. Historic events without source are banner decisions.

Once the cookie has been read, consent is resolved in this order:

  1. Global Privacy Control. If navigator.globalPrivacyControl === true, consent is "declined". GPC is not stored: the cookie is not written or changed. Turn GPC off and the stored cookie (if set) applies again.
  2. Cookie. true is "consented", false is "declined", and a missing or unrecognized value is "undecided".

The cookie is stored with path=/ and a max-age of one year. On convex.dev and *.convex.dev it is also set with domain=.convex.dev so the website, Docs, Stack, and other subdomains share one choice. The cookie is marked Secure everywhere except localhost.

Changes made through setConsent update immediately. Changes made elsewhere, such as in another tab or DevTools, are synchronized through cookie change events when available, and when the window regains focus or its visibility changes as a fallback.

React

Import from @convex-internal/web-analytics/react. WebAnalyticsProvider is a client component. useConsent throws if called outside that provider.

import { WebAnalyticsProvider } from "@convex-internal/web-analytics/react";

<WebAnalyticsProvider>{children}</WebAnalyticsProvider>;

For example, hide the banner on /start and /login redirect pages in Next.js:

"use client";

import { WebAnalyticsProvider } from "@convex-internal/web-analytics/react";
import { usePathname } from "next/navigation";
import type { ReactNode } from "react";

export function Analytics({ children }: { children: ReactNode }) {
  const pathname = usePathname();

  return (
    <WebAnalyticsProvider hideBanner={["/start", "/login"].includes(pathname)}>
      {children}
    </WebAnalyticsProvider>
  );
}

Consented

Renders children only when consent is "consented". It renders nothing during SSR, while consent is still "unknown" or "undecided", if the visitor declined, or while Global Privacy Control is on.

import { Consented } from "@convex-internal/web-analytics/react";

<Consented>
  <YourAnalyticsScripts />
</Consented>;

useConsent

  • consent (ConsentStatus)
    • "unknown" until cookie has been read (SSR and first client render)
    • "undecided" after that if there is no recognized choice yet
    • "consented" if the cookie is true and GPC is not set
    • "declined" if the cookie is false or GPC is set
  • setConsent("consented" | "declined")
    • Saves the choice to the allowsCookies cookie and updates context
    • Do not write the cookie yourself

Use the hook when you need consent or setConsent directly. Enable tracking only when consent === "consented".

Svelte

The Svelte entry exports only WebAnalytics. Render it once in the root layout. It starts PostHog and shows the banner. There is no Consented wrapper or consent store. Those can be added later; nothing using the Svelte entry has needed them yet.

<script>
  import { WebAnalytics } from "@convex-internal/web-analytics/svelte";
</script>

<WebAnalytics />

Test in-development changes

  1. In the web-analytics repo, build and pack the package:
cd /path/to/web-analytics
npm run build
npm pack

This creates a tarball such as convex-internal-web-analytics-1.0.0.tgz.

  1. Install that tarball in the consuming app:
cd /path/to/consuming-app
npm install /path/to/web-analytics/convex-internal-web-analytics-1.0.0.tgz --force

--force ensures npm refreshes the package when the filename and version have not changed.

Publish a version to npm

  1. Confirm that you are signed in to the npm account with access to the @convex-internal organization:
npm whoami

Run npm login first if needed.

  1. Commit any README or code changes, then bump the version. npm version requires a clean Git worktree and creates a version commit and tag.
npm version major   # breaking, or 0.x → 1.0.0
npm version minor   # new backwards-compatible functionality
npm version patch   # bug fixes
  1. Run tests, inspect the package contents, then publish. .npmrc sets ignore-scripts=true, so prepack will not run — build first:
npm test
npm run build
npm pack --dry-run
npm publish

Consume a published version

Convex repos typically set min-release-age=7 in .npmrc, so a version published in the last 7 days will fail to install. Override the window for that one install:

npm install @convex-internal/web-analytics@<version> --min-release-age=0

Use the local tarball workflow whenever you need to test changes that have not been published yet.

版本与发布记录

@convex-internal/web-analytics 共发布 13 个版本,首次发布于 2026/08/19;过去 12 个月发布了 13 个版本。

版本发布日期距今
2.3.0latest2026/11/073 天前
2.2.22026/09/042 个月前
2.2.12026/09/042 个月前
2.2.02026/08/272 个月前
2.1.02026/08/262 个月前
2.0.12026/08/222 个月前

关于 @convex-internal/web-analytics 的常见问题

@convex-internal/web-analytics 是什么?

Shared consent state, consent banner, and analytics setup for Convex websites.

如何安装 @convex-internal/web-analytics?

在项目目录运行 npm install @convex-internal/web-analytics,或使用 pnpm add / yarn add / bun add。

@convex-internal/web-analytics 支持 TypeScript 吗?

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

@convex-internal/web-analytics 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@convex-internal/web-analytics 可以商用吗?

@convex-internal/web-analytics 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@convex-internal/web-analytics 的下载量有多少?

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

@convex-internal/web-analytics 还在维护吗?

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