@iann29/rastro 0.4.0 → 0.6.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 +146 -24
- package/agent/integration.md +66 -29
- package/agent/manifest.json +19 -8
- package/agent/manifest.schema.json +28 -9
- package/dist/client/federation.d.ts +38 -8
- package/dist/client/federation.d.ts.map +1 -1
- package/dist/client/federation.js +18 -1
- package/dist/client/federation.js.map +1 -1
- package/dist/client/identity.d.ts +11 -0
- package/dist/client/identity.d.ts.map +1 -0
- package/dist/client/identity.js +123 -0
- package/dist/client/identity.js.map +1 -0
- package/dist/client/index.d.ts +501 -11
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +220 -4
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +8 -0
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +158 -1
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/constants.d.ts +2 -0
- package/dist/component/constants.d.ts.map +1 -1
- package/dist/component/constants.js +7 -0
- package/dist/component/constants.js.map +1 -1
- package/dist/component/coverage.d.ts +1 -0
- package/dist/component/coverage.d.ts.map +1 -1
- package/dist/component/coverage.js +6 -1
- package/dist/component/coverage.js.map +1 -1
- package/dist/component/eventStore.d.ts +2 -0
- package/dist/component/eventStore.d.ts.map +1 -1
- package/dist/component/http.d.ts.map +1 -1
- package/dist/component/http.js +51 -1
- package/dist/component/http.js.map +1 -1
- package/dist/component/ingest.d.ts +2 -0
- package/dist/component/ingest.d.ts.map +1 -1
- package/dist/component/ingest.js +72 -22
- package/dist/component/ingest.js.map +1 -1
- package/dist/component/origin.d.ts +70 -0
- package/dist/component/origin.d.ts.map +1 -0
- package/dist/component/origin.js +230 -0
- package/dist/component/origin.js.map +1 -0
- package/dist/component/people.d.ts +79 -0
- package/dist/component/people.d.ts.map +1 -0
- package/dist/component/people.js +249 -0
- package/dist/component/people.js.map +1 -0
- package/dist/component/platforms.d.ts +33 -0
- package/dist/component/platforms.d.ts.map +1 -0
- package/dist/component/platforms.js +328 -0
- package/dist/component/platforms.js.map +1 -0
- package/dist/component/reports.d.ts +35 -74
- package/dist/component/reports.d.ts.map +1 -1
- package/dist/component/reports.js +59 -14
- package/dist/component/reports.js.map +1 -1
- package/dist/component/sanitize.d.ts +5 -0
- package/dist/component/sanitize.d.ts.map +1 -1
- package/dist/component/sanitize.js +33 -1
- package/dist/component/sanitize.js.map +1 -1
- package/dist/component/schema.d.ts +101 -7
- package/dist/component/schema.js +45 -1
- package/dist/component/schema.js.map +1 -1
- package/dist/component/trackedLinks.d.ts +91 -0
- package/dist/component/trackedLinks.d.ts.map +1 -0
- package/dist/component/trackedLinks.js +314 -0
- package/dist/component/trackedLinks.js.map +1 -0
- package/dist/component/useragent.d.ts +6 -0
- package/dist/component/useragent.d.ts.map +1 -1
- package/dist/component/useragent.js +9 -0
- package/dist/component/useragent.js.map +1 -1
- package/dist/component/validators.d.ts +101 -11
- package/dist/component/validators.d.ts.map +1 -1
- package/dist/component/validators.js +62 -1
- package/dist/component/validators.js.map +1 -1
- package/dist/component/visitors.d.ts +38 -2
- package/dist/component/visitors.d.ts.map +1 -1
- package/dist/component/visitors.js +162 -42
- package/dist/component/visitors.js.map +1 -1
- package/dist/react/index.d.ts +9 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +36 -5
- package/dist/react/index.js.map +1 -1
- package/dist/tracker/generated.d.ts +6 -6
- package/dist/tracker/generated.d.ts.map +1 -1
- package/dist/tracker/generated.js +6 -6
- package/dist/tracker/generated.js.map +1 -1
- package/dist/tracker/tracker.d.ts +3 -1
- package/dist/tracker/tracker.d.ts.map +1 -1
- package/dist/tracker/tracker.js +56 -5
- package/dist/tracker/tracker.js.map +1 -1
- package/dist/tracker.min.js +1 -1
- package/docs/federation.md +24 -0
- package/docs/identity.md +307 -0
- package/docs/upgrading.md +190 -19
- package/llms.txt +11 -2
- package/package.json +5 -3
- package/src/component/_generated/api.ts +8 -0
- package/src/component/_generated/component.ts +251 -1
- package/src/component/constants.ts +7 -0
- package/src/component/coverage.ts +7 -1
- package/src/component/http.ts +56 -1
- package/src/component/ingest.ts +100 -28
- package/src/component/origin.ts +273 -0
- package/src/component/people.ts +321 -0
- package/src/component/platforms.ts +359 -0
- package/src/component/reports.ts +84 -13
- package/src/component/sanitize.ts +39 -1
- package/src/component/schema.ts +53 -0
- package/src/component/trackedLinks.ts +384 -0
- package/src/component/useragent.ts +11 -0
- package/src/component/validators.ts +120 -0
- package/src/component/visitors.ts +232 -55
- package/src/tracker/generated.ts +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/tracker/tracker.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/tracker/tracker.ts"],"names":[],"mappings":"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"}
|
package/dist/tracker.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{const
|
|
1
|
+
(()=>{const t=document.currentScript,e=t?.dataset.site,i=t?.dataset.endpoint||t?.src&&new URL("events",t.src).href;if(!e||!i)return;const n=()=>crypto.randomUUID?.()||Math.random()+"",r=new URLSearchParams(location.search),s=r.get("ref")?.slice(0,64);let o;for(const t of["source","medium","campaign","term","content"]){const e=r.get("utm_"+t)?.slice(0,64);e&&((o??={})["utm_"+t]=e)}const a="gclid gbraid wbraid msclkid ttclid twclid li_fat_id ScCid rdt_cid dclid epik srsltid mc_cid mc_eid _hsenc igsh igshid fbclid".split(" ").filter(t=>r.has(t)).slice(0,8);let c,d,l,h,f=t.dataset.visitor||"",p=Boolean(f);try{f||=localStorage._rv||=n()}catch{}try{d=sessionStorage,l=d._r,c=d._ri==f&&d._rt,h=s||d._a,h&&(d._a=h),o||=d._u&&JSON.parse(d._u),o&&(d._u=JSON.stringify(o))}catch{h=s}let v,g=0;const u=[];let m=document.referrer.split("/",3).join("/")||void 0;const _=t=>{const n=u.splice(0,50);if(!n.length)return;const r=()=>new Blob([JSON.stringify({siteId:e,events:n,sentAt:Date.now()})]);let s=r();for(;s.size>64e3&&n.length>1;)u.unshift(n.pop()),s=r();t&&navigator.sendBeacon(i,s)||fetch(i,{method:"POST",body:s,keepalive:1}).catch(()=>{}),u.length&&_(t)},y=(t,e,i)=>{const r=Date.now(),s=r-c;c=r,s<18e5||(l=n(),"pageview"!=t&&(S="",w()));try{d._r=l,d._ri=f,d._rt=r}catch{}u.push({eventId:`${l}.${r.toString(36)}.${g}`,sessionId:l,visitorId:f||l,type:t,name:e,path:location.pathname.slice(0,256),referrer:m,timestamp:r,sequence:g++,affiliateSlug:h,...i}),clearTimeout(v),v=setTimeout(_,1200)};let S;const w=()=>{const t=location.pathname;t!=S&&(S=t,y("pageview",void 0,{properties:o,clid:a.length?a:void 0}))};window.rastro=(e,i,r)=>{if("context"==e)return{sessionId:l,visitorId:f||l,identified:p};if("identify"==e||"reset"==e){if("identify"==e&&(!i||i.length>128||!/^[A-Za-z0-9][A-Za-z0-9_.:-]*$/.test(i)))return;if("identify"==e&&i==f)return;_();const r="reset"==e||p;if(p="identify"==e,f="identify"==e?i:n(),t.dataset.visitor="identify"==e?f:"",r){h=void 0,o=void 0,m=void 0,a.length=0;try{"reset"==e&&(localStorage._rv=f),d._a="",d._u=""}catch{}}c=0,g=0,S="",w()}"event"==e&&y("custom",`${i||"event"}`.slice(0,80),r&&JSON.stringify(r).length>2e4?void 0:{properties:r})},document.addEventListener("click",t=>{const e=t.target?.closest("a,button,[data-rastro-event]");if(!e)return;const i=e.dataset.rastroEvent,n=e.href,r=n&&new URL(n),s=/^https?:$/.test(r?.protocol),o=s&&r.origin!=location.origin;y(i?"custom":o?"outbound":"click",i,{target:(e.dataset.rastroLabel||e.innerText||e.tagName).slice(0,64),href:s?((o?r.origin:"")+r.pathname).slice(0,256):void 0})},1);for(const t of["pushState","replaceState"]){const e=history[t];history[t]=(...t)=>{e.apply(history,t),w()}}addEventListener("popstate",w);let b=0;const I=()=>{y("heartbeat"),_()},L=()=>{b&&(clearInterval(b),b=0,y("leave"),_(1))},E=()=>{document.hidden?L():b||(I(),b=setInterval(I,2e4))};addEventListener("pagehide",L),addEventListener("pageshow",E),document.addEventListener("visibilitychange",E),b=setInterval(I,2e4),w(),E()})();
|
package/docs/federation.md
CHANGED
|
@@ -291,6 +291,8 @@ export const {
|
|
|
291
291
|
overview,
|
|
292
292
|
liveVisitors,
|
|
293
293
|
getSession,
|
|
294
|
+
getVisitorProfile,
|
|
295
|
+
listPeople,
|
|
294
296
|
revenueSummary,
|
|
295
297
|
listSessions,
|
|
296
298
|
sessionJourney,
|
|
@@ -405,3 +407,25 @@ plane write. The customer operator provisions the authoritative grant through an
|
|
|
405
407
|
internal or host-admin mutation. For immediate revocation, revoke that local
|
|
406
408
|
grant before revoking the central connection; otherwise an already-issued token
|
|
407
409
|
remains valid until its ten-minute expiry.
|
|
410
|
+
|
|
411
|
+
## Identified visitor profiles
|
|
412
|
+
|
|
413
|
+
The optional `visitorProfiles` capability adds
|
|
414
|
+
`getVisitorProfile({siteId, visitorId})`. It resolves pre-login aliases and
|
|
415
|
+
returns `{visitorId, name?, email?, attributes?, identifiedAt, updatedAt}` or
|
|
416
|
+
null. `liveVisitors`, `listSessions` and `getSession` include an optional
|
|
417
|
+
`profile` for identified people. These attributes require `analytics:read`;
|
|
418
|
+
public live rows remove `profile`, and public tokens cannot call
|
|
419
|
+
`getVisitorProfile`. Older hosts work without this capability. Profile writes
|
|
420
|
+
stay in the product backend, outside federation. See
|
|
421
|
+
[identity integration](identity.md) for Better Auth, custom auth and external
|
|
422
|
+
servers.
|
|
423
|
+
|
|
424
|
+
The optional `people` capability adds
|
|
425
|
+
`listPeople({siteId, filter?, paginationOpts})`: a directory of current
|
|
426
|
+
profiles, independent of the report period. It supports a name/email/ID prefix
|
|
427
|
+
or an exact typed attribute value, with up to 50 rows per page. Cursors belong
|
|
428
|
+
to one site and filter. This query requires `analytics:read`; public tokens
|
|
429
|
+
cannot list people. Profile writes and the bounded `backfillVisitorProfiles`
|
|
430
|
+
upgrade remain host-authorized operations outside federation. See
|
|
431
|
+
[the directory contract and upgrade steps](identity.md#project-defined-attributes-and-the-people-directory).
|
package/docs/identity.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# Identify people with any authentication
|
|
2
|
+
|
|
3
|
+
Available in `@iann29/rastro@0.6.0` and later. Upgrade and deploy the host
|
|
4
|
+
before using these APIs in the browser or enabling the directory in federation.
|
|
5
|
+
|
|
6
|
+
Rastro connects a person's name and email to their visits, actions and
|
|
7
|
+
conversions. The product's backend resolves the signed-in user; Rastro does not
|
|
8
|
+
require Better Auth or a particular auth provider. Profiles and events stay in
|
|
9
|
+
the product's Rastro component.
|
|
10
|
+
|
|
11
|
+
## Shared contract
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
const profile = await analytics.identifyVisitor(ctx, {
|
|
15
|
+
siteId,
|
|
16
|
+
visitorId: user.analyticsId,
|
|
17
|
+
previousVisitorId, // optional: the browser's pre-login visitor ID
|
|
18
|
+
name: user.name,
|
|
19
|
+
email: user.email,
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This is a trusted server call. Resolve `user` and authorize `siteId` on the
|
|
24
|
+
server. The result is `{ visitorId, name?, email?, identifiedAt, updatedAt }`.
|
|
25
|
+
Use the returned `visitorId` in the tracker. A repeated call is idempotent;
|
|
26
|
+
omitted attributes keep their values, and `name: null` or `email: null` removes
|
|
27
|
+
that attribute. Names are bounded to 160 characters and emails to 320.
|
|
28
|
+
|
|
29
|
+
Choose one stable ID per product user. Existing tracker IDs can be reused
|
|
30
|
+
unchanged. `visitorIdForUser(userId)` converts arbitrary provider IDs into a
|
|
31
|
+
stable tracker-compatible ID. Use your product's user primary key when auth
|
|
32
|
+
providers can change. With raw Convex JWT identities, use the complete
|
|
33
|
+
`tokenIdentifier`, which includes the issuer, rather than `subject` alone. Do
|
|
34
|
+
not use email as the identity key: it can change or be shared.
|
|
35
|
+
|
|
36
|
+
## Project-defined attributes and the people directory
|
|
37
|
+
|
|
38
|
+
No user table, workspace model, auth provider or business field is required.
|
|
39
|
+
Keep your product's existing user key and map its current attributes on the
|
|
40
|
+
server, in the same resolver used above:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
return {
|
|
44
|
+
siteId: authorizedSiteId,
|
|
45
|
+
visitorId: user.analyticsId,
|
|
46
|
+
name: user.name,
|
|
47
|
+
email: user.email,
|
|
48
|
+
attributes: { language: "pt-BR", level: 3, enrolled: true },
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
An education app may send `level` and `enrolled`; a marketplace may send
|
|
53
|
+
`seller` and `orders`; a SaaS may send `plan` and `seats`. These are examples,
|
|
54
|
+
not built-in columns. Attribute values are strings, finite numbers or booleans.
|
|
55
|
+
Dates can be ISO strings. Attributes describe current state; put historical
|
|
56
|
+
context on the event's existing `properties` instead. Nested objects and arrays
|
|
57
|
+
are not supported in this first version.
|
|
58
|
+
|
|
59
|
+
Updates merge keys. Omitted keys are preserved; a null value deletes one key:
|
|
60
|
+
`attributes: { level: 4, enrolled: null }`. Empty strings, zero and false are
|
|
61
|
+
valid values. Each profile allows 32 keys, keys of up to 64 ASCII characters
|
|
62
|
+
starting with a letter (`A-Z`, `a-z`, digits, `.`, `_`, `-`), strings up to 512
|
|
63
|
+
characters, and at most 4096 UTF-8 bytes for the complete attribute map. Invalid
|
|
64
|
+
updates fail atomically. These limits also bound read and index costs.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const page = await analytics.listPeople(ctx, {
|
|
68
|
+
siteId: authorizedSiteId,
|
|
69
|
+
filter: { field: "attribute", key: "level", value: 3 },
|
|
70
|
+
paginationOpts: { cursor: null, numItems: 25 },
|
|
71
|
+
});
|
|
72
|
+
// page: { page: Person[], isDone, continueCursor }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The optional filter is either one exact typed attribute match, or a prefix:
|
|
76
|
+
`{ field: "name" | "email" | "visitorId", prefix: "Maria" }`. Names and emails
|
|
77
|
+
use case-insensitive Unicode-normalized prefixes; IDs preserve case. Text `"3"`
|
|
78
|
+
differs from number `3`. Each page uses the site's database indexes. Pages allow
|
|
79
|
+
1–50 people; pass `continueCursor` back as the next cursor. Cursors are scoped
|
|
80
|
+
to the site and filter. Clear the cursor when either changes. The directory
|
|
81
|
+
includes all identified profiles, independently of the dashboard's event date
|
|
82
|
+
range.
|
|
83
|
+
|
|
84
|
+
Re-export `listPeople` from `exposeFederatedAnalyticsApi` alongside
|
|
85
|
+
`getVisitorProfile`. The optional `people` capability enables the **Pessoas**
|
|
86
|
+
dashboard view. Existing hosts stay connected without it. People and attributes
|
|
87
|
+
are available only to authorized readers of that site; public links cannot list
|
|
88
|
+
them. The local `exposeAnalyticsApi` authorizer receives `visitor.list`.
|
|
89
|
+
|
|
90
|
+
For profiles created by the earlier unreleased identity implementation, call
|
|
91
|
+
`analytics.backfillVisitorProfiles(ctx, { siteId })` from a site-admin mutation
|
|
92
|
+
or action after deployment. Each call updates at most 64 profiles and returns
|
|
93
|
+
`{ updated, isDone }`; schedule another bounded call if `isDone` is false. The
|
|
94
|
+
local API wrapper uses the `visitor.index` authorization operation; it is not
|
|
95
|
+
exposed through federation. The example `analytics.ts` exports an
|
|
96
|
+
owner-authorized wrapper. Backfill preserves identity timestamps and is safe to
|
|
97
|
+
retry. Until it finishes, name/email search refuses to return partial results;
|
|
98
|
+
unfiltered and ID listings remain available. Fresh installations need no
|
|
99
|
+
backfill.
|
|
100
|
+
|
|
101
|
+
## Funnels across identification
|
|
102
|
+
|
|
103
|
+
Funnel progress resolves the canonical person and their pre-login aliases. Steps
|
|
104
|
+
recorded before login continue after login, including queued events under an
|
|
105
|
+
already-linked browser ID. Repeated identification and another tab do not start
|
|
106
|
+
another attempt inside the active conversion window. The original events and
|
|
107
|
+
their IDs stay intact. When multiple aliases already have progress, the furthest
|
|
108
|
+
attempt inside its conversion window takes precedence; expired attempts restart
|
|
109
|
+
only on the first step, as before.
|
|
110
|
+
|
|
111
|
+
Linking does not retroactively recompute already-counted funnel attempts or
|
|
112
|
+
other historical aggregates. Events must still arrive in step order; this change
|
|
113
|
+
does not add late-event replay.
|
|
114
|
+
|
|
115
|
+
## Convex with Better Auth
|
|
116
|
+
|
|
117
|
+
In the product's `convex/analyticsIdentity.ts`, use its existing auth component:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { Rastro } from "@iann29/rastro";
|
|
121
|
+
import { components } from "./_generated/api";
|
|
122
|
+
import type { MutationCtx } from "./_generated/server";
|
|
123
|
+
import { authComponent } from "./auth";
|
|
124
|
+
|
|
125
|
+
const analytics = new Rastro(components.rastroAnalytics);
|
|
126
|
+
|
|
127
|
+
export const identifyVisitor = analytics.identifyVisitorMutation({
|
|
128
|
+
resolveUser: async (ctx: MutationCtx) => {
|
|
129
|
+
const user = await authComponent.safeGetAuthUser(ctx);
|
|
130
|
+
if (!user) return null;
|
|
131
|
+
return {
|
|
132
|
+
siteId: "YOUR_PRODUCT_SITE_ID",
|
|
133
|
+
visitorId: user._id,
|
|
134
|
+
name: user.name,
|
|
135
|
+
email: user.email,
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`safeGetAuthUser` checks the Better Auth session. Rastro adds no Better Auth
|
|
142
|
+
runtime dependency. With multiple workspaces, resolve the site from the user's
|
|
143
|
+
authorized workspace in this callback instead of accepting a site from the
|
|
144
|
+
browser.
|
|
145
|
+
|
|
146
|
+
## Convex with custom auth or another JWT provider
|
|
147
|
+
|
|
148
|
+
Use the same mutation with your own user lookup:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { Rastro, visitorIdForUser } from "@iann29/rastro";
|
|
152
|
+
import { components } from "./_generated/api";
|
|
153
|
+
import type { MutationCtx } from "./_generated/server";
|
|
154
|
+
|
|
155
|
+
const analytics = new Rastro(components.rastroAnalytics);
|
|
156
|
+
|
|
157
|
+
export const identifyVisitor = analytics.identifyVisitorMutation({
|
|
158
|
+
resolveUser: async (ctx: MutationCtx) => {
|
|
159
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
160
|
+
if (!identity) return null;
|
|
161
|
+
return {
|
|
162
|
+
siteId: "YOUR_PRODUCT_SITE_ID",
|
|
163
|
+
visitorId: await visitorIdForUser(identity.tokenIdentifier),
|
|
164
|
+
name: identity.name,
|
|
165
|
+
email: identity.email,
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
For custom database-backed sessions, replace the resolver body with the
|
|
172
|
+
product's existing authenticated-user lookup. Returning `null` refuses the
|
|
173
|
+
request. The public mutation accepts only `previousVisitorId`; user ID, name,
|
|
174
|
+
email and site scope come from the resolver.
|
|
175
|
+
|
|
176
|
+
## React and browser lifecycle
|
|
177
|
+
|
|
178
|
+
After the login has established the backend session:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
const identifyVisitor = useMutation(api.analyticsIdentity.identifyVisitor);
|
|
182
|
+
const rastro = useRastro();
|
|
183
|
+
|
|
184
|
+
async function identifyAfterLogin() {
|
|
185
|
+
const before = rastro.context();
|
|
186
|
+
const profile = await identifyVisitor({
|
|
187
|
+
previousVisitorId:
|
|
188
|
+
before && !before.identified ? before.visitorId : undefined,
|
|
189
|
+
});
|
|
190
|
+
rastro.identify(profile.visitorId);
|
|
191
|
+
// Keep this ID in your auth state and pass it to RastroScript on later loads.
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function signOut() {
|
|
195
|
+
await yourAuth.signOut();
|
|
196
|
+
rastro.reset();
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Import `useRastro` and `RastroScript` from `@iann29/rastro/react`; use your
|
|
201
|
+
app's existing `useMutation` from `convex/react`. Call identification again
|
|
202
|
+
after restoring a logged-in session. Discard a pending identification response
|
|
203
|
+
if the auth session has changed before it returns.
|
|
204
|
+
|
|
205
|
+
`<RastroScript visitorId={analyticsVisitorId} ... />` also synchronizes ID
|
|
206
|
+
changes and logout (`visitorId` becoming undefined), including a delayed script
|
|
207
|
+
load. Mount one tracker per page. Prefer one lifecycle owner: either the prop or
|
|
208
|
+
the explicit commands, so a logout does not reset twice.
|
|
209
|
+
|
|
210
|
+
For another frontend framework, use the equivalent commands:
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
const before = window.rastro?.("context");
|
|
214
|
+
// Authenticate with your product backend, then obtain its Rastro profile.
|
|
215
|
+
window.rastro?.("identify", profile.visitorId);
|
|
216
|
+
// After logout:
|
|
217
|
+
window.rastro?.("reset");
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`context` returns `{ visitorId, sessionId, identified }`. The browser commands
|
|
221
|
+
change the tracker ID, not the stored profile. Identification flushes queued
|
|
222
|
+
events under their original ID and opens a new session without a page reload.
|
|
223
|
+
The first login retains acquisition context. Logout creates a new browser
|
|
224
|
+
visitor; logout and direct account switches clear the previous person's
|
|
225
|
+
campaign/referral context. `identify` and `reset` from `useRastro` return false
|
|
226
|
+
when the deferred tracker is not ready; the `visitorId` prop handles that case.
|
|
227
|
+
|
|
228
|
+
## Other backends: authenticated HTTP
|
|
229
|
+
|
|
230
|
+
Mount an HTTP action on the Convex deployment that owns the Rastro component.
|
|
231
|
+
The external backend can be Node, Python, Go, Rails, or any HTTP client. The
|
|
232
|
+
analytics storage still runs on Convex or Synapse.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
// convex/http.ts — merge into the product's existing router.
|
|
236
|
+
http.route({
|
|
237
|
+
path: "/analytics/identify",
|
|
238
|
+
method: "POST",
|
|
239
|
+
handler: analytics.identifyVisitorHttpAction({
|
|
240
|
+
authorize: async (_ctx, request, siteId) => {
|
|
241
|
+
const key = env.RASTRO_IDENTITY_SERVER_KEY;
|
|
242
|
+
if (
|
|
243
|
+
!key ||
|
|
244
|
+
request.headers.get("authorization") !== `Bearer ${key}` ||
|
|
245
|
+
siteId !== env.RASTRO_IDENTITY_SITE_ID
|
|
246
|
+
) {
|
|
247
|
+
throw new Error("Not authorized");
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Declare the two optional string env vars in `convex/convex.config.ts`. The
|
|
255
|
+
complete router and declarations are in `example/convex/`. Provision a random
|
|
256
|
+
server key and share it only with the authorized backend. If multiple backends
|
|
257
|
+
or sites are served, the authorizer must resolve each credential's site scope.
|
|
258
|
+
Do not expose the key in `VITE_`, `NEXT_PUBLIC_`, or browser code.
|
|
259
|
+
|
|
260
|
+
The external backend first authenticates its own user, then sends:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
const response = await fetch(process.env.RASTRO_IDENTITY_URL!, {
|
|
264
|
+
method: "POST",
|
|
265
|
+
headers: {
|
|
266
|
+
"Content-Type": "application/json",
|
|
267
|
+
Authorization: `Bearer ${process.env.RASTRO_IDENTITY_SERVER_KEY}`,
|
|
268
|
+
},
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
siteId: process.env.RASTRO_IDENTITY_SITE_ID,
|
|
271
|
+
visitorId: user.analyticsId,
|
|
272
|
+
previousVisitorId,
|
|
273
|
+
name: user.name,
|
|
274
|
+
email: user.email,
|
|
275
|
+
}),
|
|
276
|
+
});
|
|
277
|
+
if (!response.ok) throw new Error(`Rastro identify failed: ${response.status}`);
|
|
278
|
+
const profile = await response.json();
|
|
279
|
+
// Return profile.visitorId to the authenticated browser.
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The endpoint accepts at most 8 KiB of JSON, validates the same fields as the SDK
|
|
283
|
+
and sends `Cache-Control: no-store`. Statuses: 200 success, 400 invalid input,
|
|
284
|
+
403 denied credential/site, 404 unknown site, 409 conflicting identity, 413
|
|
285
|
+
oversized body, 415 wrong content type, 429 alias limit, 500 server failure.
|
|
286
|
+
|
|
287
|
+
## Dashboard and existing history
|
|
288
|
+
|
|
289
|
+
Re-export `getVisitorProfile` from `exposeFederatedAnalyticsApi` in the host's
|
|
290
|
+
`convex/rastroFederation.ts`. It is advertised by the optional `visitorProfiles`
|
|
291
|
+
capability. Private live/session reports include a profile when one exists; old
|
|
292
|
+
hosts and unidentified visitors continue to work without it.
|
|
293
|
+
|
|
294
|
+
The dashboard shows names/emails in **Ao vivo** and **Jornadas**, searches those
|
|
295
|
+
attributes within the loaded session records, and opens the person's history for
|
|
296
|
+
the selected site and period. Existing events retain their original ID; the
|
|
297
|
+
identity link resolves them at read time. A profile is keyed by site and
|
|
298
|
+
visitor, with no email-based merging. An identified person cannot be linked into
|
|
299
|
+
another person. Each identity supports the existing limit of ten pre-login
|
|
300
|
+
aliases. Profile attributes persist independently of event retention and can be
|
|
301
|
+
cleared with explicit null updates.
|
|
302
|
+
|
|
303
|
+
Profile reads require a reader's authorization for that site. Public dashboard
|
|
304
|
+
links omit profiles and cannot call `getVisitorProfile`. The tracking endpoint
|
|
305
|
+
continues to accept browser telemetry; an identity label does not turn
|
|
306
|
+
browser-sent events into authenticated business transactions. Record revenue
|
|
307
|
+
through the existing trusted `trackConversion` server API.
|
package/docs/upgrading.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Upgrading Amage Rastro
|
|
2
2
|
|
|
3
|
+
## People, attributes and identity continuity (0.6.0)
|
|
4
|
+
|
|
5
|
+
Install `@iann29/rastro@0.6.0` and deploy the host through its normal workflow.
|
|
6
|
+
|
|
7
|
+
- Additive `visitorProfiles` and `visitorAttributes` storage; no event/session
|
|
8
|
+
rewrite.
|
|
9
|
+
- Attributes are optional project-defined strings, numbers and booleans. Name,
|
|
10
|
+
email and attribute searches use indexes with bounded pagination.
|
|
11
|
+
- `identifyVisitor`, `identifyVisitorMutation` and authenticated
|
|
12
|
+
`identifyVisitorHttpAction` support any backend authentication. Existing
|
|
13
|
+
`linkVisitor` remains available.
|
|
14
|
+
- Re-export `getVisitorProfile` and `listPeople` from federation and refresh the
|
|
15
|
+
connection to advertise `visitorProfiles` and `people`. The dashboard
|
|
16
|
+
tolerates older hosts. Its Pessoas view lists profiles, filters attributes and
|
|
17
|
+
opens history.
|
|
18
|
+
- For profiles created before the directory, call the owner-authorized
|
|
19
|
+
`backfillVisitorProfiles({siteId})` until `isDone` is true (at most 64
|
|
20
|
+
profiles per call). This initializes search fields and attribute indexes;
|
|
21
|
+
timestamps and event history are preserved. Fresh installations need no
|
|
22
|
+
backfill.
|
|
23
|
+
- Funnels continue across linked pre-login and account IDs, including queued
|
|
24
|
+
alias events. Historical aggregates are not recomputed; steps must still
|
|
25
|
+
arrive in order.
|
|
26
|
+
- Map connections between routes in the same column bend around intermediate
|
|
27
|
+
nodes instead of drawing through them.
|
|
28
|
+
- Tracker `identify`/`reset` rotate sessions on login/logout without a reload;
|
|
29
|
+
`context` now includes `identified`. `RastroScript` synchronizes identity
|
|
30
|
+
changes and forwards native load/error events.
|
|
31
|
+
- The reference example's auth entrypoint is now
|
|
32
|
+
`analyticsIdentity:identifyVisitor`; configure its server-owned
|
|
33
|
+
`RASTRO_IDENTITY_SITE_ID`. Its optional HTTP route also requires
|
|
34
|
+
`RASTRO_IDENTITY_SERVER_KEY`.
|
|
35
|
+
- The tracker budget is now below 1,700 bytes gzip including identity switching.
|
|
36
|
+
|
|
37
|
+
See [the complete identity guide](identity.md) for integration and deployment
|
|
38
|
+
order.
|
|
39
|
+
|
|
3
40
|
Pin exact versions, read the changelog, and rehearse upgrades against a
|
|
4
41
|
non-production snapshot before changing a maintained deployment. `0.1.0` is the
|
|
5
42
|
first release without a prerelease tag; the alphas below it stay documented for
|
|
@@ -7,30 +44,161 @@ hosts still on them.
|
|
|
7
44
|
|
|
8
45
|
## Release matrix
|
|
9
46
|
|
|
10
|
-
| Current state | Required path
|
|
11
|
-
| ----------------------------------------------------- |
|
|
12
|
-
| Fresh deployment | Install the intended release directly
|
|
13
|
-
| `0.1.0-alpha.0` with maintained data | Install `0.1.0-alpha.1` first and wait for staged visitor-index backfills
|
|
14
|
-
| `0.1.0-alpha.1` | Wait for staged visitor-index backfills, then install `alpha.2`
|
|
15
|
-
| `0.1.0-alpha.2` with legacy `events` rows | Stay on `alpha.2` and run/resume migration
|
|
16
|
-
| `0.1.0-alpha.3` fresh/canonical deployment | Rehearse the next alpha normally
|
|
17
|
-
| `0.1.0-alpha.3` through `alpha.5` with canonical data | Install `0.1.0-alpha.6` directly; Web Vitals tables are additive
|
|
18
|
-
| `0.1.0-alpha.6` | Install `0.1.0-alpha.7` directly; no schema change
|
|
19
|
-
| `0.1.0-alpha.7` | Install `0.1.0-alpha.8` directly; site map tables are additive; re-export `siteMap`
|
|
20
|
-
| `0.1.0-alpha.8` | Install `0.1.0-alpha.10` directly; no schema change; the tracker changes
|
|
21
|
-
| `0.1.0-alpha.9` | Install `0.1.0-alpha.10` directly; `alpha.9` is deprecated — it rejected its own leave beacons
|
|
22
|
-
| `0.1.0-alpha.10` | Install `0.1.0-alpha.12` directly; new tables and fields are additive; re-export the configure functions to opt in
|
|
23
|
-
| `0.1.0-alpha.11` | Install `0.1.0-alpha.12` directly; same code, the package now ships `src/tracker/generated.ts`
|
|
24
|
-
| `0.1.0-alpha.12` | Install `0.1.0` directly; every schema change is an optional field or a new table; add `analytics:public` to a grant only to allow public links
|
|
25
|
-
| `0.1.0` | Install `0.2.0` directly; add the optional host callback and grant version to enable transfers
|
|
26
|
-
| `0.2.0` | Install `0.3.0` directly; no new table; export `getSession` and `revenueSummary` from the federation module
|
|
27
|
-
| `0.3.0` | Install `0.4.0` directly; no re-export; the deploy rebuilds the `reportRollupQueue` index and the tracker changes
|
|
28
|
-
|
|
|
47
|
+
| Current state | Required path | Success condition |
|
|
48
|
+
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
|
|
49
|
+
| Fresh deployment | Install the intended release directly | Component deploys and `/rastro/health` succeeds |
|
|
50
|
+
| `0.1.0-alpha.0` with maintained data | Install `0.1.0-alpha.1` first and wait for staged visitor-index backfills | Every staged index reports complete before installing `alpha.2` |
|
|
51
|
+
| `0.1.0-alpha.1` | Wait for staged visitor-index backfills, then install `alpha.2` | Backfills complete before active readers deploy |
|
|
52
|
+
| `0.1.0-alpha.2` with legacy `events` rows | Stay on `alpha.2` and run/resume migration | Durable success plus empty source |
|
|
53
|
+
| `0.1.0-alpha.3` fresh/canonical deployment | Rehearse the next alpha normally | Schema, reports, tracker, and retention checks pass |
|
|
54
|
+
| `0.1.0-alpha.3` through `alpha.5` with canonical data | Install `0.1.0-alpha.6` directly; Web Vitals tables are additive | Schema deploys and `/rastro/health` reports `webVitals: "optIn"` |
|
|
55
|
+
| `0.1.0-alpha.6` | Install `0.1.0-alpha.7` directly; no schema change | `GET /rastro/tracker.js` contains `sentAt` |
|
|
56
|
+
| `0.1.0-alpha.7` | Install `0.1.0-alpha.8` directly; site map tables are additive; re-export `siteMap` | `/rastro/health` reports `siteMap: "dailyRollup"` |
|
|
57
|
+
| `0.1.0-alpha.8` | Install `0.1.0-alpha.10` directly; no schema change; the tracker changes | `/rastro/health` reports `liveDepartures: "leaveBeacon"` |
|
|
58
|
+
| `0.1.0-alpha.9` | Install `0.1.0-alpha.10` directly; `alpha.9` is deprecated — it rejected its own leave beacons | The final page-close `POST /rastro/events` returns 200 |
|
|
59
|
+
| `0.1.0-alpha.10` | Install `0.1.0-alpha.12` directly; new tables and fields are additive; re-export the configure functions to opt in | `/rastro/health` reports `tracker.version: "0.1.0-alpha.12"` |
|
|
60
|
+
| `0.1.0-alpha.11` | Install `0.1.0-alpha.12` directly; same code, the package now ships `src/tracker/generated.ts` | A `convex/` test importing `@iann29/rastro/test` typechecks on push |
|
|
61
|
+
| `0.1.0-alpha.12` | Install `0.1.0` directly; every schema change is an optional field or a new table; add `analytics:public` to a grant only to allow public links | `/rastro/health` reports `tracker.version: "0.1.0"` |
|
|
62
|
+
| `0.1.0` | Install `0.2.0` directly; add the optional host callback and grant version to enable transfers | Health reports `0.2.0`; opted-in connectors advertise `transfer` |
|
|
63
|
+
| `0.2.0` | Install `0.3.0` directly; no new table; export `getSession` and `revenueSummary` from the federation module | Health reports `0.3.0`; the manifest lists `sessionDetails` |
|
|
64
|
+
| `0.3.0` | Install `0.4.0` directly; no re-export; the deploy rebuilds the `reportRollupQueue` index and the tracker changes | Health reports `0.4.0`; a hidden tab leaves **Ao vivo** in ~10 s |
|
|
65
|
+
| `0.4.0` | Install `0.5.0` directly; every schema change is an optional field or a new table; export `listTrackedLinks`, `createTrackedLink`, `updateTrackedLink` and `deleteTrackedLink` from the federation module; reverify — the manifest advertises `trackedLinks` | Health reports `0.5.0`; the manifest lists `trackedLinks` |
|
|
66
|
+
| `0.5.0` | Install `0.6.0`; export `listPeople` and `getVisitorProfile`, deploy, and reverify. Use the host identity resolver to populate profiles. | Health reports `0.6.0`; the manifest lists `people` and `visitorProfiles` |
|
|
67
|
+
| Any release whose packed declarations lack federation | Stop and request an eligible exact registry release | Packed declarations contain the federation exports |
|
|
29
68
|
|
|
30
69
|
Do not upgrade a populated legacy deployment directly to a release that removes
|
|
31
70
|
the `events` table. Schema acceptance alone does not prove that telemetry was
|
|
32
71
|
migrated.
|
|
33
72
|
|
|
73
|
+
## Origins and tracked links (0.5.0)
|
|
74
|
+
|
|
75
|
+
Install `@iann29/rastro@0.5.0` and deploy the host through its normal workflow.
|
|
76
|
+
Every schema change is an optional field or a new table, so no staged phase and
|
|
77
|
+
no backfill are needed. Then add the four tracked-link functions to the
|
|
78
|
+
destructure in `convex/rastroFederation.ts`:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
export const {
|
|
82
|
+
transferConnection,
|
|
83
|
+
manifest,
|
|
84
|
+
connectionStatus,
|
|
85
|
+
listSites,
|
|
86
|
+
overview,
|
|
87
|
+
liveVisitors,
|
|
88
|
+
getSession,
|
|
89
|
+
revenueSummary,
|
|
90
|
+
listSessions,
|
|
91
|
+
sessionJourney,
|
|
92
|
+
listConversions,
|
|
93
|
+
visitorJourney,
|
|
94
|
+
goalsReport,
|
|
95
|
+
funnelsReport,
|
|
96
|
+
affiliatesReport,
|
|
97
|
+
vitalsReport,
|
|
98
|
+
siteMap,
|
|
99
|
+
dataCoverage,
|
|
100
|
+
siteSettings,
|
|
101
|
+
updateSite,
|
|
102
|
+
listGoals,
|
|
103
|
+
upsertGoal,
|
|
104
|
+
removeGoal,
|
|
105
|
+
listFunnels,
|
|
106
|
+
upsertFunnel,
|
|
107
|
+
removeFunnel,
|
|
108
|
+
listAffiliates,
|
|
109
|
+
upsertAffiliate,
|
|
110
|
+
removeAffiliate,
|
|
111
|
+
retentionStatus,
|
|
112
|
+
setRetentionPolicy,
|
|
113
|
+
disableRetentionPolicy,
|
|
114
|
+
listTrackedLinks,
|
|
115
|
+
createTrackedLink,
|
|
116
|
+
updateTrackedLink,
|
|
117
|
+
deleteTrackedLink,
|
|
118
|
+
} = federated;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Deploy again, then open **Conexões** and click **Verificar novamente** so the
|
|
122
|
+
control plane records the `trackedLinks` capability. Listing links needs only a
|
|
123
|
+
reader; creating, changing and deleting them need `analytics:configure` in both
|
|
124
|
+
the token and the local grant, like goals and affiliates. A host that skips the
|
|
125
|
+
re-export keeps working: the connector simply does not advertise the capability,
|
|
126
|
+
and the dashboard's **Links** tab says what is missing.
|
|
127
|
+
|
|
128
|
+
What reports show differently:
|
|
129
|
+
|
|
130
|
+
- **Fontes in three levels.** Visão geral's flat "Origens" list becomes
|
|
131
|
+
**Fontes**: the channel a session arrived by, the platform inside it, and the
|
|
132
|
+
raw hosts inside that. A host outside the classifier's table lands under
|
|
133
|
+
Referência › Outros.
|
|
134
|
+
- **Sessions from before the upgrade** are classified on read from what they
|
|
135
|
+
kept, marked `evidence: "legado"` (`legacy` in the API), and never enter
|
|
136
|
+
`topPlatforms`, `topChannels` or `topEvidence`. Nothing is backfilled.
|
|
137
|
+
- **Classificado desde.** `dataCoverage`'s new `origin` dataset says from when a
|
|
138
|
+
site carries origins — its first ingest on this release plus the rollup delay
|
|
139
|
+
— and the caption reads "Classificado desde"; it says nothing rather than
|
|
140
|
+
guessing when it cannot read the date.
|
|
141
|
+
- **One rule decides.** A declared `utm_source`, then a click-ID name, then the
|
|
142
|
+
referrer host, then the in-app browser, then an affiliate `ref`. So a landing
|
|
143
|
+
with `fbclid` alone is Meta by click ID, and nothing at all — the only way to
|
|
144
|
+
be `direct`. WhatsApp, Telegram, SMS and native e-mail apps stay `direct`
|
|
145
|
+
unless a tracked link or a UTM proves them.
|
|
146
|
+
- **Attribution quality.** A strip above the tree reads `topEvidence`: how much
|
|
147
|
+
of the traffic a UTM, a click ID, a referrer, an in-app browser or an
|
|
148
|
+
affiliate proved, and how much proves nothing.
|
|
149
|
+
- **`topPlatforms` values** are the platform id alone when the session arrived
|
|
150
|
+
by that platform's default channel and `platform@channel` when it did not
|
|
151
|
+
(`google@paid_search`); `splitPlatformDimension` reads the pair back.
|
|
152
|
+
`source`, `topSources`, `topCampaigns` and `topMediums` are unchanged.
|
|
153
|
+
|
|
154
|
+
Tracked links:
|
|
155
|
+
|
|
156
|
+
- `GET /rastro/l/<slug>` answers `302` with `Cache-Control: no-store` to the
|
|
157
|
+
link's destination, appending `utm_source` (the platform), `utm_medium` (the
|
|
158
|
+
channel), `utm_campaign` (the campaign, or the slug when the link has none)
|
|
159
|
+
and `utm_content` (the slug). The destination's own query stays, and a `utm_*`
|
|
160
|
+
key it already carries is never overridden. An unknown or disabled slug
|
|
161
|
+
answers `404` in plain text.
|
|
162
|
+
- **No open redirect.** A destination must be an absolute `http(s)` URL without
|
|
163
|
+
credentials on one of the site's domains (exact, or a `*.` pattern). The rule
|
|
164
|
+
is checked when the link is created or changed and again on every click, so a
|
|
165
|
+
domain removed from the site stops redirecting at once.
|
|
166
|
+
- **Bots.** A self-declared bot, the WhatsApp, Facebook and Telegram link
|
|
167
|
+
previews included, is still redirected but counted under `bots`, never
|
|
168
|
+
`clicks`. Clicks land in daily counters spread over four shards.
|
|
169
|
+
- **Slugs** are 3–32 lowercase letters, digits or hyphens and unique across the
|
|
170
|
+
deployment, because the route names no site. A site keeps at most 200 links.
|
|
171
|
+
- **A short domain.** The route lives on the deployment's HTTP origin
|
|
172
|
+
(`https://<deployment>.convex.site/rastro/l/promo`). A host that wants a
|
|
173
|
+
presentable link serves that origin under a short domain of its own, such as
|
|
174
|
+
`go.example.com/rastro/l/promo`; nothing in the component changes.
|
|
175
|
+
|
|
176
|
+
Tracker:
|
|
177
|
+
|
|
178
|
+
- It sends the click-ID key **names** of the landing URL in `clid` (`fbclid`,
|
|
179
|
+
`gclid`, `ttclid`, `mc_cid`…), never their values, at most eight; ingestion
|
|
180
|
+
drops any name outside the allowlist. No advertising identifier leaves the
|
|
181
|
+
page.
|
|
182
|
+
- The referrer is sent as scheme and host, so a referrer of the form
|
|
183
|
+
`android-app://<package>` now reaches the server with its package instead of
|
|
184
|
+
the literal `"null"`: an Instagram or Gmail tap on Android classifies as that
|
|
185
|
+
platform.
|
|
186
|
+
- The script is 2,594 bytes raw and 1,395 bytes gzip, and its budget moved from
|
|
187
|
+
1,280 to 1,400 bytes gzip. Hosts serving it from the component get it on
|
|
188
|
+
upgrade, with a new `tracker.hash` and `ETag`; returning browsers pick it up
|
|
189
|
+
within the cache window (see [Tracker cache](#tracker-cache)).
|
|
190
|
+
|
|
191
|
+
Acceptance for this upgrade:
|
|
192
|
+
|
|
193
|
+
- `/rastro/health` reports `tracker.version: "0.5.0"` and a new `tracker.hash`.
|
|
194
|
+
- A `GET /rastro/l/<slug>` on a link created from the dashboard answers `302`
|
|
195
|
+
with `utm_source`, `utm_medium`, `utm_campaign` and `utm_content` on the
|
|
196
|
+
destination.
|
|
197
|
+
- **Conexões → Verificar novamente** shows the `trackedLinks` capability and the
|
|
198
|
+
**Links** tab appears.
|
|
199
|
+
- In a browser context opened after the deploy, a landing with `?gclid=x` shows
|
|
200
|
+
in **Fontes** under Busca paga › Google.
|
|
201
|
+
|
|
34
202
|
## Sessions, presence and rollups (0.4.0)
|
|
35
203
|
|
|
36
204
|
`0.4.0` needs no host edit: no new function, capability, or re-export. Install
|
|
@@ -483,6 +651,9 @@ control-plane issuer.
|
|
|
483
651
|
lets an owner or admin create a goal from the dashboard.
|
|
484
652
|
- On `0.4.0` or later: hiding the site's tab removes the visitor from the live
|
|
485
653
|
view within about ten seconds, and showing it brings them back.
|
|
654
|
+
- On `0.5.0` or later: the federation module re-exports the four tracked-link
|
|
655
|
+
functions, a created link redirects with its `utm_*`, and a landing with a
|
|
656
|
+
click ID appears under its channel and platform in **Fontes**.
|
|
486
657
|
- Protected overview, journey, goal, funnel, and affiliate reports used by the
|
|
487
658
|
host still run.
|
|
488
659
|
- Trusted conversion idempotency and currency checks still pass.
|