Color mode

Analytics

Storage-independent analytics primitives and browser page-view tracking for Riebeckite. It contains no Cloudflare, Worker, database, or vendor code.

日本語

Design

  • AnalyticsEvent includes a typed page_view event and can be extended with provider-specific event unions.
  • AnalyticsProvider declares discoverable capabilities and exposes capture and query. Queries cover per-content page views and popular content, with optional ISO-8601 time ranges.
  • UnsupportedAnalyticsQueryError makes unsupported query capabilities explicit. MemoryAnalyticsProvider is included for tests and local examples.
  • Provider runtime configuration (credentials, storage, bindings) stays inside the provider. The browser receives only AnalyticsPublicConfig.

Usage

ts
import { analytics, MemoryAnalyticsProvider } from "@riebeckite/plugin-analytics";
 
const provider = new MemoryAnalyticsProvider();
 
export default {
  plugins: [
    analytics({
      provider,
      publicConfig: { collectorUrl: "/analytics/events" },
    }),
  ],
};

collectorUrl is intentionally public. It is a relative path or an HTTP(S) URL for a collector that accepts a JSON POST body. A future provider package can expose a collector backed by its own private runtime configuration.

Browser behavior

For every published content entry with Core's source-authored stable id, the plugin places a small content-ID marker in rendered HTML and registers initAnalytics with the generic public-config client mechanism.

In a browser, the initializer sends exactly one event per document:

json
{
  "type": "page_view",
  "contentId": "guide-1",
  "occurredAt": "2026-01-01T00:00:00.000Z",
  "path": "/guide",
  "lang": "en"
}

path and lang are contextual metadata, not identity. Content without a stable ID is not tracked. The initializer is a no-op during builds/SSR and is idempotent in a document. Riebeckite's current static document navigation needs no SPA route hooks; SPA navigation is not tracked automatically.

Content IDs are an authoring responsibility. Duplicate id declarations across published notes are reported by @riebeckite/plugin-diagnostics (duplicate-content-id / invalid-content-id) and validated by the plugin's own validateAnalyticsOptions at check time.

Provider contract

ts
const result = await provider.query({
  type: "popular_content",
  limit: 10,
  timeRange: { from: "2026-01-01T00:00:00.000Z" },
});

Capabilities are capture, content_page_views, and popular_content. Call assertAnalyticsQuerySupported(provider, query) when implementing a provider that may not support all queries.

Diagnostics

@riebeckite/plugin-diagnostics reports an analytics-untracked finding for published content without a stable content ID when the site enables this plugin, so tracking gaps are visible in check, doctor, and build diagnostics.

Exports

  • analytics() / analyticsPlugin()
  • initAnalytics (@riebeckite/plugin-analytics/client)
  • MemoryAnalyticsProvider
  • Event, query/result, provider/capability, and public-config types
  • UnsupportedAnalyticsQueryError and capability helpers

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/analytics/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Analytics
4 +
5 + Storage-independent analytics primitives and browser page-view tracking for
6 + Riebeckite. It contains no Cloudflare, Worker, database, or vendor code.
7 +
8 + [日本語](./analytics.md)
9 +
10 + ## Design
11 +
12 + - `AnalyticsEvent` includes a typed `page_view` event and can be extended with
13 + provider-specific event unions.
14 + - `AnalyticsProvider` declares discoverable capabilities and exposes `capture`
15 + and `query`. Queries cover per-content page views and popular content, with
16 + optional ISO-8601 time ranges.
17 + - `UnsupportedAnalyticsQueryError` makes unsupported query capabilities
18 + explicit. `MemoryAnalyticsProvider` is included for tests and local examples.
19 + - Provider runtime configuration (credentials, storage, bindings) stays inside
20 + the provider. The browser receives only `AnalyticsPublicConfig`.
21 +
22 + ## Usage
23 +
24 + ```ts
25 + import { analytics, MemoryAnalyticsProvider } from "@riebeckite/plugin-analytics";
26 +
27 + const provider = new MemoryAnalyticsProvider();
28 +
29 + export default {
30 + plugins: [
31 + analytics({
32 + provider,
33 + publicConfig: { collectorUrl: "/analytics/events" },
34 + }),
35 + ],
36 + };
37 + ```
38 +
39 + `collectorUrl` is intentionally public. It is a relative path or an HTTP(S)
40 + URL for a collector that accepts a JSON `POST` body. A future provider package
41 + can expose a collector backed by its own private runtime configuration.
42 +
43 + ## Browser behavior
44 +
45 + For every published content entry with Core's source-authored stable `id`, the
46 + plugin places a small content-ID marker in rendered HTML and registers
47 + `initAnalytics` with the generic public-config client mechanism.
48 +
49 + In a browser, the initializer sends exactly one event per document:
50 +
51 + ```json
52 + {
53 + "type": "page_view",
54 + "contentId": "guide-1",
55 + "occurredAt": "2026-01-01T00:00:00.000Z",
56 + "path": "/guide",
57 + "lang": "en"
58 + }
59 + ```
60 +
61 + `path` and `lang` are contextual metadata, not identity. Content without a
62 + stable ID is not tracked. The initializer is a no-op during builds/SSR and is
63 + idempotent in a document. Riebeckite's current static document navigation needs
64 + no SPA route hooks; SPA navigation is not tracked automatically.
65 +
66 + Content IDs are an authoring responsibility. Duplicate `id` declarations across
67 + published notes are reported by
68 + [`@riebeckite/plugin-diagnostics`](./diagnostics.en.md)
69 + (`duplicate-content-id` / `invalid-content-id`) and validated by the plugin's own
70 + `validateAnalyticsOptions` at `check` time.
71 +
72 + ## Provider contract
73 +
74 + ```ts
75 + const result = await provider.query({
76 + type: "popular_content",
77 + limit: 10,
78 + timeRange: { from: "2026-01-01T00:00:00.000Z" },
79 + });
80 + ```
81 +
82 + Capabilities are `capture`, `content_page_views`, and `popular_content`. Call
83 + `assertAnalyticsQuerySupported(provider, query)` when implementing a provider
84 + that may not support all queries.
85 +
86 + ## Diagnostics
87 +
88 + `@riebeckite/plugin-diagnostics` reports an `analytics-untracked` finding for
89 + published content without a stable content ID when the site enables this
90 + plugin, so tracking gaps are visible in `check`, `doctor`, and build
91 + diagnostics.
92 +
93 + ## Exports
94 +
95 + - `analytics()` / `analyticsPlugin()`
96 + - `initAnalytics` (`@riebeckite/plugin-analytics/client`)
97 + - `MemoryAnalyticsProvider`
98 + - Event, query/result, provider/capability, and public-config types
99 + - `UnsupportedAnalyticsQueryError` and capability helpers
100 +
101 + ## See also
102 +
103 + - [Plugin guide](../reference/plugin-api.en.md)
104 +