@proveanything/smartlinks 1.8.0 → 1.8.1
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/dist/api/analytics.d.ts +3 -3
- package/dist/api/analytics.js +48 -11
- package/dist/docs/API_SUMMARY.md +10 -8
- package/dist/docs/analytics-metadata-conventions.md +18 -14
- package/dist/docs/analytics.md +14 -17
- package/dist/openapi.yaml +5 -5
- package/dist/types/analytics.d.ts +10 -9
- package/docs/API_SUMMARY.md +10 -8
- package/docs/analytics-metadata-conventions.md +18 -14
- package/docs/analytics.md +14 -17
- package/openapi.yaml +5 -5
- package/package.json +1 -1
package/dist/api/analytics.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AnalyticsTrackOptions, AnalyticsTrackResult, AnalyticsBrowserConfig, AnalyticsGeolocationCaptureOptions, AnalyticsLinkClickInput, AnalyticsLinkBindingOptions, AnalyticsPageViewBindingOptions, AnalyticsClassicReportRequest, AnalyticsVisitorIdOptions, CollectionAnalyticsEvent, TagAnalyticsEvent, AnalyticsSummaryRequest, AnalyticsSummaryResponse, AnalyticsTimeseriesRequest, AnalyticsTimeseriesResponse, AnalyticsBreakdownRequest, AnalyticsBreakdownResponse, AnalyticsEventsRequest, AnalyticsEventsResponse, LegacyAnalyticsRequest, AnalyticsDashboardResponse, AnalyticsProductsResponse, AnalyticsQrCodesResponse, AnalyticsTagsResponse, AnalyticsWeeklyRequest, AnalyticsCountryRequest } from "../types/analytics";
|
|
2
|
-
export type { AnalyticsTrackOptions, AnalyticsTrackResult, AnalyticsBrowserConfig, AnalyticsGeolocationCaptureOptions, AnalyticsLinkClickInput, AnalyticsLinkBindingOptions, AnalyticsPageViewBindingOptions, AnalyticsClassicReportRequest, AnalyticsVisitorIdOptions, CollectionAnalyticsEvent, TagAnalyticsEvent, AnalyticsSummaryRequest, AnalyticsSummaryResponse, AnalyticsTimeseriesRequest, AnalyticsTimeseriesResponse, AnalyticsBreakdownRequest, AnalyticsBreakdownResponse, AnalyticsEventsRequest, AnalyticsEventsResponse, LegacyAnalyticsRequest, AnalyticsDashboardResponse, AnalyticsProductsResponse, AnalyticsQrCodesResponse, AnalyticsTagsResponse, AnalyticsWeeklyRequest, AnalyticsCountryRequest, };
|
|
1
|
+
import type { AnalyticsTrackOptions, AnalyticsTrackResult, AnalyticsBrowserConfig, AnalyticsGeolocationCaptureOptions, AnalyticsLinkClickInput, AnalyticsLinkBindingOptions, AnalyticsPageViewBindingOptions, AnalyticsClassicReportRequest, AnalyticsVisitorIdOptions, AnalyticsSessionId, CollectionAnalyticsEvent, TagAnalyticsEvent, AnalyticsSummaryRequest, AnalyticsSummaryResponse, AnalyticsTimeseriesRequest, AnalyticsTimeseriesResponse, AnalyticsBreakdownRequest, AnalyticsBreakdownResponse, AnalyticsEventsRequest, AnalyticsEventsResponse, LegacyAnalyticsRequest, AnalyticsDashboardResponse, AnalyticsProductsResponse, AnalyticsQrCodesResponse, AnalyticsTagsResponse, AnalyticsWeeklyRequest, AnalyticsCountryRequest } from "../types/analytics";
|
|
2
|
+
export type { AnalyticsTrackOptions, AnalyticsTrackResult, AnalyticsBrowserConfig, AnalyticsGeolocationCaptureOptions, AnalyticsLinkClickInput, AnalyticsLinkBindingOptions, AnalyticsPageViewBindingOptions, AnalyticsClassicReportRequest, AnalyticsVisitorIdOptions, AnalyticsSessionId, CollectionAnalyticsEvent, TagAnalyticsEvent, AnalyticsSummaryRequest, AnalyticsSummaryResponse, AnalyticsTimeseriesRequest, AnalyticsTimeseriesResponse, AnalyticsBreakdownRequest, AnalyticsBreakdownResponse, AnalyticsEventsRequest, AnalyticsEventsResponse, LegacyAnalyticsRequest, AnalyticsDashboardResponse, AnalyticsProductsResponse, AnalyticsQrCodesResponse, AnalyticsTagsResponse, AnalyticsWeeklyRequest, AnalyticsCountryRequest, };
|
|
3
3
|
export declare namespace analytics {
|
|
4
4
|
namespace collection {
|
|
5
5
|
/**
|
|
@@ -17,7 +17,7 @@ export declare namespace analytics {
|
|
|
17
17
|
}
|
|
18
18
|
namespace browser {
|
|
19
19
|
function configure(config: AnalyticsBrowserConfig): void;
|
|
20
|
-
function getSessionId():
|
|
20
|
+
function getSessionId(): AnalyticsSessionId | undefined;
|
|
21
21
|
function getVisitorId(): string | undefined;
|
|
22
22
|
function setVisitorId(visitorId: string, options?: AnalyticsVisitorIdOptions): string;
|
|
23
23
|
function clearVisitorId(options?: Pick<AnalyticsVisitorIdOptions, 'storage' | 'storageKey'>): void;
|
package/dist/api/analytics.js
CHANGED
|
@@ -39,8 +39,15 @@ const defaultCampaignParamMap = {
|
|
|
39
39
|
qrCodeId: 'qrCodeId',
|
|
40
40
|
scanMethod: ['scanMethod', 'scan_method'],
|
|
41
41
|
};
|
|
42
|
+
const promotedAnalyticsKeys = new Set([
|
|
43
|
+
'visitorId',
|
|
44
|
+
'referrerHost',
|
|
45
|
+
'pageId',
|
|
46
|
+
'entryType',
|
|
47
|
+
'scanMethod',
|
|
48
|
+
]);
|
|
42
49
|
function createSessionId() {
|
|
43
|
-
return
|
|
50
|
+
return Date.now() * 1000 + Math.floor(Math.random() * 1000);
|
|
44
51
|
}
|
|
45
52
|
function createVisitorId() {
|
|
46
53
|
return `visitor_${Date.now()}_${Math.floor(Math.random() * 1000000)}`;
|
|
@@ -56,6 +63,33 @@ function getStorage(mode) {
|
|
|
56
63
|
}
|
|
57
64
|
return undefined;
|
|
58
65
|
}
|
|
66
|
+
function parseStoredSessionId(value) {
|
|
67
|
+
if (/^\d+$/.test(value)) {
|
|
68
|
+
const parsed = Number(value);
|
|
69
|
+
if (Number.isSafeInteger(parsed))
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
function assertValidSessionId(sessionId) {
|
|
75
|
+
if (sessionId === undefined || sessionId === null)
|
|
76
|
+
return undefined;
|
|
77
|
+
if (typeof sessionId !== 'number' || !Number.isSafeInteger(sessionId)) {
|
|
78
|
+
throw new Error('analytics sessionId must be a safe integer number.');
|
|
79
|
+
}
|
|
80
|
+
return sessionId;
|
|
81
|
+
}
|
|
82
|
+
function prunePromotedMetadataKeys(metadata) {
|
|
83
|
+
if (!metadata)
|
|
84
|
+
return undefined;
|
|
85
|
+
const entries = Object.entries(metadata).filter(([key]) => !promotedAnalyticsKeys.has(key));
|
|
86
|
+
if (entries.length === 0)
|
|
87
|
+
return undefined;
|
|
88
|
+
return Object.fromEntries(entries);
|
|
89
|
+
}
|
|
90
|
+
function normalizeAnalyticsEvent(event) {
|
|
91
|
+
return Object.assign(Object.assign({}, event), { sessionId: assertValidSessionId(event.sessionId), metadata: prunePromotedMetadataKeys(event.metadata) });
|
|
92
|
+
}
|
|
59
93
|
function getOrCreateSessionId() {
|
|
60
94
|
var _a, _b, _c, _d;
|
|
61
95
|
if (analyticsBrowserState.sessionId)
|
|
@@ -64,14 +98,17 @@ function getOrCreateSessionId() {
|
|
|
64
98
|
const storage = getStorage('session');
|
|
65
99
|
const existing = key ? storage === null || storage === void 0 ? void 0 : storage.getItem(key) : undefined;
|
|
66
100
|
if (existing) {
|
|
67
|
-
|
|
68
|
-
|
|
101
|
+
const parsed = parseStoredSessionId(existing);
|
|
102
|
+
if (parsed !== undefined) {
|
|
103
|
+
analyticsBrowserState.sessionId = parsed;
|
|
104
|
+
return parsed;
|
|
105
|
+
}
|
|
69
106
|
}
|
|
70
|
-
const generated = (_d = (_c = (_b = analyticsBrowserState.config).sessionIdFactory) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : createSessionId();
|
|
107
|
+
const generated = assertValidSessionId((_d = (_c = (_b = analyticsBrowserState.config).sessionIdFactory) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : createSessionId());
|
|
71
108
|
analyticsBrowserState.sessionId = generated;
|
|
72
109
|
if (key) {
|
|
73
110
|
try {
|
|
74
|
-
storage === null || storage === void 0 ? void 0 : storage.setItem(key, generated);
|
|
111
|
+
storage === null || storage === void 0 ? void 0 : storage.setItem(key, String(generated));
|
|
75
112
|
}
|
|
76
113
|
catch (_e) {
|
|
77
114
|
}
|
|
@@ -201,21 +238,21 @@ function getResolvedLocation() {
|
|
|
201
238
|
return undefined;
|
|
202
239
|
}
|
|
203
240
|
function mergeCollectionEventDefaults(event) {
|
|
204
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
241
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
205
242
|
const configuredDefaults = (_a = analyticsBrowserState.config.defaultCollectionEvent) !== null && _a !== void 0 ? _a : {};
|
|
206
243
|
const dynamicDefaults = (_d = (_c = (_b = analyticsBrowserState.config).getCollectionDefaults) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : {};
|
|
207
244
|
const campaignFields = analyticsBrowserState.config.autoCaptureCampaignParams === false ? {} : getCampaignFields();
|
|
208
245
|
const path = (_e = event.path) !== null && _e !== void 0 ? _e : getCurrentPath();
|
|
209
246
|
const visitorId = (_f = event.visitorId) !== null && _f !== void 0 ? _f : getOrCreateVisitorId();
|
|
210
247
|
const href = (_h = (_g = event.href) !== null && _g !== void 0 ? _g : dynamicDefaults.href) !== null && _h !== void 0 ? _h : configuredDefaults.href;
|
|
211
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, configuredDefaults), dynamicDefaults), campaignFields), getCurrentReferrerFields()), { visitorId, sessionId: getOrCreateSessionId(), deviceType: detectDeviceType(), path, pagePath: (
|
|
248
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, configuredDefaults), dynamicDefaults), campaignFields), getCurrentReferrerFields()), { visitorId, sessionId: assertValidSessionId((_j = event.sessionId) !== null && _j !== void 0 ? _j : getOrCreateSessionId()), deviceType: detectDeviceType(), path, pagePath: (_l = (_k = event.pagePath) !== null && _k !== void 0 ? _k : campaignFields.pagePath) !== null && _l !== void 0 ? _l : path, destinationDomain: (_m = event.destinationDomain) !== null && _m !== void 0 ? _m : getDestinationDomain(href), location: getResolvedLocation(), eventType: 'page_view' }), event), { metadata: prunePromotedMetadataKeys(Object.assign(Object.assign(Object.assign({}, ((_o = configuredDefaults.metadata) !== null && _o !== void 0 ? _o : {})), ((_p = dynamicDefaults.metadata) !== null && _p !== void 0 ? _p : {})), ((_q = event.metadata) !== null && _q !== void 0 ? _q : {}))) });
|
|
212
249
|
}
|
|
213
250
|
function mergeTagEventDefaults(event) {
|
|
214
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
251
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
215
252
|
const configuredDefaults = (_a = analyticsBrowserState.config.defaultTagEvent) !== null && _a !== void 0 ? _a : {};
|
|
216
253
|
const dynamicDefaults = (_d = (_c = (_b = analyticsBrowserState.config).getTagDefaults) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : {};
|
|
217
254
|
const visitorId = (_e = event.visitorId) !== null && _e !== void 0 ? _e : getOrCreateVisitorId();
|
|
218
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, configuredDefaults), dynamicDefaults), { visitorId, sessionId: getOrCreateSessionId(), deviceType: detectDeviceType(), location: getResolvedLocation(), eventType: 'scan_tag' }), event), { metadata:
|
|
255
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, configuredDefaults), dynamicDefaults), { visitorId, sessionId: assertValidSessionId((_f = event.sessionId) !== null && _f !== void 0 ? _f : getOrCreateSessionId()), deviceType: detectDeviceType(), location: getResolvedLocation(), eventType: 'scan_tag' }), event), { metadata: prunePromotedMetadataKeys(Object.assign(Object.assign(Object.assign({}, ((_g = configuredDefaults.metadata) !== null && _g !== void 0 ? _g : {})), ((_h = dynamicDefaults.metadata) !== null && _h !== void 0 ? _h : {})), ((_j = event.metadata) !== null && _j !== void 0 ? _j : {}))) });
|
|
219
256
|
}
|
|
220
257
|
function isExternalHref(href) {
|
|
221
258
|
if (typeof window === 'undefined')
|
|
@@ -267,7 +304,7 @@ export var analytics;
|
|
|
267
304
|
* Uses `navigator.sendBeacon()` when available, falling back to `fetch(..., { keepalive: true })`.
|
|
268
305
|
*/
|
|
269
306
|
function track(event, options) {
|
|
270
|
-
return queueAnalytics('/public/analytics/collection', event, options);
|
|
307
|
+
return queueAnalytics('/public/analytics/collection', normalizeAnalyticsEvent(event), options);
|
|
271
308
|
}
|
|
272
309
|
collection.track = track;
|
|
273
310
|
})(collection = analytics.collection || (analytics.collection = {}));
|
|
@@ -278,7 +315,7 @@ export var analytics;
|
|
|
278
315
|
* Uses `navigator.sendBeacon()` when available, falling back to `fetch(..., { keepalive: true })`.
|
|
279
316
|
*/
|
|
280
317
|
function track(event, options) {
|
|
281
|
-
return queueAnalytics('/public/analytics/tag', event, options);
|
|
318
|
+
return queueAnalytics('/public/analytics/tag', normalizeAnalyticsEvent(event), options);
|
|
282
319
|
}
|
|
283
320
|
tag.track = track;
|
|
284
321
|
})(tag = analytics.tag || (analytics.tag = {}));
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.1 | Generated: 2026-03-14T09:21:59.178Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -938,9 +938,9 @@ interface AnalyticsLocation {
|
|
|
938
938
|
}
|
|
939
939
|
```
|
|
940
940
|
|
|
941
|
-
**
|
|
941
|
+
**AnalyticsStandardEventFields** (interface)
|
|
942
942
|
```typescript
|
|
943
|
-
interface
|
|
943
|
+
interface AnalyticsStandardEventFields {
|
|
944
944
|
visitorId?: string
|
|
945
945
|
referrer?: string
|
|
946
946
|
referrerHost?: string
|
|
@@ -977,13 +977,13 @@ interface AnalyticsTrackOptions {
|
|
|
977
977
|
```typescript
|
|
978
978
|
interface AnalyticsBrowserConfig {
|
|
979
979
|
sessionStorageKey?: string
|
|
980
|
-
sessionIdFactory?: () =>
|
|
980
|
+
sessionIdFactory?: () => AnalyticsSessionId
|
|
981
981
|
visitorId?: string
|
|
982
982
|
visitorStorage?: AnalyticsStorageMode
|
|
983
983
|
visitorStorageKey?: string
|
|
984
984
|
visitorIdFactory?: () => string
|
|
985
985
|
autoCaptureCampaignParams?: boolean
|
|
986
|
-
campaignParamMap?: Partial<Record<keyof
|
|
986
|
+
campaignParamMap?: Partial<Record<keyof AnalyticsStandardEventFields, string | string[]>>
|
|
987
987
|
defaultCollectionEvent?: Partial<CollectionAnalyticsEvent>
|
|
988
988
|
defaultTagEvent?: Partial<TagAnalyticsEvent>
|
|
989
989
|
getCollectionDefaults?: () => Partial<CollectionAnalyticsEvent> | undefined
|
|
@@ -1048,8 +1048,8 @@ interface AnalyticsFilterRequest {
|
|
|
1048
1048
|
batchIds?: string[]
|
|
1049
1049
|
variantId?: string
|
|
1050
1050
|
variantIds?: string[]
|
|
1051
|
-
sessionId?:
|
|
1052
|
-
sessionIds?:
|
|
1051
|
+
sessionId?: AnalyticsSessionId
|
|
1052
|
+
sessionIds?: AnalyticsSessionId[]
|
|
1053
1053
|
country?: string
|
|
1054
1054
|
countries?: string[]
|
|
1055
1055
|
metadata?: Record<string, any>
|
|
@@ -1256,6 +1256,8 @@ interface AnalyticsTagsResponse {
|
|
|
1256
1256
|
|
|
1257
1257
|
**AnalyticsStorageMode** = `'local' | 'session' | false`
|
|
1258
1258
|
|
|
1259
|
+
**AnalyticsSessionId** = `number`
|
|
1260
|
+
|
|
1259
1261
|
**EventAnalyticsDimension** = ``
|
|
1260
1262
|
|
|
1261
1263
|
**TagAnalyticsDimension** = ``
|
|
@@ -5789,7 +5791,7 @@ Fire-and-forget tag analytics event. Uses `navigator.sendBeacon()` when availabl
|
|
|
5789
5791
|
**configure**(config: AnalyticsBrowserConfig) → `void`
|
|
5790
5792
|
Fire-and-forget tag analytics event. Uses `navigator.sendBeacon()` when available, falling back to `fetch(..., { keepalive: true })`.
|
|
5791
5793
|
|
|
5792
|
-
**getSessionId**() → `
|
|
5794
|
+
**getSessionId**() → `AnalyticsSessionId | undefined`
|
|
5793
5795
|
Fire-and-forget tag analytics event. Uses `navigator.sendBeacon()` when available, falling back to `fetch(..., { keepalive: true })`.
|
|
5794
5796
|
|
|
5795
5797
|
**getVisitorId**() → `string | undefined`
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
# Analytics Metadata Conventions
|
|
2
2
|
|
|
3
|
-
Use these as the recommended standard
|
|
3
|
+
Use these as the recommended standard analytics keys.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Some of these are now promoted top-level analytics fields. Others remain good metadata keys for custom dimensions.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Recommended Keys
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Promoted top-level fields
|
|
12
12
|
|
|
13
|
-
- `
|
|
13
|
+
- `visitorId`
|
|
14
14
|
- `referrerHost`
|
|
15
|
+
- `entryType`
|
|
16
|
+
- `pageId`
|
|
17
|
+
- `scanMethod`
|
|
18
|
+
|
|
19
|
+
These should be sent as top-level analytics fields, not inside `metadata`.
|
|
20
|
+
|
|
21
|
+
### Metadata-friendly keys
|
|
22
|
+
|
|
23
|
+
- `referrer`
|
|
15
24
|
- `utmSource`
|
|
16
25
|
- `utmMedium`
|
|
17
26
|
- `utmCampaign`
|
|
18
27
|
- `utmContent`
|
|
19
28
|
- `utmTerm`
|
|
20
|
-
- `entryType` — for example `direct`, `qr`, `nfc`, `social`, `email`, `paid`, or `organic`
|
|
21
|
-
|
|
22
|
-
### Link-tree and page analytics
|
|
23
|
-
|
|
24
29
|
- `group`
|
|
25
30
|
- `tag`
|
|
26
31
|
- `campaign`
|
|
@@ -31,13 +36,8 @@ You can put them in `metadata` directly today. The public analytics ingestion en
|
|
|
31
36
|
- `linkTitle`
|
|
32
37
|
- `destinationDomain`
|
|
33
38
|
- `pagePath`
|
|
34
|
-
- `pageId`
|
|
35
39
|
- `qrCodeId`
|
|
36
40
|
|
|
37
|
-
### Physical scan analytics
|
|
38
|
-
|
|
39
|
-
- `scanMethod` — for example `nfc` or `qr`
|
|
40
|
-
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
## Why These Matter
|
|
@@ -56,6 +56,7 @@ These keys give teams a shared vocabulary for:
|
|
|
56
56
|
|
|
57
57
|
- Treat these as reserved standard keys.
|
|
58
58
|
- Prefer these names before inventing custom alternatives.
|
|
59
|
+
- Send promoted fields at top level.
|
|
59
60
|
- Keep values flat and scalar where possible so they are easier to filter and break down later.
|
|
60
61
|
- Promote a field to a first-class backend column only when it becomes a hot platform-wide dimension.
|
|
61
62
|
|
|
@@ -65,14 +66,17 @@ These keys give teams a shared vocabulary for:
|
|
|
65
66
|
|
|
66
67
|
```typescript
|
|
67
68
|
analytics.collection.track({
|
|
68
|
-
sessionId:
|
|
69
|
+
sessionId: 1234567890,
|
|
69
70
|
eventType: 'click_link',
|
|
70
71
|
collectionId: 'demo-collection',
|
|
72
|
+
visitorId: 'visitor_123',
|
|
71
73
|
linkId: 'hero-cta',
|
|
72
74
|
href: 'https://example.com/buy',
|
|
75
|
+
referrerHost: 'instagram.com',
|
|
73
76
|
placement: 'hero',
|
|
74
77
|
campaign: 'summer-launch',
|
|
75
78
|
utmSource: 'email',
|
|
79
|
+
pageId: 'QR123',
|
|
76
80
|
metadata: {
|
|
77
81
|
pagePath: '/c/demo-collection',
|
|
78
82
|
},
|
package/dist/docs/analytics.md
CHANGED
|
@@ -44,7 +44,7 @@ There are two analytics domains:
|
|
|
44
44
|
| Collection events | `/public/analytics/collection` | Page views, clicks, app navigation, landing pages |
|
|
45
45
|
| Tag events | `/public/analytics/tag` | NFC / QR scans, claim/code activity, suspicious scan monitoring |
|
|
46
46
|
|
|
47
|
-
The backend stores custom analytics dimensions in `metadata
|
|
47
|
+
The backend stores custom analytics dimensions in `metadata`, but promoted analytics fields now belong at top level and are queried from real columns.
|
|
48
48
|
|
|
49
49
|
See [docs/analytics-metadata-conventions.md](analytics-metadata-conventions.md) for the recommended key set.
|
|
50
50
|
|
|
@@ -60,7 +60,7 @@ import { initializeApi, analytics } from '@proveanything/smartlinks'
|
|
|
60
60
|
initializeApi({ baseURL: 'https://smartlinks.app/api/v1' })
|
|
61
61
|
|
|
62
62
|
analytics.collection.track({
|
|
63
|
-
sessionId:
|
|
63
|
+
sessionId: 1234567890,
|
|
64
64
|
eventType: 'page_view',
|
|
65
65
|
collectionId: 'demo-collection',
|
|
66
66
|
productId: 'product_1',
|
|
@@ -74,7 +74,7 @@ analytics.collection.track({
|
|
|
74
74
|
|
|
75
75
|
```typescript
|
|
76
76
|
analytics.collection.track({
|
|
77
|
-
sessionId:
|
|
77
|
+
sessionId: 1234567890,
|
|
78
78
|
eventType: 'click_link',
|
|
79
79
|
collectionId: 'demo-collection',
|
|
80
80
|
productId: 'product_1',
|
|
@@ -91,7 +91,7 @@ analytics.collection.track({
|
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
93
|
analytics.tag.track({
|
|
94
|
-
sessionId:
|
|
94
|
+
sessionId: 1234567890,
|
|
95
95
|
eventType: 'scan_tag',
|
|
96
96
|
collectionId: 'demo-collection',
|
|
97
97
|
productId: 'product_1',
|
|
@@ -298,15 +298,13 @@ Tracks generic collection analytics events such as:
|
|
|
298
298
|
- internal navigation
|
|
299
299
|
- outbound link activity
|
|
300
300
|
|
|
301
|
-
Supported top-level fields include the core event fields plus
|
|
302
|
-
|
|
303
|
-
`visitorId` is also supported as a standard top-level field and is mirrored into `metadata` by the backend for backward compatibility.
|
|
301
|
+
Supported top-level fields include the core event fields plus promoted analytics columns such as `visitorId`, `referrerHost`, `pageId`, and `entryType`, along with custom metadata dimensions like `group`, `placement`, `pagePath`, and `qrCodeId`.
|
|
304
302
|
|
|
305
303
|
Example:
|
|
306
304
|
|
|
307
305
|
```typescript
|
|
308
306
|
analytics.collection.track({
|
|
309
|
-
sessionId:
|
|
307
|
+
sessionId: 1234567890,
|
|
310
308
|
eventType: 'page_view',
|
|
311
309
|
collectionId: 'demo-collection',
|
|
312
310
|
productId: 'product_1',
|
|
@@ -322,6 +320,7 @@ analytics.collection.track({
|
|
|
322
320
|
utmCampaign: 'summer-launch',
|
|
323
321
|
group: 'summer-launch',
|
|
324
322
|
placement: 'hero',
|
|
323
|
+
pageId: 'QR123',
|
|
325
324
|
metadata: { pagePath: '/c/demo-collection?pageId=QR123' },
|
|
326
325
|
})
|
|
327
326
|
```
|
|
@@ -335,15 +334,13 @@ Tracks physical scan analytics such as:
|
|
|
335
334
|
- claim/code activity
|
|
336
335
|
- admin vs customer scan behavior
|
|
337
336
|
|
|
338
|
-
Supported top-level fields include the core scan fields plus
|
|
339
|
-
|
|
340
|
-
Like collection events, tag events also accept `visitorId` as a standard top-level field.
|
|
337
|
+
Supported top-level fields include the core scan fields plus promoted analytics columns such as `visitorId`, `entryType`, and `scanMethod`, along with custom metadata dimensions like `group`, `tag`, and campaign extras.
|
|
341
338
|
|
|
342
339
|
Example:
|
|
343
340
|
|
|
344
341
|
```typescript
|
|
345
342
|
analytics.tag.track({
|
|
346
|
-
sessionId:
|
|
343
|
+
sessionId: 1234567890,
|
|
347
344
|
eventType: 'scan_tag',
|
|
348
345
|
collectionId: 'demo-collection',
|
|
349
346
|
productId: 'product_1',
|
|
@@ -374,6 +371,8 @@ Notes:
|
|
|
374
371
|
|
|
375
372
|
Top-level scalar metadata values are the most query-friendly today. You can filter them with `metadata` and break them down with `dimension: 'metadata'` plus `metadataKey`.
|
|
376
373
|
|
|
374
|
+
Promoted fields such as `visitorId`, `referrerHost`, `pageId`, `entryType`, and `scanMethod` should be sent and queried as top-level fields, not inside `metadata`.
|
|
375
|
+
|
|
377
376
|
```typescript
|
|
378
377
|
const grouped = await analytics.admin.breakdown('demo-collection', {
|
|
379
378
|
source: 'tag',
|
|
@@ -528,7 +527,7 @@ const traffic = await analytics.admin.timeseries('demo-collection', {
|
|
|
528
527
|
})
|
|
529
528
|
```
|
|
530
529
|
|
|
531
|
-
`uniqueVisitors` now works in generic analytics queries. The backend uses `visitorId` when present and falls back to `sessionId` for older events that do not include it yet.
|
|
530
|
+
`uniqueVisitors` now works in generic analytics queries. The backend uses the top-level `visitorId` column when present and falls back to numeric `sessionId` for older events that do not include it yet.
|
|
532
531
|
|
|
533
532
|
### Breakdown
|
|
534
533
|
|
|
@@ -579,7 +578,7 @@ Most admin analytics queries support combinations of:
|
|
|
579
578
|
- `proofId` or `proofIds[]`
|
|
580
579
|
- `batchId` or `batchIds[]`
|
|
581
580
|
- `variantId` or `variantIds[]`
|
|
582
|
-
- `sessionId` or `sessionIds[]`
|
|
581
|
+
- `sessionId` or `sessionIds[]` as numbers
|
|
583
582
|
- `country` or `countries[]`
|
|
584
583
|
- `metadata` for top-level JSON equality matching
|
|
585
584
|
|
|
@@ -626,11 +625,9 @@ Analytics metadata filtering currently works best with top-level scalar keys suc
|
|
|
626
625
|
- `campaign`
|
|
627
626
|
- `group`
|
|
628
627
|
- `tag`
|
|
629
|
-
- `referrerHost`
|
|
630
628
|
- `utmSource`
|
|
631
629
|
- `utmCampaign`
|
|
632
630
|
- `pagePath`
|
|
633
|
-
- `scanMethod`
|
|
634
631
|
|
|
635
632
|
See [docs/analytics-metadata-conventions.md](analytics-metadata-conventions.md) for the recommended shared vocabulary.
|
|
636
633
|
|
|
@@ -645,7 +642,7 @@ Use `/summary`, `/timeseries`, `/breakdown`, and `/events` when you are building
|
|
|
645
642
|
```typescript
|
|
646
643
|
function trackAndNavigate(href: string) {
|
|
647
644
|
analytics.collection.track({
|
|
648
|
-
sessionId:
|
|
645
|
+
sessionId: 1234567890,
|
|
649
646
|
eventType: 'click_link',
|
|
650
647
|
collectionId: 'demo-collection',
|
|
651
648
|
linkId: 'buy-now',
|
package/dist/openapi.yaml
CHANGED
|
@@ -10782,7 +10782,7 @@ components:
|
|
|
10782
10782
|
type: number
|
|
10783
10783
|
area:
|
|
10784
10784
|
type: number
|
|
10785
|
-
|
|
10785
|
+
AnalyticsStandardEventFields:
|
|
10786
10786
|
type: object
|
|
10787
10787
|
properties:
|
|
10788
10788
|
visitorId:
|
|
@@ -10834,7 +10834,7 @@ components:
|
|
|
10834
10834
|
type: object
|
|
10835
10835
|
properties:
|
|
10836
10836
|
sessionId:
|
|
10837
|
-
|
|
10837
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
10838
10838
|
eventType:
|
|
10839
10839
|
$ref: "#/components/schemas/AnalyticsEventType"
|
|
10840
10840
|
collectionId:
|
|
@@ -10873,7 +10873,7 @@ components:
|
|
|
10873
10873
|
type: object
|
|
10874
10874
|
properties:
|
|
10875
10875
|
sessionId:
|
|
10876
|
-
|
|
10876
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
10877
10877
|
eventType:
|
|
10878
10878
|
$ref: "#/components/schemas/AnalyticsEventType"
|
|
10879
10879
|
collectionId:
|
|
@@ -11048,11 +11048,11 @@ components:
|
|
|
11048
11048
|
items:
|
|
11049
11049
|
type: string
|
|
11050
11050
|
sessionId:
|
|
11051
|
-
|
|
11051
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
11052
11052
|
sessionIds:
|
|
11053
11053
|
type: array
|
|
11054
11054
|
items:
|
|
11055
|
-
|
|
11055
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
11056
11056
|
country:
|
|
11057
11057
|
type: string
|
|
11058
11058
|
countries:
|
|
@@ -11,6 +11,7 @@ export type AnalyticsMetric = 'count' | 'uniqueSessions' | 'uniqueVisitors';
|
|
|
11
11
|
export type AnalyticsSortOrder = 'asc' | 'desc';
|
|
12
12
|
export type AnalyticsDeviceType = 'mobile' | 'tablet' | 'desktop' | 'unknown';
|
|
13
13
|
export type AnalyticsStorageMode = 'local' | 'session' | false;
|
|
14
|
+
export type AnalyticsSessionId = number;
|
|
14
15
|
export interface AnalyticsLocation {
|
|
15
16
|
country?: string;
|
|
16
17
|
latitude?: number;
|
|
@@ -18,7 +19,7 @@ export interface AnalyticsLocation {
|
|
|
18
19
|
area?: number;
|
|
19
20
|
[key: string]: any;
|
|
20
21
|
}
|
|
21
|
-
export interface
|
|
22
|
+
export interface AnalyticsStandardEventFields {
|
|
22
23
|
visitorId?: string;
|
|
23
24
|
referrer?: string;
|
|
24
25
|
referrerHost?: string;
|
|
@@ -42,8 +43,8 @@ export interface AnalyticsStandardMetadataFields {
|
|
|
42
43
|
qrCodeId?: string;
|
|
43
44
|
scanMethod?: string;
|
|
44
45
|
}
|
|
45
|
-
export interface CollectionAnalyticsEvent extends
|
|
46
|
-
sessionId?:
|
|
46
|
+
export interface CollectionAnalyticsEvent extends AnalyticsStandardEventFields {
|
|
47
|
+
sessionId?: AnalyticsSessionId;
|
|
47
48
|
eventType: AnalyticsEventType;
|
|
48
49
|
collectionId: string;
|
|
49
50
|
productId?: string;
|
|
@@ -60,8 +61,8 @@ export interface CollectionAnalyticsEvent extends AnalyticsStandardMetadataField
|
|
|
60
61
|
location?: AnalyticsLocation;
|
|
61
62
|
metadata?: Record<string, any>;
|
|
62
63
|
}
|
|
63
|
-
export interface TagAnalyticsEvent extends
|
|
64
|
-
sessionId?:
|
|
64
|
+
export interface TagAnalyticsEvent extends AnalyticsStandardEventFields {
|
|
65
|
+
sessionId?: AnalyticsSessionId;
|
|
65
66
|
eventType: AnalyticsEventType;
|
|
66
67
|
collectionId: string;
|
|
67
68
|
productId?: string;
|
|
@@ -81,13 +82,13 @@ export interface AnalyticsTrackOptions {
|
|
|
81
82
|
}
|
|
82
83
|
export interface AnalyticsBrowserConfig {
|
|
83
84
|
sessionStorageKey?: string;
|
|
84
|
-
sessionIdFactory?: () =>
|
|
85
|
+
sessionIdFactory?: () => AnalyticsSessionId;
|
|
85
86
|
visitorId?: string;
|
|
86
87
|
visitorStorage?: AnalyticsStorageMode;
|
|
87
88
|
visitorStorageKey?: string;
|
|
88
89
|
visitorIdFactory?: () => string;
|
|
89
90
|
autoCaptureCampaignParams?: boolean;
|
|
90
|
-
campaignParamMap?: Partial<Record<keyof
|
|
91
|
+
campaignParamMap?: Partial<Record<keyof AnalyticsStandardEventFields, string | string[]>>;
|
|
91
92
|
defaultCollectionEvent?: Partial<CollectionAnalyticsEvent>;
|
|
92
93
|
defaultTagEvent?: Partial<TagAnalyticsEvent>;
|
|
93
94
|
getCollectionDefaults?: () => Partial<CollectionAnalyticsEvent> | undefined;
|
|
@@ -148,8 +149,8 @@ export interface AnalyticsFilterRequest {
|
|
|
148
149
|
batchIds?: string[];
|
|
149
150
|
variantId?: string;
|
|
150
151
|
variantIds?: string[];
|
|
151
|
-
sessionId?:
|
|
152
|
-
sessionIds?:
|
|
152
|
+
sessionId?: AnalyticsSessionId;
|
|
153
|
+
sessionIds?: AnalyticsSessionId[];
|
|
153
154
|
country?: string;
|
|
154
155
|
countries?: string[];
|
|
155
156
|
metadata?: Record<string, any>;
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.1 | Generated: 2026-03-14T09:21:59.178Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -938,9 +938,9 @@ interface AnalyticsLocation {
|
|
|
938
938
|
}
|
|
939
939
|
```
|
|
940
940
|
|
|
941
|
-
**
|
|
941
|
+
**AnalyticsStandardEventFields** (interface)
|
|
942
942
|
```typescript
|
|
943
|
-
interface
|
|
943
|
+
interface AnalyticsStandardEventFields {
|
|
944
944
|
visitorId?: string
|
|
945
945
|
referrer?: string
|
|
946
946
|
referrerHost?: string
|
|
@@ -977,13 +977,13 @@ interface AnalyticsTrackOptions {
|
|
|
977
977
|
```typescript
|
|
978
978
|
interface AnalyticsBrowserConfig {
|
|
979
979
|
sessionStorageKey?: string
|
|
980
|
-
sessionIdFactory?: () =>
|
|
980
|
+
sessionIdFactory?: () => AnalyticsSessionId
|
|
981
981
|
visitorId?: string
|
|
982
982
|
visitorStorage?: AnalyticsStorageMode
|
|
983
983
|
visitorStorageKey?: string
|
|
984
984
|
visitorIdFactory?: () => string
|
|
985
985
|
autoCaptureCampaignParams?: boolean
|
|
986
|
-
campaignParamMap?: Partial<Record<keyof
|
|
986
|
+
campaignParamMap?: Partial<Record<keyof AnalyticsStandardEventFields, string | string[]>>
|
|
987
987
|
defaultCollectionEvent?: Partial<CollectionAnalyticsEvent>
|
|
988
988
|
defaultTagEvent?: Partial<TagAnalyticsEvent>
|
|
989
989
|
getCollectionDefaults?: () => Partial<CollectionAnalyticsEvent> | undefined
|
|
@@ -1048,8 +1048,8 @@ interface AnalyticsFilterRequest {
|
|
|
1048
1048
|
batchIds?: string[]
|
|
1049
1049
|
variantId?: string
|
|
1050
1050
|
variantIds?: string[]
|
|
1051
|
-
sessionId?:
|
|
1052
|
-
sessionIds?:
|
|
1051
|
+
sessionId?: AnalyticsSessionId
|
|
1052
|
+
sessionIds?: AnalyticsSessionId[]
|
|
1053
1053
|
country?: string
|
|
1054
1054
|
countries?: string[]
|
|
1055
1055
|
metadata?: Record<string, any>
|
|
@@ -1256,6 +1256,8 @@ interface AnalyticsTagsResponse {
|
|
|
1256
1256
|
|
|
1257
1257
|
**AnalyticsStorageMode** = `'local' | 'session' | false`
|
|
1258
1258
|
|
|
1259
|
+
**AnalyticsSessionId** = `number`
|
|
1260
|
+
|
|
1259
1261
|
**EventAnalyticsDimension** = ``
|
|
1260
1262
|
|
|
1261
1263
|
**TagAnalyticsDimension** = ``
|
|
@@ -5789,7 +5791,7 @@ Fire-and-forget tag analytics event. Uses `navigator.sendBeacon()` when availabl
|
|
|
5789
5791
|
**configure**(config: AnalyticsBrowserConfig) → `void`
|
|
5790
5792
|
Fire-and-forget tag analytics event. Uses `navigator.sendBeacon()` when available, falling back to `fetch(..., { keepalive: true })`.
|
|
5791
5793
|
|
|
5792
|
-
**getSessionId**() → `
|
|
5794
|
+
**getSessionId**() → `AnalyticsSessionId | undefined`
|
|
5793
5795
|
Fire-and-forget tag analytics event. Uses `navigator.sendBeacon()` when available, falling back to `fetch(..., { keepalive: true })`.
|
|
5794
5796
|
|
|
5795
5797
|
**getVisitorId**() → `string | undefined`
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
# Analytics Metadata Conventions
|
|
2
2
|
|
|
3
|
-
Use these as the recommended standard
|
|
3
|
+
Use these as the recommended standard analytics keys.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Some of these are now promoted top-level analytics fields. Others remain good metadata keys for custom dimensions.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Recommended Keys
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Promoted top-level fields
|
|
12
12
|
|
|
13
|
-
- `
|
|
13
|
+
- `visitorId`
|
|
14
14
|
- `referrerHost`
|
|
15
|
+
- `entryType`
|
|
16
|
+
- `pageId`
|
|
17
|
+
- `scanMethod`
|
|
18
|
+
|
|
19
|
+
These should be sent as top-level analytics fields, not inside `metadata`.
|
|
20
|
+
|
|
21
|
+
### Metadata-friendly keys
|
|
22
|
+
|
|
23
|
+
- `referrer`
|
|
15
24
|
- `utmSource`
|
|
16
25
|
- `utmMedium`
|
|
17
26
|
- `utmCampaign`
|
|
18
27
|
- `utmContent`
|
|
19
28
|
- `utmTerm`
|
|
20
|
-
- `entryType` — for example `direct`, `qr`, `nfc`, `social`, `email`, `paid`, or `organic`
|
|
21
|
-
|
|
22
|
-
### Link-tree and page analytics
|
|
23
|
-
|
|
24
29
|
- `group`
|
|
25
30
|
- `tag`
|
|
26
31
|
- `campaign`
|
|
@@ -31,13 +36,8 @@ You can put them in `metadata` directly today. The public analytics ingestion en
|
|
|
31
36
|
- `linkTitle`
|
|
32
37
|
- `destinationDomain`
|
|
33
38
|
- `pagePath`
|
|
34
|
-
- `pageId`
|
|
35
39
|
- `qrCodeId`
|
|
36
40
|
|
|
37
|
-
### Physical scan analytics
|
|
38
|
-
|
|
39
|
-
- `scanMethod` — for example `nfc` or `qr`
|
|
40
|
-
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
## Why These Matter
|
|
@@ -56,6 +56,7 @@ These keys give teams a shared vocabulary for:
|
|
|
56
56
|
|
|
57
57
|
- Treat these as reserved standard keys.
|
|
58
58
|
- Prefer these names before inventing custom alternatives.
|
|
59
|
+
- Send promoted fields at top level.
|
|
59
60
|
- Keep values flat and scalar where possible so they are easier to filter and break down later.
|
|
60
61
|
- Promote a field to a first-class backend column only when it becomes a hot platform-wide dimension.
|
|
61
62
|
|
|
@@ -65,14 +66,17 @@ These keys give teams a shared vocabulary for:
|
|
|
65
66
|
|
|
66
67
|
```typescript
|
|
67
68
|
analytics.collection.track({
|
|
68
|
-
sessionId:
|
|
69
|
+
sessionId: 1234567890,
|
|
69
70
|
eventType: 'click_link',
|
|
70
71
|
collectionId: 'demo-collection',
|
|
72
|
+
visitorId: 'visitor_123',
|
|
71
73
|
linkId: 'hero-cta',
|
|
72
74
|
href: 'https://example.com/buy',
|
|
75
|
+
referrerHost: 'instagram.com',
|
|
73
76
|
placement: 'hero',
|
|
74
77
|
campaign: 'summer-launch',
|
|
75
78
|
utmSource: 'email',
|
|
79
|
+
pageId: 'QR123',
|
|
76
80
|
metadata: {
|
|
77
81
|
pagePath: '/c/demo-collection',
|
|
78
82
|
},
|
package/docs/analytics.md
CHANGED
|
@@ -44,7 +44,7 @@ There are two analytics domains:
|
|
|
44
44
|
| Collection events | `/public/analytics/collection` | Page views, clicks, app navigation, landing pages |
|
|
45
45
|
| Tag events | `/public/analytics/tag` | NFC / QR scans, claim/code activity, suspicious scan monitoring |
|
|
46
46
|
|
|
47
|
-
The backend stores custom analytics dimensions in `metadata
|
|
47
|
+
The backend stores custom analytics dimensions in `metadata`, but promoted analytics fields now belong at top level and are queried from real columns.
|
|
48
48
|
|
|
49
49
|
See [docs/analytics-metadata-conventions.md](analytics-metadata-conventions.md) for the recommended key set.
|
|
50
50
|
|
|
@@ -60,7 +60,7 @@ import { initializeApi, analytics } from '@proveanything/smartlinks'
|
|
|
60
60
|
initializeApi({ baseURL: 'https://smartlinks.app/api/v1' })
|
|
61
61
|
|
|
62
62
|
analytics.collection.track({
|
|
63
|
-
sessionId:
|
|
63
|
+
sessionId: 1234567890,
|
|
64
64
|
eventType: 'page_view',
|
|
65
65
|
collectionId: 'demo-collection',
|
|
66
66
|
productId: 'product_1',
|
|
@@ -74,7 +74,7 @@ analytics.collection.track({
|
|
|
74
74
|
|
|
75
75
|
```typescript
|
|
76
76
|
analytics.collection.track({
|
|
77
|
-
sessionId:
|
|
77
|
+
sessionId: 1234567890,
|
|
78
78
|
eventType: 'click_link',
|
|
79
79
|
collectionId: 'demo-collection',
|
|
80
80
|
productId: 'product_1',
|
|
@@ -91,7 +91,7 @@ analytics.collection.track({
|
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
93
|
analytics.tag.track({
|
|
94
|
-
sessionId:
|
|
94
|
+
sessionId: 1234567890,
|
|
95
95
|
eventType: 'scan_tag',
|
|
96
96
|
collectionId: 'demo-collection',
|
|
97
97
|
productId: 'product_1',
|
|
@@ -298,15 +298,13 @@ Tracks generic collection analytics events such as:
|
|
|
298
298
|
- internal navigation
|
|
299
299
|
- outbound link activity
|
|
300
300
|
|
|
301
|
-
Supported top-level fields include the core event fields plus
|
|
302
|
-
|
|
303
|
-
`visitorId` is also supported as a standard top-level field and is mirrored into `metadata` by the backend for backward compatibility.
|
|
301
|
+
Supported top-level fields include the core event fields plus promoted analytics columns such as `visitorId`, `referrerHost`, `pageId`, and `entryType`, along with custom metadata dimensions like `group`, `placement`, `pagePath`, and `qrCodeId`.
|
|
304
302
|
|
|
305
303
|
Example:
|
|
306
304
|
|
|
307
305
|
```typescript
|
|
308
306
|
analytics.collection.track({
|
|
309
|
-
sessionId:
|
|
307
|
+
sessionId: 1234567890,
|
|
310
308
|
eventType: 'page_view',
|
|
311
309
|
collectionId: 'demo-collection',
|
|
312
310
|
productId: 'product_1',
|
|
@@ -322,6 +320,7 @@ analytics.collection.track({
|
|
|
322
320
|
utmCampaign: 'summer-launch',
|
|
323
321
|
group: 'summer-launch',
|
|
324
322
|
placement: 'hero',
|
|
323
|
+
pageId: 'QR123',
|
|
325
324
|
metadata: { pagePath: '/c/demo-collection?pageId=QR123' },
|
|
326
325
|
})
|
|
327
326
|
```
|
|
@@ -335,15 +334,13 @@ Tracks physical scan analytics such as:
|
|
|
335
334
|
- claim/code activity
|
|
336
335
|
- admin vs customer scan behavior
|
|
337
336
|
|
|
338
|
-
Supported top-level fields include the core scan fields plus
|
|
339
|
-
|
|
340
|
-
Like collection events, tag events also accept `visitorId` as a standard top-level field.
|
|
337
|
+
Supported top-level fields include the core scan fields plus promoted analytics columns such as `visitorId`, `entryType`, and `scanMethod`, along with custom metadata dimensions like `group`, `tag`, and campaign extras.
|
|
341
338
|
|
|
342
339
|
Example:
|
|
343
340
|
|
|
344
341
|
```typescript
|
|
345
342
|
analytics.tag.track({
|
|
346
|
-
sessionId:
|
|
343
|
+
sessionId: 1234567890,
|
|
347
344
|
eventType: 'scan_tag',
|
|
348
345
|
collectionId: 'demo-collection',
|
|
349
346
|
productId: 'product_1',
|
|
@@ -374,6 +371,8 @@ Notes:
|
|
|
374
371
|
|
|
375
372
|
Top-level scalar metadata values are the most query-friendly today. You can filter them with `metadata` and break them down with `dimension: 'metadata'` plus `metadataKey`.
|
|
376
373
|
|
|
374
|
+
Promoted fields such as `visitorId`, `referrerHost`, `pageId`, `entryType`, and `scanMethod` should be sent and queried as top-level fields, not inside `metadata`.
|
|
375
|
+
|
|
377
376
|
```typescript
|
|
378
377
|
const grouped = await analytics.admin.breakdown('demo-collection', {
|
|
379
378
|
source: 'tag',
|
|
@@ -528,7 +527,7 @@ const traffic = await analytics.admin.timeseries('demo-collection', {
|
|
|
528
527
|
})
|
|
529
528
|
```
|
|
530
529
|
|
|
531
|
-
`uniqueVisitors` now works in generic analytics queries. The backend uses `visitorId` when present and falls back to `sessionId` for older events that do not include it yet.
|
|
530
|
+
`uniqueVisitors` now works in generic analytics queries. The backend uses the top-level `visitorId` column when present and falls back to numeric `sessionId` for older events that do not include it yet.
|
|
532
531
|
|
|
533
532
|
### Breakdown
|
|
534
533
|
|
|
@@ -579,7 +578,7 @@ Most admin analytics queries support combinations of:
|
|
|
579
578
|
- `proofId` or `proofIds[]`
|
|
580
579
|
- `batchId` or `batchIds[]`
|
|
581
580
|
- `variantId` or `variantIds[]`
|
|
582
|
-
- `sessionId` or `sessionIds[]`
|
|
581
|
+
- `sessionId` or `sessionIds[]` as numbers
|
|
583
582
|
- `country` or `countries[]`
|
|
584
583
|
- `metadata` for top-level JSON equality matching
|
|
585
584
|
|
|
@@ -626,11 +625,9 @@ Analytics metadata filtering currently works best with top-level scalar keys suc
|
|
|
626
625
|
- `campaign`
|
|
627
626
|
- `group`
|
|
628
627
|
- `tag`
|
|
629
|
-
- `referrerHost`
|
|
630
628
|
- `utmSource`
|
|
631
629
|
- `utmCampaign`
|
|
632
630
|
- `pagePath`
|
|
633
|
-
- `scanMethod`
|
|
634
631
|
|
|
635
632
|
See [docs/analytics-metadata-conventions.md](analytics-metadata-conventions.md) for the recommended shared vocabulary.
|
|
636
633
|
|
|
@@ -645,7 +642,7 @@ Use `/summary`, `/timeseries`, `/breakdown`, and `/events` when you are building
|
|
|
645
642
|
```typescript
|
|
646
643
|
function trackAndNavigate(href: string) {
|
|
647
644
|
analytics.collection.track({
|
|
648
|
-
sessionId:
|
|
645
|
+
sessionId: 1234567890,
|
|
649
646
|
eventType: 'click_link',
|
|
650
647
|
collectionId: 'demo-collection',
|
|
651
648
|
linkId: 'buy-now',
|
package/openapi.yaml
CHANGED
|
@@ -10782,7 +10782,7 @@ components:
|
|
|
10782
10782
|
type: number
|
|
10783
10783
|
area:
|
|
10784
10784
|
type: number
|
|
10785
|
-
|
|
10785
|
+
AnalyticsStandardEventFields:
|
|
10786
10786
|
type: object
|
|
10787
10787
|
properties:
|
|
10788
10788
|
visitorId:
|
|
@@ -10834,7 +10834,7 @@ components:
|
|
|
10834
10834
|
type: object
|
|
10835
10835
|
properties:
|
|
10836
10836
|
sessionId:
|
|
10837
|
-
|
|
10837
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
10838
10838
|
eventType:
|
|
10839
10839
|
$ref: "#/components/schemas/AnalyticsEventType"
|
|
10840
10840
|
collectionId:
|
|
@@ -10873,7 +10873,7 @@ components:
|
|
|
10873
10873
|
type: object
|
|
10874
10874
|
properties:
|
|
10875
10875
|
sessionId:
|
|
10876
|
-
|
|
10876
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
10877
10877
|
eventType:
|
|
10878
10878
|
$ref: "#/components/schemas/AnalyticsEventType"
|
|
10879
10879
|
collectionId:
|
|
@@ -11048,11 +11048,11 @@ components:
|
|
|
11048
11048
|
items:
|
|
11049
11049
|
type: string
|
|
11050
11050
|
sessionId:
|
|
11051
|
-
|
|
11051
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
11052
11052
|
sessionIds:
|
|
11053
11053
|
type: array
|
|
11054
11054
|
items:
|
|
11055
|
-
|
|
11055
|
+
$ref: "#/components/schemas/AnalyticsSessionId"
|
|
11056
11056
|
country:
|
|
11057
11057
|
type: string
|
|
11058
11058
|
countries:
|