@liiift-studio/sanity-visitor-insights 0.11.0 → 0.13.0
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 +62 -0
- package/dist/index.d.mts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +372 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +373 -42
- package/dist/index.mjs.map +1 -1
- package/dist/{ranges-YGStz1nR.d.mts → ranges-CiTnQEnz.d.mts} +158 -1
- package/dist/{ranges-YGStz1nR.d.ts → ranges-CiTnQEnz.d.ts} +158 -1
- package/dist/server.d.mts +6 -4
- package/dist/server.d.ts +6 -4
- package/dist/server.js +377 -84
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +374 -83
- package/dist/server.mjs.map +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{vercel-C597eCC_.d.mts → vercel-CwILuQVm.d.mts} +14 -1
- package/dist/{vercel-C597eCC_.d.ts → vercel-CwILuQVm.d.ts} +14 -1
- package/package.json +1 -1
- package/src/core/core.test.ts +98 -0
- package/src/core/ranges.ts +59 -0
- package/src/core/siteConfig.ts +79 -0
- package/src/reportData.ts +57 -0
- package/src/server/createHandler.ts +65 -6
- package/src/server/diagnostics.ts +22 -5
- package/src/server/ga4.ts +71 -8
- package/src/server/orders.ts +233 -47
- package/src/server/reports/acquisition.ts +54 -10
- package/src/server/reports/journey.ts +94 -10
- package/src/server/reports/measurementHealth.ts +55 -26
- package/src/server/reports/reports.test.ts +318 -9
- package/src/server/reports/typefaceInterest.ts +58 -12
- package/src/studio/Figure.tsx +316 -13
- package/src/studio/VisitorInsightsTool.tsx +29 -8
- package/src/studio/panels.test.tsx +109 -10
- package/src/studio/panels.tsx +171 -8
- package/src/studio/useReport.ts +11 -6
- package/src/types.ts +10 -0
package/README.md
CHANGED
|
@@ -184,6 +184,7 @@ empty charts — pasting a measurement id here is caught by name.
|
|
|
184
184
|
|
|
185
185
|
| Variable | Where | What |
|
|
186
186
|
|---|---|---|
|
|
187
|
+
| `VISITOR_INSIGHTS_ENABLED` | Site (server) | **Required.** Any truthy value switches the route on |
|
|
187
188
|
| `VISITOR_INSIGHTS_GA4_SERVICE_ACCOUNT` | Site (server) | Service-account JSON, raw or base64 |
|
|
188
189
|
| `VISITOR_INSIGHTS_VERCEL_TOKEN` | Site (server) | Vercel API token with project read access |
|
|
189
190
|
| `SANITY_STUDIO_PROJECT_ID` | Site (server) | Already set; used to verify Studio tokens |
|
|
@@ -191,6 +192,67 @@ empty charts — pasting a measurement id here is caught by name.
|
|
|
191
192
|
The service account needs **Viewer** on each GA4 property. Nothing here is `NEXT_PUBLIC_`; none of
|
|
192
193
|
it reaches the browser.
|
|
193
194
|
|
|
195
|
+
#### Scoping to your own hostnames
|
|
196
|
+
|
|
197
|
+
`ga4.hostnames` restricts every GA4 report to the hosts you name. A GA4 property is not necessarily
|
|
198
|
+
one website — Darden's also receives `impactsport.ca`, an unrelated business, which was inside the
|
|
199
|
+
headline session count, both percentages computed from it, and the funnel's entry rung. Omit the
|
|
200
|
+
field to accept every hostname, which is the old behaviour.
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
ga4: {
|
|
204
|
+
propertyId: '123456789',
|
|
205
|
+
timezone: 'America/Los_Angeles',
|
|
206
|
+
hostnames: ['www.dardenstudio.com', 'dardenstudio.com'],
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### Orders: status and revenue
|
|
211
|
+
|
|
212
|
+
`orders.countedStatuses` names the statuses that count as a real sale; everything else is excluded
|
|
213
|
+
and reported separately. Leave it unset and test, failed, pending and refunded orders all count as
|
|
214
|
+
sales — at seven orders a quarter, one test order is a 14% error. The status breakdown is always
|
|
215
|
+
reported so you can see what vocabulary your own orders use before configuring this.
|
|
216
|
+
|
|
217
|
+
`orders.totalField` turns on revenue. Without it a $30 web licence and a $400 multi-seat desktop
|
|
218
|
+
licence are the same integer, so nothing can be ranked by what it is worth. An order total is not a
|
|
219
|
+
customer field; the PII projection allow-list is unchanged.
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
orders: {
|
|
223
|
+
documentType: 'order',
|
|
224
|
+
typefacesField: 'typefaces',
|
|
225
|
+
statusField: 'orderStatus',
|
|
226
|
+
countedStatuses: ['complete', 'paid'],
|
|
227
|
+
totalField: 'total',
|
|
228
|
+
currency: 'USD',
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### Conversions that are not a sale
|
|
233
|
+
|
|
234
|
+
`eventNames.enquiry`, `.subscribe` and `.assetDownload` surface outcomes the funnel used to score as
|
|
235
|
+
drop-offs. A custom commission is worth many multiples of a licence, and the funnel ended at
|
|
236
|
+
`purchase` — so the visitor who read three typeface pages and emailed was counted as a leak.
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
eventNames: {
|
|
240
|
+
enquiry: ['enquiry_submit'],
|
|
241
|
+
subscribe: ['subscribe'],
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### The master switch
|
|
246
|
+
|
|
247
|
+
`VISITOR_INSIGHTS_ENABLED` is an explicit opt-in. Unset, the route answers `503` with
|
|
248
|
+
`disabled: true` and does no Sanity or GA4 work, and the Studio tool shows a neutral "Switched off"
|
|
249
|
+
card rather than an error. Set it to anything that is not `false`, `0`, `off`, `no`, `disabled` or
|
|
250
|
+
empty — a word, a code, `true`, whatever the site's operator prefers.
|
|
251
|
+
|
|
252
|
+
This is deliberately the opposite default to `SALES_PORTAL_ENABLED`, which is on unless the value
|
|
253
|
+
is literally `"false"`. Mounting this route wires up analytics credentials, so it should not begin
|
|
254
|
+
answering on a site where nobody chose to switch it on.
|
|
255
|
+
|
|
194
256
|
---
|
|
195
257
|
|
|
196
258
|
## Before it will show anything useful
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-CiTnQEnz.mjs';
|
|
4
|
+
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-CiTnQEnz.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The Visitor Insights Studio tool.
|
|
@@ -54,6 +54,7 @@ type ReportState<T> = {
|
|
|
54
54
|
} | {
|
|
55
55
|
status: 'error';
|
|
56
56
|
message: string;
|
|
57
|
+
disabled?: boolean;
|
|
57
58
|
};
|
|
58
59
|
/** Options for useReport. */
|
|
59
60
|
interface UseReportOptions {
|
|
@@ -92,7 +93,6 @@ declare function useReport<T>({ apiBaseUrl, report, range, custom }: UseReportOp
|
|
|
92
93
|
declare function formatCount(value: number): string;
|
|
93
94
|
/** Format a 0–1 ratio as a percentage. */
|
|
94
95
|
declare function formatPercent(ratio: number, digits?: number): string;
|
|
95
|
-
/** Props for MetricFigure. */
|
|
96
96
|
interface MetricFigureProps {
|
|
97
97
|
metric: MetricValue;
|
|
98
98
|
/** Accessible label describing what this number counts. */
|
|
@@ -167,8 +167,9 @@ declare function MeasurementHealthPanel({ data }: {
|
|
|
167
167
|
data: MeasurementHealthData;
|
|
168
168
|
}): React.ReactElement;
|
|
169
169
|
/** Acquisition — where visitors came from, with design-industry referrers called out. */
|
|
170
|
-
declare function AcquisitionPanel({ data }: {
|
|
170
|
+
declare function AcquisitionPanel({ data, previous }: {
|
|
171
171
|
data: AcquisitionData;
|
|
172
|
+
previous?: AcquisitionData;
|
|
172
173
|
}): React.ReactElement;
|
|
173
174
|
/** Journey — a funnel, drawn as a tracked sequence or as independent totals, whichever the report used. */
|
|
174
175
|
declare function JourneyPanel({ data }: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-
|
|
4
|
-
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-
|
|
3
|
+
import { R as ReportEnvelope, a as ReportName, b as RangeKey, M as MetricValue, A as AcquisitionData, D as DiagnosticReport, J as JourneyData, c as MeasurementHealthData, T as TypefaceInterestData } from './ranges-CiTnQEnz.js';
|
|
4
|
+
export { C as Coverage, d as DateRange, E as EventCutover, P as PREEXISTING, e as REPORT_NAMES, f as ReportError, S as SiteAnalyticsConfig, g as SourceName, h as SourceStatus, U as UnavailableReason, i as coverageForRange, j as isReportName, o as ok, p as partial, k as previousRange, r as resolveRange, u as unavailable, v as validateSiteConfig, l as valueOrNull } from './ranges-CiTnQEnz.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The Visitor Insights Studio tool.
|
|
@@ -54,6 +54,7 @@ type ReportState<T> = {
|
|
|
54
54
|
} | {
|
|
55
55
|
status: 'error';
|
|
56
56
|
message: string;
|
|
57
|
+
disabled?: boolean;
|
|
57
58
|
};
|
|
58
59
|
/** Options for useReport. */
|
|
59
60
|
interface UseReportOptions {
|
|
@@ -92,7 +93,6 @@ declare function useReport<T>({ apiBaseUrl, report, range, custom }: UseReportOp
|
|
|
92
93
|
declare function formatCount(value: number): string;
|
|
93
94
|
/** Format a 0–1 ratio as a percentage. */
|
|
94
95
|
declare function formatPercent(ratio: number, digits?: number): string;
|
|
95
|
-
/** Props for MetricFigure. */
|
|
96
96
|
interface MetricFigureProps {
|
|
97
97
|
metric: MetricValue;
|
|
98
98
|
/** Accessible label describing what this number counts. */
|
|
@@ -167,8 +167,9 @@ declare function MeasurementHealthPanel({ data }: {
|
|
|
167
167
|
data: MeasurementHealthData;
|
|
168
168
|
}): React.ReactElement;
|
|
169
169
|
/** Acquisition — where visitors came from, with design-industry referrers called out. */
|
|
170
|
-
declare function AcquisitionPanel({ data }: {
|
|
170
|
+
declare function AcquisitionPanel({ data, previous }: {
|
|
171
171
|
data: AcquisitionData;
|
|
172
|
+
previous?: AcquisitionData;
|
|
172
173
|
}): React.ReactElement;
|
|
173
174
|
/** Journey — a funnel, drawn as a tracked sequence or as independent totals, whichever the report used. */
|
|
174
175
|
declare function JourneyPanel({ data }: {
|