@zoho_apptics/apptics-js-sdk 2.0.0-beta → 2.0.0-beta.2
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/CHANGELOG.md +191 -21
- package/README.md +519 -333
- package/dist/apptics.esm.min.js +2 -2
- package/dist/apptics.esm.min.js.map +1 -1
- package/dist/apptics.min.js +2 -2
- package/dist/apptics.min.js.map +1 -1
- package/dist/chunks/lifecycle-C6m1W7jo.min.js +3 -0
- package/dist/chunks/lifecycle-C6m1W7jo.min.js.map +1 -0
- package/dist/chunks/send-CgUO82ne.min.js +3 -0
- package/dist/chunks/send-CgUO82ne.min.js.map +1 -0
- package/dist/cjs/core/attempts.js +1 -1
- package/dist/cjs/core/batch.js +2 -2
- package/dist/cjs/core/consent.d.ts +18 -4
- package/dist/cjs/core/consent.js +31 -15
- package/dist/cjs/core/constants.d.ts +57 -27
- package/dist/cjs/core/constants.js +52 -33
- package/dist/cjs/core/db.d.ts +12 -4
- package/dist/cjs/core/db.js +167 -34
- package/dist/cjs/core/debug.js +1 -1
- package/dist/cjs/core/env.d.ts +0 -3
- package/dist/cjs/core/env.js +1 -9
- package/dist/cjs/core/framework-id.d.ts +1 -1
- package/dist/cjs/core/framework-id.js +3 -3
- package/dist/cjs/core/guard.d.ts +9 -0
- package/dist/cjs/core/guard.js +27 -13
- package/dist/cjs/core/hooks.d.ts +7 -4
- package/dist/cjs/core/hooks.js +3 -3
- package/dist/cjs/core/locks.d.ts +9 -0
- package/dist/cjs/core/locks.js +22 -0
- package/dist/cjs/core/logger.d.ts +3 -4
- package/dist/cjs/core/logger.js +4 -40
- package/dist/cjs/core/state.d.ts +9 -6
- package/dist/cjs/core/state.js +3 -5
- package/dist/cjs/core/storage.d.ts +20 -5
- package/dist/cjs/core/storage.js +115 -20
- package/dist/cjs/core/stylesheet.d.ts +8 -0
- package/dist/cjs/core/stylesheet.js +29 -0
- package/dist/cjs/core/transport.d.ts +2 -0
- package/dist/cjs/core/transport.js +30 -18
- package/dist/cjs/core/utils.js +1 -1
- package/dist/cjs/core/validate.js +2 -2
- package/dist/cjs/device/appversion.d.ts +10 -6
- package/dist/cjs/device/appversion.js +38 -3
- package/dist/cjs/device/index.d.ts +28 -2
- package/dist/cjs/device/index.js +312 -44
- package/dist/cjs/engagement/api-rules.d.ts +32 -67
- package/dist/cjs/engagement/api-rules.js +144 -157
- package/dist/cjs/engagement/auto-api.js +2 -2
- package/dist/cjs/engagement/auto-screen.d.ts +2 -0
- package/dist/cjs/engagement/auto-screen.js +67 -3
- package/dist/cjs/engagement/defined-events.js +1 -1
- package/dist/cjs/engagement/send.js +12 -3
- package/dist/cjs/engagement/session.d.ts +29 -3
- package/dist/cjs/engagement/session.js +253 -26
- package/dist/cjs/engagement/track.d.ts +4 -4
- package/dist/cjs/engagement/track.js +58 -30
- package/dist/cjs/errors/send.js +2 -2
- package/dist/cjs/errors/track.d.ts +2 -1
- package/dist/cjs/errors/track.js +49 -7
- package/dist/cjs/feedback/controls.d.ts +12 -0
- package/dist/cjs/feedback/controls.js +104 -25
- package/dist/cjs/feedback/index.d.ts +8 -7
- package/dist/cjs/feedback/index.js +32 -13
- package/dist/cjs/feedback/logs.d.ts +13 -11
- package/dist/cjs/feedback/logs.js +57 -28
- package/dist/cjs/feedback/quartz.d.ts +18 -0
- package/dist/cjs/feedback/quartz.js +105 -0
- package/dist/cjs/feedback/send.d.ts +5 -2
- package/dist/cjs/feedback/send.js +30 -28
- package/dist/cjs/feedback/styles.d.ts +10 -0
- package/dist/cjs/feedback/styles.js +8 -0
- package/dist/cjs/feedback/template.d.ts +1 -1
- package/dist/cjs/feedback/template.js +20 -12
- package/dist/cjs/feedback/ui.d.ts +21 -6
- package/dist/cjs/feedback/ui.js +283 -70
- package/dist/cjs/heatmap/send.d.ts +2 -0
- package/dist/cjs/heatmap/send.js +3 -5
- package/dist/cjs/heatmap/track.d.ts +1 -1
- package/dist/cjs/heatmap/track.js +87 -16
- package/dist/cjs/index.d.ts +16 -63
- package/dist/cjs/index.js +144 -95
- package/dist/cjs/lifecycle.d.ts +21 -3
- package/dist/cjs/lifecycle.js +353 -89
- package/dist/cjs/remoteconfig/country.d.ts +4 -0
- package/dist/cjs/remoteconfig/country.js +73 -0
- package/dist/cjs/remoteconfig/custom.d.ts +7 -7
- package/dist/cjs/remoteconfig/custom.js +31 -51
- package/dist/cjs/remoteconfig/evaluate.d.ts +3 -3
- package/dist/cjs/remoteconfig/evaluate.js +56 -43
- package/dist/cjs/remoteconfig/fetch.d.ts +16 -9
- package/dist/cjs/remoteconfig/fetch.js +120 -39
- package/dist/cjs/remoteconfig/index.d.ts +19 -8
- package/dist/cjs/remoteconfig/index.js +81 -39
- package/dist/cjs/remoteconfig/store.d.ts +15 -7
- package/dist/cjs/remoteconfig/store.js +68 -35
- package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
- package/dist/cjs/remoteconfig/tz-countries.js +13 -0
- package/dist/{esm/core → cjs/remotelog}/callsite.d.ts +11 -4
- package/dist/cjs/{core → remotelog}/callsite.js +30 -7
- package/dist/cjs/remotelog/gate.d.ts +2 -11
- package/dist/cjs/remotelog/gate.js +9 -35
- package/dist/cjs/remotelog/index.d.ts +4 -21
- package/dist/cjs/remotelog/logger.d.ts +11 -17
- package/dist/cjs/remotelog/logger.js +31 -59
- package/dist/cjs/remotelog/send.js +11 -11
- package/dist/cjs/remotelogger/index.d.ts +12 -0
- package/dist/cjs/remotelogger/index.js +18 -0
- package/dist/cjs/scheduler.d.ts +3 -1
- package/dist/cjs/scheduler.js +25 -22
- package/dist/cjs/types.d.ts +208 -90
- package/dist/cjs/user/index.js +16 -7
- package/dist/esm/core/attempts.js +1 -1
- package/dist/esm/core/batch.js +2 -2
- package/dist/esm/core/consent.d.ts +18 -4
- package/dist/esm/core/consent.js +32 -17
- package/dist/esm/core/constants.d.ts +57 -27
- package/dist/esm/core/constants.js +51 -33
- package/dist/esm/core/db.d.ts +12 -4
- package/dist/esm/core/db.js +164 -35
- package/dist/esm/core/debug.js +1 -1
- package/dist/esm/core/env.d.ts +0 -3
- package/dist/esm/core/env.js +2 -9
- package/dist/esm/core/framework-id.d.ts +1 -1
- package/dist/esm/core/framework-id.js +3 -3
- package/dist/esm/core/guard.d.ts +9 -0
- package/dist/esm/core/guard.js +27 -14
- package/dist/esm/core/hooks.d.ts +7 -4
- package/dist/esm/core/hooks.js +3 -3
- package/dist/esm/core/locks.d.ts +9 -0
- package/dist/esm/core/locks.js +20 -0
- package/dist/esm/core/logger.d.ts +3 -4
- package/dist/esm/core/logger.js +4 -40
- package/dist/esm/core/state.d.ts +9 -6
- package/dist/esm/core/state.js +3 -5
- package/dist/esm/core/storage.d.ts +20 -5
- package/dist/esm/core/storage.js +113 -21
- package/dist/esm/core/stylesheet.d.ts +8 -0
- package/dist/esm/core/stylesheet.js +27 -0
- package/dist/esm/core/transport.d.ts +2 -0
- package/dist/esm/core/transport.js +30 -19
- package/dist/esm/core/utils.js +1 -1
- package/dist/esm/core/validate.js +2 -2
- package/dist/esm/device/appversion.d.ts +10 -6
- package/dist/esm/device/appversion.js +37 -4
- package/dist/esm/device/index.d.ts +28 -2
- package/dist/esm/device/index.js +313 -49
- package/dist/esm/engagement/api-rules.d.ts +32 -67
- package/dist/esm/engagement/api-rules.js +143 -155
- package/dist/esm/engagement/auto-api.js +3 -3
- package/dist/esm/engagement/auto-screen.d.ts +2 -0
- package/dist/esm/engagement/auto-screen.js +67 -4
- package/dist/esm/engagement/defined-events.js +1 -1
- package/dist/esm/engagement/send.js +12 -3
- package/dist/esm/engagement/session.d.ts +29 -3
- package/dist/esm/engagement/session.js +251 -30
- package/dist/esm/engagement/track.d.ts +4 -4
- package/dist/esm/engagement/track.js +65 -37
- package/dist/esm/errors/send.js +2 -2
- package/dist/esm/errors/track.d.ts +2 -1
- package/dist/esm/errors/track.js +49 -7
- package/dist/esm/feedback/controls.d.ts +12 -0
- package/dist/esm/feedback/controls.js +103 -26
- package/dist/esm/feedback/index.d.ts +8 -7
- package/dist/esm/feedback/index.js +34 -13
- package/dist/esm/feedback/logs.d.ts +13 -11
- package/dist/esm/feedback/logs.js +59 -30
- package/dist/esm/feedback/quartz.d.ts +18 -0
- package/dist/esm/feedback/quartz.js +99 -0
- package/dist/esm/feedback/send.d.ts +5 -2
- package/dist/esm/feedback/send.js +31 -31
- package/dist/esm/feedback/styles.d.ts +10 -0
- package/dist/esm/feedback/styles.js +4 -0
- package/dist/esm/feedback/template.d.ts +1 -1
- package/dist/esm/feedback/template.js +20 -12
- package/dist/esm/feedback/ui.d.ts +21 -6
- package/dist/esm/feedback/ui.js +283 -71
- package/dist/esm/heatmap/send.d.ts +2 -0
- package/dist/esm/heatmap/send.js +3 -5
- package/dist/esm/heatmap/track.d.ts +1 -1
- package/dist/esm/heatmap/track.js +87 -16
- package/dist/esm/index.d.ts +16 -63
- package/dist/esm/index.js +148 -83
- package/dist/esm/lifecycle.d.ts +21 -3
- package/dist/esm/lifecycle.js +359 -98
- package/dist/esm/remoteconfig/country.d.ts +4 -0
- package/dist/esm/remoteconfig/country.js +70 -0
- package/dist/esm/remoteconfig/custom.d.ts +7 -7
- package/dist/esm/remoteconfig/custom.js +32 -52
- package/dist/esm/remoteconfig/evaluate.d.ts +3 -3
- package/dist/esm/remoteconfig/evaluate.js +57 -44
- package/dist/esm/remoteconfig/fetch.d.ts +16 -9
- package/dist/esm/remoteconfig/fetch.js +120 -39
- package/dist/esm/remoteconfig/index.d.ts +19 -8
- package/dist/esm/remoteconfig/index.js +82 -40
- package/dist/esm/remoteconfig/store.d.ts +15 -7
- package/dist/esm/remoteconfig/store.js +68 -36
- package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
- package/dist/esm/remoteconfig/tz-countries.js +11 -0
- package/dist/{cjs/core → esm/remotelog}/callsite.d.ts +11 -4
- package/dist/esm/{core → remotelog}/callsite.js +30 -8
- package/dist/esm/remotelog/gate.d.ts +2 -11
- package/dist/esm/remotelog/gate.js +10 -32
- package/dist/esm/remotelog/index.d.ts +4 -21
- package/dist/esm/remotelog/logger.d.ts +11 -17
- package/dist/esm/remotelog/logger.js +33 -61
- package/dist/esm/remotelog/send.js +13 -13
- package/dist/esm/remotelogger/index.d.ts +12 -0
- package/dist/esm/remotelogger/index.js +13 -0
- package/dist/esm/scheduler.d.ts +3 -1
- package/dist/esm/scheduler.js +26 -24
- package/dist/esm/types.d.ts +208 -90
- package/dist/esm/user/index.js +18 -8
- package/dist/feedback.esm.min.js +2 -2
- package/dist/feedback.esm.min.js.map +1 -1
- package/dist/remoteconfig.esm.min.js +3 -0
- package/dist/remoteconfig.esm.min.js.map +1 -0
- package/dist/remotelogger.esm.min.js +3 -0
- package/dist/remotelogger.esm.min.js.map +1 -0
- package/package.json +16 -17
- package/dist/chunks/batch-BU_mTpm1.min.js +0 -3
- package/dist/chunks/batch-BU_mTpm1.min.js.map +0 -1
- package/dist/chunks/logs-Bea5zUW_.min.js +0 -3
- package/dist/chunks/logs-Bea5zUW_.min.js.map +0 -1
- package/dist/cjs/auto-init.d.ts +0 -8
- package/dist/cjs/auto-init.js +0 -32
- package/dist/cjs/heatmap/index.d.ts +0 -16
- package/dist/cjs/heatmap/index.js +0 -22
- package/dist/cjs/remotelog/index.js +0 -55
- package/dist/esm/auto-init.d.ts +0 -8
- package/dist/esm/auto-init.js +0 -29
- package/dist/esm/heatmap/index.d.ts +0 -16
- package/dist/esm/heatmap/index.js +0 -17
- package/dist/esm/remotelog/index.js +0 -51
- package/dist/heatmap.esm.min.js +0 -3
- package/dist/heatmap.esm.min.js.map +0 -1
- package/dist/style.css +0 -1
package/README.md
CHANGED
|
@@ -5,17 +5,17 @@ JavaScript/TypeScript library for [Zoho Apptics](https://www.zoho.com/apptics/)
|
|
|
5
5
|
### Prerequisites
|
|
6
6
|
|
|
7
7
|
- A browser app: Chrome 80+, Edge 80+, Firefox 74+ or Safari 14+.
|
|
8
|
-
- A Browser app registered in the Apptics web console (Quick start → Browser), which gives you its `
|
|
8
|
+
- A Browser app registered in the Apptics web console (Quick start → Browser), which gives you its `base_url`, `auth_key` and `app_domain`. You also need your app's `appversion`.
|
|
9
9
|
|
|
10
10
|
The SDK is plain TypeScript with no framework dependency. It works with any bundler (Vite, webpack, Next.js, …) and from a `<script>` tag.
|
|
11
11
|
|
|
12
12
|
## Install Apptics
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
npm install @zoho_apptics/apptics-js-sdk@2.0.0-beta
|
|
15
|
+
npm install @zoho_apptics/apptics-js-sdk@2.0.0-beta.2
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
A plain `npm install @zoho_apptics/apptics-js-sdk` still installs 1.0.2, the current `latest`. Upgrading from 1.0.2? `Apptics.init()` takes different config now; see [
|
|
18
|
+
A plain `npm install @zoho_apptics/apptics-js-sdk` still installs 1.0.2, the current `latest`. Upgrading from 1.0.2? `Apptics.init()` takes different config now; see [Migrating from 1.0.2 to 2.0.0-beta.2](#migrating-from-102-to-200-beta2).
|
|
19
19
|
|
|
20
20
|
## Initialize Apptics
|
|
21
21
|
|
|
@@ -24,71 +24,90 @@ Start Apptics once, as early as your app runs, with the values from the Apptics
|
|
|
24
24
|
### With a bundler
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
|
-
import { Apptics,
|
|
27
|
+
import { Apptics, AppticsEvent } from '@zoho_apptics/apptics-js-sdk';
|
|
28
28
|
|
|
29
29
|
// Your web app's Apptics configuration, from the Apptics web console
|
|
30
30
|
const appticsConfig = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
base_url: 'YOUR_BASE_URL',
|
|
32
|
+
auth_key: 'YOUR_AUTH_KEY',
|
|
33
|
+
app_domain: 'YOUR_APP_DOMAIN',
|
|
34
34
|
appversion: 'YOUR_APPVERSION', // your app's version
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// Initialize Apptics. Screens are tracked from the URL from here on, route changes included
|
|
38
38
|
Apptics.init(appticsConfig);
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
AppticsEvent.addEvent('signup', 'onboarding', { plan: 'pro' });
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
The config object is **required**, with `
|
|
43
|
+
The config object is **required**, with `base_url`, `auth_key`, `app_domain` and `appversion`: `Apptics.init()` won't start without them, and logs a warning naming whatever is missing.
|
|
44
44
|
|
|
45
|
-
`Apptics.init()` returns right away. The SDK finishes starting once its storage has loaded, usually within a few milliseconds. Calls you make before that are queued and run in order, so you don't have to wait. If you need to know when it's running, use `await
|
|
45
|
+
`Apptics.init()` returns right away. The SDK finishes starting once its storage has loaded, usually within a few milliseconds. Calls you make before that are queued and run in order, so you don't have to wait. If you need to know when it's running, use `await Apptics.ready()`.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Every call belongs to an object, named after its feature, so you import only the object: `Apptics.init()`, `AppticsEvent.addEvent()`, `AppticsError.trackError()`, `AppticsFeedback.feedbackFormOpen()`. See [The API at a glance](#the-api-at-a-glance). CommonJS works too (`const { Apptics } = require('@zoho_apptics/apptics-js-sdk')`). Importing the SDK is safe during server-side rendering: nothing runs until `Apptics.init()` is called in the browser.
|
|
48
48
|
|
|
49
49
|
### With a `<script>` tag (CDN)
|
|
50
50
|
|
|
51
|
-
Load the browser build and call `Apptics.init()` after it. One `<script>` tag is all it takes: the
|
|
52
|
-
|
|
51
|
+
Load the browser build and call `Apptics.init()` after it. One `<script>` tag is all it takes: the feedback
|
|
52
|
+
form's styles are inside the build, so there is no stylesheet to add.
|
|
53
53
|
|
|
54
54
|
```html
|
|
55
|
-
<script src="https://
|
|
55
|
+
<script src="https://static.zohocdn.com/apptics-js-sdk/2.0.0-beta.2/apptics.min.js"></script>
|
|
56
56
|
<script>
|
|
57
57
|
Apptics.init({
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
base_url: 'YOUR_BASE_URL',
|
|
59
|
+
auth_key: 'YOUR_AUTH_KEY',
|
|
60
|
+
app_domain: 'YOUR_APP_DOMAIN',
|
|
61
61
|
appversion: 'YOUR_APPVERSION', // your app's version
|
|
62
62
|
});
|
|
63
63
|
// screens are tracked from the URL automatically; events are yours to send
|
|
64
|
-
|
|
64
|
+
AppticsEvent.addEvent('signup', 'onboarding', { plan: 'pro' });
|
|
65
65
|
</script>
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
The build defines the same
|
|
68
|
+
The build defines the same objects as globals (`Apptics`, `AppticsEvent`, `AppticsScreen`, `AppticsApi`, `AppticsError`, `AppticsUser`, `AppticsSettings`, `AppticsFeedback`, `AppticsLogger`, `AppticsRemoteConfig`, `AppticsHeatmap`), so a page's code reads as it would after an import. Every module is included (feedback, heatmaps, remote config, the remote logger), and everything is also on `window.apptics`. Define `window.appticsReady = () => { … }` to run code once it's ready.
|
|
69
69
|
|
|
70
70
|
`Apptics.init()` runs exactly once; a second call logs a warning and returns `false`. Calls that track
|
|
71
71
|
or send something are ignored until `Apptics.init()` has run, and the first such call logs a console
|
|
72
72
|
warning saying so.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
Each release has its own folder on the CDN, `https://static.zohocdn.com/apptics-js-sdk/{version}/`, so a page keeps loading the version it names until you change it. See [Loading from a CDN](#loading-from-a-cdn) for module builds and subresource integrity.
|
|
75
|
+
|
|
76
|
+
### The API at a glance
|
|
77
|
+
|
|
78
|
+
Each feature's calls are on one object:
|
|
79
|
+
|
|
80
|
+
| Object | Calls | Entry point |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `Apptics` | `init(config)`, `ready()`, `flush()`, `reset()`, `enableDebug()`, `disableDebug()` | main |
|
|
83
|
+
| `AppticsEvent` | `addEvent(eventName, groupName, properties?)`, `addEvent(DefinedEvents.X, properties?)`, `setClickTracking(enabled?)`, `DefinedEvents` | main |
|
|
84
|
+
| `AppticsScreen` | `inScreen(screenName, properties?)` → id, `outScreen(id)`, `setScreenTracking(enabled?)` | main |
|
|
85
|
+
| `AppticsError` | `trackError(error, properties?)`, `setErrorTracking(enabled?)` | main |
|
|
86
|
+
| `AppticsUser` | `setUser(userid, groupid?, properties?)`, `getUser()`, `UserBuilder` | main |
|
|
87
|
+
| `AppticsSettings` | `setTrackingStatus(status)`, `getTrackingStatus()`, the `AP_TRACKING_STATUS` constants | main |
|
|
88
|
+
| `AppticsApi` | `startTrackApi(url, method?)` → id, `endTrackApi(id, responseCode, responseMessage?)`, `configure(config)`, `setApiTracking(enabled?)`, `ApiTrackingBuilder` | main |
|
|
89
|
+
| `AppticsHeatmap` | `setHeatmapTracking(enabled?)` | main |
|
|
90
|
+
| `AppticsLogger` | `verbose(message, properties?)`, `debug(message, properties?)`, `info(message, properties?)`, `warn(message, properties?)`, `error(message, properties?)` | `/remote-logger` |
|
|
91
|
+
| `AppticsFeedback` | `feedbackFormOpen(options?)`, `feedbackFormClose()`, `sendFeedback(options?)`, `addFeedbackLog(message)`, `addDiagnosticsInfo(heading, key, value)`, `setFeedbackTheme(theme)`, the `AP_FEEDBACK_TYPE` constants | `/feedback` |
|
|
92
|
+
| `AppticsRemoteConfig` | `fetchValue(name, callback?, coldFetch?)`, `fetchValues(names?, callback?, coldFetch?)`, `setCustomConditionValue(conditionname, value)` | `/remote-config` |
|
|
93
|
+
|
|
94
|
+
The `set…Tracking(enabled?)` calls switch each automatic tracker on or off while the page runs
|
|
95
|
+
(see [Turning automatic tracking on and off](#turning-automatic-tracking-on-and-off)).
|
|
75
96
|
|
|
76
97
|
### Frameworks
|
|
77
98
|
|
|
78
|
-
React, Vue, Angular, Svelte, Ember, Solid, jQuery and hand-written JS all start the same way, and every one of them needs only that: the SDK follows the route itself ([automatic screen tracking](#automatic-screen-tracking)). To name screens from your router instead, call `
|
|
99
|
+
React, Vue, Angular, Svelte, Ember, Solid, jQuery and hand-written JS all start the same way, and every one of them needs only that: the SDK follows the route itself ([automatic screen tracking](#automatic-screen-tracking)). To name screens from your router instead, call `AppticsScreen.inScreen()` from the hook in the last column: a call made as the route changes replaces the automatic view, and `track_screen: false` turns the automatic one off altogether.
|
|
79
100
|
|
|
80
101
|
| Framework | Start | Screen on navigation, with `track_screen: false` |
|
|
81
102
|
|---|---|---|
|
|
82
103
|
| React, Remix, Gatsby | `useEffect(() => { Apptics.init(config); }, [])` | `useLocation()` in an effect |
|
|
83
|
-
| Vue 3 | a plugin: `app.use(apptics, { router })` | `router.afterEach(to =>
|
|
104
|
+
| Vue 3 | a plugin: `app.use(apptics, { router })` | `router.afterEach(to => AppticsScreen.inScreen(to.path))` |
|
|
84
105
|
| Angular | an injectable service | `router.events` filtered to `NavigationEnd` |
|
|
85
106
|
| Svelte, SvelteKit | `src/hooks.client.ts`, or `onMount` | `afterNavigate` |
|
|
86
107
|
| Ember | an instance initializer | `router.on('routeDidChange', …)` |
|
|
87
108
|
| Next.js | `'use client'` component in the layout | `usePathname()` in an effect |
|
|
88
109
|
| Nuxt 3 | `plugins/apptics.client.ts` | `useRouter().afterEach(…)` |
|
|
89
|
-
| Plain JS, jQuery | the `<script>` tag itself | `
|
|
90
|
-
|
|
91
|
-
**Server-side rendering** (Next, Nuxt, SvelteKit, Remix, Angular Universal): importing the SDK on the server is safe — `Apptics.init()` returns `false` instead of throwing — but it tracks nothing there. Start it from a browser-only hook, as the recipes do. There is no Node/server-side tracking: `engines.node` in `package.json` is the floor for building the package and running its CLI.
|
|
110
|
+
| Plain JS, jQuery | the `<script>` tag itself | `AppticsScreen.inScreen()` where you change view |
|
|
92
111
|
|
|
93
112
|
## Error Tracking
|
|
94
113
|
|
|
@@ -97,52 +116,77 @@ Uncaught errors and unhandled promise rejections are tracked automatically, as J
|
|
|
97
116
|
Report an error your code caught:
|
|
98
117
|
|
|
99
118
|
```ts
|
|
100
|
-
import {
|
|
119
|
+
import { AppticsError } from '@zoho_apptics/apptics-js-sdk';
|
|
101
120
|
|
|
102
121
|
try {
|
|
103
122
|
doSomething();
|
|
104
123
|
} catch (error) {
|
|
105
|
-
|
|
124
|
+
AppticsError.trackError({ type: 'error', error });
|
|
106
125
|
}
|
|
107
126
|
```
|
|
108
127
|
|
|
109
|
-
`
|
|
128
|
+
`AppticsError.trackError` also accepts `error` and `unhandledrejection` events as they are, and properties as a second argument.
|
|
129
|
+
|
|
130
|
+
To record only the errors you report yourself, turn the automatic tracking off, at start-up or
|
|
131
|
+
later. `AppticsError.trackError()` records either way:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
Apptics.init({ ...config, track_error: false }); // from the start
|
|
135
|
+
AppticsError.setErrorTracking(false); // or while the page runs; true turns it back on
|
|
136
|
+
```
|
|
110
137
|
|
|
111
138
|
React, Vue, Angular, SvelteKit and Ember catch render errors themselves, so those never reach `window.onerror`. Report them from the framework's own error hook:
|
|
112
139
|
|
|
113
140
|
| Framework | Error hook |
|
|
114
141
|
|---|---|
|
|
115
|
-
| React | an error boundary: `componentDidCatch(error) {
|
|
116
|
-
| Vue 3, Nuxt 3 | `app.config.errorHandler = (error) =>
|
|
117
|
-
| Angular | an `ErrorHandler` whose `handleError(error)` calls `
|
|
142
|
+
| React | an error boundary: `componentDidCatch(error) { AppticsError.trackError({ type: 'error', error }); }` |
|
|
143
|
+
| Vue 3, Nuxt 3 | `app.config.errorHandler = (error) => AppticsError.trackError({ type: 'error', error })` (Nuxt: `nuxtApp.hook('vue:error', …)`) |
|
|
144
|
+
| Angular | an `ErrorHandler` whose `handleError(error)` calls `AppticsError.trackError({ type: 'error', error })`, provided as `{ provide: ErrorHandler, useClass: … }` |
|
|
118
145
|
| SvelteKit | `handleError({ error })` in `src/hooks.client.ts` |
|
|
119
|
-
| Ember | `Ember.onerror = (error) =>
|
|
146
|
+
| Ember | `Ember.onerror = (error) => AppticsError.trackError({ type: 'error', error })` |
|
|
120
147
|
|
|
121
148
|
## Event Tracking
|
|
122
149
|
|
|
123
|
-
Track an event, with
|
|
150
|
+
Track an event in a group, with optional properties:
|
|
124
151
|
|
|
125
152
|
```ts
|
|
126
|
-
import {
|
|
153
|
+
import { AppticsEvent } from '@zoho_apptics/apptics-js-sdk';
|
|
127
154
|
|
|
128
|
-
|
|
155
|
+
AppticsEvent.addEvent('eventName', 'eventGroupName');
|
|
156
|
+
AppticsEvent.addEvent('eventName', 'eventGroupName', { propKey: 'propValue' });
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The group is required. An event without one (left out, `''`, or properties in its place, as in
|
|
160
|
+
`addEvent('eventName', { propKey: 'propValue' })`) is not logged, and the console says so, debug
|
|
161
|
+
or not:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
AppticsEvent.addEvent: groupName is required for "eventName": addEvent(eventName, groupName, properties?)
|
|
129
165
|
```
|
|
130
166
|
|
|
131
167
|
Event and group names start with a letter, followed by letters, digits or `_`, at most 100
|
|
132
|
-
characters, and may not start with `ap_` or `AP_`, which is reserved for defined events.
|
|
133
|
-
|
|
134
|
-
|
|
168
|
+
characters, and may not start with `ap_` or `AP_`, which is reserved for defined events. An event
|
|
169
|
+
with an invalid name or group is not logged, and the console says why.
|
|
170
|
+
|
|
171
|
+
Properties: keys start with a letter, followed by up to 49 letters, digits or `_`, and may not
|
|
172
|
+
start with `ap_`. Values are numbers, booleans or strings of up to 250 characters; anything else
|
|
173
|
+
(an object, an array) is sent as its JSON text. A property that breaks these rules
|
|
174
|
+
is dropped and the event is still logged with the rest. At most 24 properties and 7,666
|
|
175
|
+
characters in all; past that the later ones are dropped. The same rules apply to screen and error
|
|
176
|
+
properties.
|
|
135
177
|
|
|
136
178
|
### Defined events
|
|
137
179
|
|
|
138
|
-
Apptics' ready-made events,
|
|
180
|
+
Apptics' ready-made events, each with its own `AP_` group. They are
|
|
139
181
|
not tracked automatically; log the ones that apply:
|
|
140
182
|
|
|
141
183
|
```ts
|
|
142
|
-
import {
|
|
184
|
+
import { AppticsEvent } from '@zoho_apptics/apptics-js-sdk';
|
|
185
|
+
|
|
186
|
+
const { DefinedEvents } = AppticsEvent;
|
|
143
187
|
|
|
144
|
-
|
|
145
|
-
|
|
188
|
+
AppticsEvent.addEvent(DefinedEvents.AP_USER_LOGIN);
|
|
189
|
+
AppticsEvent.addEvent(DefinedEvents.AP_SEARCH, { results: 12 });
|
|
146
190
|
```
|
|
147
191
|
|
|
148
192
|
| Group | Events |
|
|
@@ -153,9 +197,11 @@ AppticsEvents.addEvent(DefinedEvents.AP_SEARCH, { results: 12 });
|
|
|
153
197
|
| `AP_OTHERS` | `AP_NETWORK_REACHABILITY_CHANGE`, `AP_NETWORK_BANDWIDTH_CHANGE`, `AP_SWITCH_THEME_LIGHT`, `AP_SWITCH_THEME_DARK`, `AP_SWITCH_THEME_CUSTOM`, `AP_SWITCH_ORIENTATION_LANDSCAPE`, `AP_SWITCH_ORIENTATION_PORTRAIT` |
|
|
154
198
|
| `AP_OS` | `AP_OS_UPDATE`, `AP_OS_UNSUPPORTED` |
|
|
155
199
|
|
|
156
|
-
With a `<script>` tag it is `
|
|
200
|
+
With a `<script>` tag it is `AppticsEvent.DefinedEvents` too.
|
|
201
|
+
|
|
202
|
+
### Click tracking
|
|
157
203
|
|
|
158
|
-
Clicks can
|
|
204
|
+
Clicks can be tracked from attributes in your markup, with no code:
|
|
159
205
|
|
|
160
206
|
```html
|
|
161
207
|
<section apgroupaction="checkout">
|
|
@@ -163,127 +209,172 @@ Clicks can also be tracked from markup, without code:
|
|
|
163
209
|
</section>
|
|
164
210
|
```
|
|
165
211
|
|
|
166
|
-
Clicking the button, or anything inside it, tracks `buy_clicked` in group `checkout
|
|
212
|
+
Clicking the button, or anything inside it, tracks `buy_clicked` in group `checkout`, the nearest
|
|
213
|
+
`apgroupaction` around it, with the properties in `apeventprops` (JSON). An element with no
|
|
214
|
+
`apgroupaction` around it is not tracked, and the console says the group is missing. The `data-`
|
|
215
|
+
spellings work too (`data-apeventaction`, `data-apgroupaction`, `data-apeventprops`), which React
|
|
216
|
+
and TypeScript accept as they are.
|
|
217
|
+
|
|
218
|
+
#### Turning click tracking off
|
|
219
|
+
|
|
220
|
+
`track_click: false` in `Apptics.init()`, or `AppticsEvent.setClickTracking(false)` while the page
|
|
221
|
+
runs, stops click tracking from markup. `AppticsEvent.addEvent()` records either way.
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
Apptics.init({ ...config, track_click: false }); // from the start
|
|
225
|
+
AppticsEvent.setClickTracking(true); // or switch it later
|
|
226
|
+
```
|
|
167
227
|
|
|
168
|
-
Properties: keys start with a letter, followed by up to 49 letters, digits or `_`, and may not
|
|
169
|
-
start with `ap_`. Values are numbers, booleans or strings of up to 250 characters; anything else
|
|
170
|
-
(an object, an array) is sent as its JSON text. As on Android, a property that breaks these rules
|
|
171
|
-
is dropped and the event is still logged with the rest. At most 24 properties and 7,666
|
|
172
|
-
characters in all; past that the later ones are dropped. The same rules apply to screen and error
|
|
173
|
-
properties.
|
|
174
228
|
|
|
175
229
|
## Screen Tracking
|
|
176
230
|
|
|
177
231
|
Screens are tracked automatically, from the URL (see [below](#automatic-screen-tracking)). To
|
|
178
|
-
record one yourself
|
|
232
|
+
record one yourself, with your own name or with properties, call `AppticsScreen.inScreen`:
|
|
179
233
|
|
|
180
234
|
```ts
|
|
181
|
-
import {
|
|
235
|
+
import { AppticsScreen } from '@zoho_apptics/apptics-js-sdk';
|
|
182
236
|
|
|
183
|
-
|
|
237
|
+
AppticsScreen.inScreen('checkout');
|
|
184
238
|
```
|
|
185
239
|
|
|
186
240
|
Each screen view records how long it lasted. It ends when the next screen starts, when the page
|
|
187
241
|
is hidden (coming back starts a new view of the same screen), or when its session ends.
|
|
188
|
-
`
|
|
189
|
-
that closes without the page changing, say
|
|
242
|
+
`AppticsScreen.inScreen` returns the view's id; hand it to `AppticsScreen.outScreen` to end the view yourself (a dialog
|
|
243
|
+
that closes without the page changing, say):
|
|
190
244
|
|
|
191
245
|
```ts
|
|
192
|
-
import {
|
|
246
|
+
import { AppticsScreen } from '@zoho_apptics/apptics-js-sdk';
|
|
193
247
|
|
|
194
|
-
const id =
|
|
195
|
-
|
|
248
|
+
const id = AppticsScreen.inScreen('settings'); // when the screen is shown
|
|
249
|
+
AppticsScreen.outScreen(id); // when it is dismissed
|
|
196
250
|
```
|
|
197
251
|
|
|
198
|
-
`
|
|
252
|
+
`AppticsScreen.inScreen` returns `''` for a name that isn't a valid screen name.
|
|
199
253
|
|
|
200
|
-
Screen names: up to 99 characters of letters, digits, spaces and `. - _ & /
|
|
201
|
-
feedback and heatmap records are attributed to the current screen: the one `
|
|
254
|
+
Screen names: up to 99 characters of letters, digits, spaces and `. - _ & / : *`. Events, errors,
|
|
255
|
+
feedback and heatmap records are attributed to the current screen: the one `AppticsScreen.inScreen()` last
|
|
202
256
|
named, or else the one automatic tracking named from the URL. A heatmap record always has a
|
|
203
|
-
screen view behind it: with automatic tracking off and no `
|
|
257
|
+
screen view behind it: with automatic tracking off and no `AppticsScreen.inScreen()` call, the first record
|
|
204
258
|
on a page records a view of the page, named the same way from its path, and a new one when the
|
|
205
259
|
path changes.
|
|
206
260
|
|
|
207
|
-
An `
|
|
261
|
+
An `AppticsScreen.inScreen()` call made during a navigation, from a router hook for example,
|
|
208
262
|
replaces the automatic view of it, so the navigation counts once, under your name. The automatic view waits
|
|
209
263
|
300 ms for such a call before it is recorded; a call after that is a screen view of its own.
|
|
210
264
|
|
|
211
265
|
### Automatic screen tracking
|
|
212
266
|
|
|
213
|
-
On by default: the SDK records screen views from the URL, with no `
|
|
267
|
+
On by default: the SDK records screen views from the URL, with no `AppticsScreen.inScreen()` calls. It records the page the SDK starts on, then every navigation: `history.pushState` / `replaceState`
|
|
214
268
|
(React Router, Vue Router, Angular, Next.js and other single-page routers), back and forward, and
|
|
215
269
|
`#/` hash routes. The screen is named by its path, without the query string, so `/search?q=shoes`
|
|
216
270
|
is `/search` and `/#/orders` is `/orders`. Characters a screen name can't hold become `_`, and a
|
|
217
271
|
name stops at 99 characters. A plain `#anchor` and a navigation that lands on the same path are
|
|
218
272
|
not new views.
|
|
219
273
|
|
|
220
|
-
Paths with ids in them make every record its own screen.
|
|
221
|
-
|
|
222
|
-
|
|
274
|
+
Paths with ids in them make every record its own screen. `screen_routes` names them instead. Each
|
|
275
|
+
entry is one of three kinds, tried in order; the first that matches names the screen, and a path
|
|
276
|
+
none matches keeps its own name:
|
|
277
|
+
|
|
278
|
+
| Entry | Matches | Recorded as |
|
|
279
|
+
|---|---|---|
|
|
280
|
+
| `'/users/{id}/orders'` | a route pattern: `{id}`, `:id` and `*` each match one path segment | the pattern, each variable segment as `*` |
|
|
281
|
+
| `{ equals: '/', name: 'Home' }` | that path exactly (a trailing slash does not matter) | `name` |
|
|
282
|
+
| `{ regex: /^\/orders\/\d+$/, name: 'Order detail' }` | any path the regular expression matches (a `RegExp` or its source as a string) | `name` |
|
|
223
283
|
|
|
224
|
-
|
|
284
|
+
```ts
|
|
285
|
+
Apptics.init({
|
|
286
|
+
...config,
|
|
287
|
+
screen_routes: [
|
|
288
|
+
{ equals: '/', name: 'Home' },
|
|
289
|
+
{ regex: /^\/orders\/\d+$/, name: 'Order detail' },
|
|
290
|
+
'/users/{id}/{id}/orders',
|
|
291
|
+
'/products/:sku',
|
|
292
|
+
],
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Opened | Recorded as |
|
|
297
|
+
|---|---|
|
|
298
|
+
| `/` | `Home` |
|
|
299
|
+
| `/orders/123?tab=items` | `Order detail` (paths are matched without the query string) |
|
|
300
|
+
| `/users/12/34/orders` | `/users/*/*/orders` |
|
|
301
|
+
| `/products/sku-889` | `/products/*` |
|
|
302
|
+
| `/users/12/34/settings` | `/users/12/34/settings` (no entry matches, so the name is kept) |
|
|
303
|
+
|
|
304
|
+
An entry that can't be used (no `name`, a regex that does not compile) is left out, and
|
|
305
|
+
`Apptics.init()` says which in the console.
|
|
306
|
+
|
|
307
|
+
**An app that names its screens from its router** keeps doing so with `AppticsScreen.inScreen()`: a call
|
|
225
308
|
within 300 ms of the navigation replaces the automatic view (see
|
|
226
|
-
[Screen Tracking](#screen-tracking)). To track only the screens you name yourself
|
|
227
|
-
aren't routes, or hooks that run later than that
|
|
309
|
+
[Screen Tracking](#screen-tracking)). To track only the screens you name yourself (screens that
|
|
310
|
+
aren't routes, or hooks that run later than that), turn automatic tracking off:
|
|
228
311
|
|
|
229
312
|
```ts
|
|
230
313
|
Apptics.init({ ...config, track_screen: false });
|
|
231
314
|
```
|
|
232
315
|
|
|
233
|
-
|
|
316
|
+
or switch it while the page runs, for a part of the app that names its screens itself:
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
AppticsScreen.setScreenTracking(false); // only inScreen() calls are recorded
|
|
320
|
+
AppticsScreen.setScreenTracking(true); // back on: the page as it is now is recorded
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
`Apptics.reset()` takes the history wrappers off; the `Apptics.init()` it runs puts them back.
|
|
234
324
|
|
|
235
325
|
## Track User
|
|
236
326
|
|
|
237
327
|
Register the signed-in user:
|
|
238
328
|
|
|
239
329
|
```ts
|
|
240
|
-
import {
|
|
330
|
+
import { AppticsUser } from '@zoho_apptics/apptics-js-sdk';
|
|
241
331
|
|
|
242
|
-
|
|
332
|
+
AppticsUser.setUser('user-id', 'customer-group-id'); // the group is optional
|
|
243
333
|
```
|
|
244
334
|
|
|
245
|
-
`
|
|
335
|
+
`AppticsUser.setUser` switches tracking to "with PII" (see [Tracking settings](#tracking-settings)). `AppticsUser.getUser()` returns the active user.
|
|
246
336
|
|
|
247
337
|
### Track User with properties
|
|
248
338
|
|
|
249
339
|
```ts
|
|
250
|
-
import {
|
|
340
|
+
import { AppticsUser } from '@zoho_apptics/apptics-js-sdk';
|
|
251
341
|
|
|
252
|
-
const properties = new
|
|
342
|
+
const properties = new AppticsUser.UserBuilder()
|
|
253
343
|
.setFirstName('Ana')
|
|
254
344
|
.setEmailAddress('ana@zylker.com')
|
|
255
345
|
.setPlanType('pro')
|
|
256
346
|
.setCustomProperties({ team: 'design' })
|
|
257
347
|
.build();
|
|
258
348
|
|
|
259
|
-
|
|
349
|
+
AppticsUser.setUser('user-id', 'customer-group-id', properties);
|
|
260
350
|
```
|
|
261
351
|
|
|
262
|
-
The builder also has `setLastName`, `setCompanyName`, `setContactNumber`, `setCountry`, `setRegion`, `setCity`, `setGeoLocation`, `setGender`, `setTimezone`, `setLanguage`, `setEngagementScore` and `setDateOfBirth
|
|
352
|
+
The builder also has `setLastName`, `setCompanyName`, `setContactNumber`, `setCountry`, `setRegion`, `setCity`, `setGeoLocation`, `setGender`, `setTimezone`, `setLanguage`, `setEngagementScore` and `setDateOfBirth`, and `addStringProperty(key, value)`,
|
|
353
|
+
`addNumberProperty` and `addBooleanProperty` for one custom property at a time. `build()` validates the properties against what the server accepts.
|
|
263
354
|
|
|
264
355
|
## Tracking settings
|
|
265
356
|
|
|
266
357
|
Set what the SDK may track for this visitor:
|
|
267
358
|
|
|
268
359
|
```ts
|
|
269
|
-
import {
|
|
360
|
+
import { AppticsSettings } from '@zoho_apptics/apptics-js-sdk';
|
|
270
361
|
|
|
271
|
-
setTrackingStatus(AP_TRACKING_STATUS.USAGE_TRACKING_WITHOUT_PII);
|
|
362
|
+
AppticsSettings.setTrackingStatus(AppticsSettings.AP_TRACKING_STATUS.USAGE_TRACKING_WITHOUT_PII);
|
|
272
363
|
```
|
|
273
364
|
|
|
274
|
-
|
|
|
365
|
+
| `AppticsSettings.AP_TRACKING_STATUS.` | Value | Meaning |
|
|
275
366
|
|---|---|---|
|
|
276
367
|
| `USAGE_TRACKING_WITH_PII` | 1 | Track, with the user's identity |
|
|
277
368
|
| `USAGE_TRACKING_WITHOUT_PII` | 4 | Track anonymously (the default) |
|
|
278
369
|
| `NO_TRACKING` | -1 | Track nothing |
|
|
279
370
|
|
|
280
|
-
`getTrackingStatus()` returns the current one.
|
|
371
|
+
`AppticsSettings.getTrackingStatus()` returns the current one.
|
|
281
372
|
|
|
282
373
|
### Privacy
|
|
283
374
|
|
|
284
375
|
- The browser's Do Not Track setting is honoured unless `ignore_do_not_track: true` is passed to `Apptics.init()`.
|
|
285
376
|
- Nothing is tracked for known crawlers.
|
|
286
|
-
- Heatmaps name an element from an attribute the author chose (`data-ap-label`, `aria-label`, `name`, `id`, `title`); its visible text is used only with `USAGE_TRACKING_WITH_PII`.
|
|
377
|
+
- Heatmaps name an element from an attribute the author chose (`data-ap-label`, `apeventaction` or `data-apeventaction`, `aria-label`, `name`, `id`, `title`); its visible text is used only with `USAGE_TRACKING_WITH_PII`.
|
|
287
378
|
|
|
288
379
|
## API Tracking
|
|
289
380
|
|
|
@@ -294,44 +385,62 @@ Record the API calls your app makes, for the console's API page. Either let the
|
|
|
294
385
|
Apptics.init({ ...config, track_api: true }); // record every fetch and XHR call
|
|
295
386
|
```
|
|
296
387
|
|
|
297
|
-
`
|
|
298
|
-
[`
|
|
388
|
+
`AppticsApi.setApiTracking(enabled)` switches it later. Which hosts and endpoints are recorded is set with
|
|
389
|
+
[`AppticsApi.configure`](#configuring-api-tracking).
|
|
299
390
|
|
|
300
|
-
or record calls yourself with `
|
|
391
|
+
or record calls yourself with `AppticsApi.startTrackApi` / `endTrackApi`. The
|
|
301
392
|
SDK times the call between the two:
|
|
302
393
|
|
|
303
394
|
```ts
|
|
304
|
-
import {
|
|
395
|
+
import { AppticsApi } from '@zoho_apptics/apptics-js-sdk';
|
|
305
396
|
|
|
306
|
-
const id =
|
|
397
|
+
const id = AppticsApi.startTrackApi('https://api.example.com/orders/42', 'GET');
|
|
307
398
|
const response = await fetch('https://api.example.com/orders/42');
|
|
308
|
-
|
|
399
|
+
AppticsApi.endTrackApi(id, response.status, response.statusText);
|
|
309
400
|
```
|
|
310
401
|
|
|
311
|
-
Between them, automatic tracking and `
|
|
402
|
+
Between them, automatic tracking and `AppticsApi.startTrackApi` / `endTrackApi` are the
|
|
312
403
|
two ways a call is recorded.
|
|
313
404
|
|
|
314
405
|
### Configuring API tracking
|
|
315
406
|
|
|
316
|
-
Build the rules with `ApiTrackingBuilder`
|
|
317
|
-
|
|
318
|
-
|
|
407
|
+
Build the rules with `AppticsApi.ApiTrackingBuilder` (as `AppticsUser.UserBuilder` builds user
|
|
408
|
+
properties) and apply them once, before the requests they should cover. It works before
|
|
409
|
+
`Apptics.init()`:
|
|
319
410
|
|
|
320
411
|
```ts
|
|
321
|
-
import {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
.
|
|
325
|
-
.
|
|
326
|
-
.
|
|
327
|
-
.
|
|
328
|
-
.preserveSegments('v1', 'v2')
|
|
412
|
+
import { AppticsApi } from '@zoho_apptics/apptics-js-sdk';
|
|
413
|
+
|
|
414
|
+
AppticsApi.configure(new AppticsApi.ApiTrackingBuilder()
|
|
415
|
+
.allowRegex(/^https:\/\/api\.yourapp\.(com|in|ae)\//) // only your API hosts
|
|
416
|
+
.allowEquals('https://auth.yourapp.com/token') // and this one endpoint
|
|
417
|
+
.ignoreEquals('https://api.yourapp.com/health') // never this one
|
|
418
|
+
.ignoreRegex(/\/internal\//) // nor anything under /internal/
|
|
329
419
|
.build());
|
|
330
420
|
```
|
|
331
421
|
|
|
422
|
+
Four rules, two kinds by two: an exact URL (`Equals`) or a regular expression (`Regex`), to allow
|
|
423
|
+
or to ignore. Each is tried on the call's URL as `scheme://host[:port]/path`, without its query
|
|
424
|
+
string or fragment, so one rule can name a host, a path or a single endpoint.
|
|
425
|
+
|
|
426
|
+
| Builder call | Effect |
|
|
427
|
+
|---|---|
|
|
428
|
+
| `allowEquals(...urls)` | Record these URLs exactly, as `'https://api.yourapp.com/orders'` |
|
|
429
|
+
| `allowRegex(...patterns)` | Record the URLs these regular expressions match, as `/^https:\/\/api\.yourapp\.com\//` |
|
|
430
|
+
| `ignoreEquals(...urls)` | Never record these URLs exactly |
|
|
431
|
+
| `ignoreRegex(...patterns)` | Never record the URLs these regular expressions match |
|
|
432
|
+
|
|
433
|
+
- **Ignore always wins.** Ignore rules are tried first; then, when there are any allow rules, a call
|
|
434
|
+
must match one of them. With no rules at all, every call is recorded.
|
|
435
|
+
- **Equals** compares whole URLs: the scheme and host are not case-sensitive, a trailing slash and
|
|
436
|
+
the default port do not matter, a port that is not the default does. It takes full URLs only.
|
|
437
|
+
- **Regex** takes a `RegExp` or its source as a string, and works with any flags.
|
|
438
|
+
- A URL that is not a full http(s) URL, or a regex that does not compile, is left out and the
|
|
439
|
+
console says why. A second `AppticsApi.configure()` replaces the first.
|
|
440
|
+
|
|
332
441
|
The rules apply to every call, the ones `track_api` catches and the ones you report yourself.
|
|
333
442
|
|
|
334
|
-
**Path normalization**, on
|
|
443
|
+
**Path normalization**, always on, so calls group by endpoint rather than by id:
|
|
335
444
|
|
|
336
445
|
| Called | Recorded as |
|
|
337
446
|
|---|---|
|
|
@@ -340,25 +449,11 @@ The rules apply to every call, the ones `track_api` catches and the ones you rep
|
|
|
340
449
|
| `DELETE /sessions/eyJhbGciOi….….` | `/sessions/*` (JWT) |
|
|
341
450
|
| `GET /products/search?q=shoes` | `/products/search` (the query string is always removed) |
|
|
342
451
|
|
|
343
|
-
| Builder call | Effect |
|
|
344
|
-
|---|---|
|
|
345
|
-
| `ignoreDomains(...)` / `allowOnlyDomains(...)` | Never record these hosts / record only these |
|
|
346
|
-
| `allowOnlyTLDs('.com', ...)` / `ignoreTLDs('.local', ...)` | Record only / never hosts ending in these |
|
|
347
|
-
| `ignoreDomainPrefixes('dev.', ...)` / `ignoreDomainSuffixes('.cdn.net', ...)` | Never record hosts starting or ending with these |
|
|
348
|
-
| `groupDomains('api.myapp.*', ...)` | Record `api.myapp.com`, `.in`, `.eu`… as one host, `api.myapp.*` |
|
|
349
|
-
| `ignoreEndpoint('/health', '/internal/*', '/users/{id}/x', '/debug/**')` | Never record these paths: exact, `*` or `{name}` for one segment, `**` at the end for everything under it |
|
|
350
|
-
| `addPattern('/v1/accounts/{accountId}')` | Record a matching path as the pattern, each `{name}` as `*`. Tried before auto-detection |
|
|
351
|
-
| `preserveSegments('v1', '404', ...)` | Never turn these segments into `*` |
|
|
352
|
-
| `autoDetection(false)` | Normalize only `addPattern` matches; record every other path as it is |
|
|
353
|
-
|
|
354
|
-
An ignore rule always wins over an allow list. A second `AppticsApiTracker.configure()` replaces the
|
|
355
|
-
first.
|
|
356
|
-
|
|
357
452
|
The SDK's own requests are never recorded, and neither are calls to `localhost` or a bare IP
|
|
358
453
|
address: the server only accepts hostnames with a dot and a letters-only suffix, so the SDK drops
|
|
359
|
-
those calls and says so in the console. `
|
|
360
|
-
With a `<script>` tag, `
|
|
361
|
-
|
|
454
|
+
those calls and says so in the console. `AppticsApi.setApiTracking(false)` removes the wrappers again.
|
|
455
|
+
With a `<script>` tag, `AppticsApi` is a global as it is here, `AppticsApi.ApiTrackingBuilder`
|
|
456
|
+
included.
|
|
362
457
|
|
|
363
458
|
## Remote Config
|
|
364
459
|
|
|
@@ -367,163 +462,235 @@ Read parameters set in the console. Its own entry point, so apps that don't use
|
|
|
367
462
|
```ts
|
|
368
463
|
import { AppticsRemoteConfig } from '@zoho_apptics/apptics-js-sdk/remote-config';
|
|
369
464
|
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
465
|
+
const banner = await AppticsRemoteConfig.fetchValue('bannerText'); // null if there is none
|
|
466
|
+
const some = await AppticsRemoteConfig.fetchValues(['primaryColor', 'maxItems']);
|
|
467
|
+
// → { primaryColor: '#0b6e4f', maxItems: '10' }
|
|
468
|
+
const all = await AppticsRemoteConfig.fetchValues(); // every parameter
|
|
469
|
+
const fresh = await AppticsRemoteConfig.fetchValue('bannerText', true); // coldFetch: asks the server now
|
|
373
470
|
|
|
374
|
-
//
|
|
375
|
-
AppticsRemoteConfig.setCustomConditionValue('
|
|
471
|
+
// for a custom condition: its name, then this device's values, comma separated
|
|
472
|
+
AppticsRemoteConfig.setCustomConditionValue('is_custom', 'custom_color');
|
|
376
473
|
```
|
|
377
474
|
|
|
475
|
+
A name the console doesn't have is `null`.
|
|
476
|
+
|
|
477
|
+
**How a value is chosen.** The SDK goes through the conditions in the order the console lists them
|
|
478
|
+
(`all_condition`), skipping those that don't apply to the parameter. The first one that matches
|
|
479
|
+
this device gives the parameter's value for it; when none matches, the parameter's default value.
|
|
480
|
+
A condition matches when all of its criteria match this device.
|
|
481
|
+
|
|
378
482
|
Values are text, as the console stores them: `Number(values.maxItems)`,
|
|
379
483
|
`values.showBanner === 'true'` or `JSON.parse(...)` turn them into what the app needs.
|
|
380
484
|
|
|
381
485
|
The SDK fetches once on its own when it starts (or when this module is imported after it has),
|
|
382
486
|
so values are this session's without a call of yours.
|
|
383
487
|
|
|
384
|
-
**Fetching.**
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
488
|
+
**Fetching.** The first fetch of each page load asks for the whole rule set, and its answer
|
|
489
|
+
replaces what was stored. After that the SDK keeps the values up to date by itself: every 3
|
|
490
|
+
minutes, and when the tab comes back after 15 seconds or more away, it asks only for what changed
|
|
491
|
+
since its last fetch and merges that into the stored set. `fetchValue` and `fetchValues` answer
|
|
492
|
+
from those values, so reading a value on every render costs no requests. Each also takes a
|
|
493
|
+
callback, and returns a Promise either way. To ask the server now instead, see
|
|
494
|
+
[Cold fetch](#cold-fetch).
|
|
389
495
|
|
|
390
|
-
**When a fetch fails** (offline, or a server error), they answer with the values fetched before
|
|
391
|
-
|
|
392
|
-
you passed to `fetchValues` — instead.
|
|
496
|
+
**When a fetch fails** (offline, or a server error), they answer with the values fetched before;
|
|
497
|
+
with none fetched yet, `null` (and `fetchValues()` answers with no parameters).
|
|
393
498
|
|
|
394
|
-
**Custom conditions.**
|
|
395
|
-
|
|
396
|
-
condition matches when
|
|
397
|
-
applied at once, without a fetch; an empty value removes
|
|
398
|
-
before `Apptics.init()
|
|
499
|
+
**Custom conditions.** `setCustomConditionValue(conditionname, value)` says what this device is
|
|
500
|
+
for the custom condition with that name in the console, with several values comma separated
|
|
501
|
+
(`'gold,platinum'`). The condition matches when one of them is one of the values it lists. The
|
|
502
|
+
stored rules are applied again at once, without a fetch; an empty value removes it. Values are for
|
|
503
|
+
this page, so set them as the app starts; it works before `Apptics.init()`, and `Apptics.reset()`
|
|
504
|
+
clears them.
|
|
399
505
|
|
|
400
|
-
Conditions on the user
|
|
401
|
-
`
|
|
506
|
+
Conditions on the user, such as the customer group, are re-applied on their own once
|
|
507
|
+
`AppticsUser.setUser` has registered the user, so the next read answers for them.
|
|
402
508
|
|
|
403
509
|
| Call | Notes |
|
|
404
510
|
|---|---|
|
|
405
|
-
| `fetchValue(name, callback?, coldFetch?)` | One parameter for this session; `null` when the console has none. |
|
|
406
|
-
| `fetchValues(
|
|
407
|
-
| `
|
|
408
|
-
| `setCustomConditionValue(key, value)` | What this device is for a custom criteria; an empty value removes it. |
|
|
511
|
+
| `fetchValue(name, callback?, coldFetch?)` | One parameter for this session; `null` when the console has none. `fetchValue(name, coldFetch)` works too. `coldFetch: true` asks the server now (see [Cold fetch](#cold-fetch)). |
|
|
512
|
+
| `fetchValues(names?, callback?, coldFetch?)` | The parameters named in the list, `null` for a missing one; with no names, every parameter. `fetchValues(callback)`, `fetchValues(names, coldFetch)` and `fetchValues(coldFetch)` work too. |
|
|
513
|
+
| `setCustomConditionValue(conditionname, value)` | This device's values for a custom condition, comma separated (`'gold,platinum'`); an empty value removes them. |
|
|
409
514
|
|
|
410
515
|
With a `<script>` tag, `AppticsRemoteConfig` is a global as it is here.
|
|
411
516
|
|
|
517
|
+
### Cold fetch
|
|
518
|
+
|
|
519
|
+
By default `fetchValue` and `fetchValues` answer from the values the page already has, which the
|
|
520
|
+
SDK keeps up to date every 3 minutes. For a value that must be current now, say right after it was
|
|
521
|
+
changed in the console, or before a step that depends on it, pass `true` as the last argument:
|
|
522
|
+
`fetchValue('bannerText', true)`, `fetchValues(['primaryColor', 'maxItems'], true)`,
|
|
523
|
+
`fetchValues(true)` for every parameter, or after a callback, as in
|
|
524
|
+
`fetchValue('bannerText', render, true)`.
|
|
525
|
+
|
|
526
|
+
What a cold fetch does:
|
|
527
|
+
|
|
528
|
+
- It asks the server for the whole rule set now (`getupdates` with `flagtime` 0), whatever the page
|
|
529
|
+
has already fetched, and the answer **replaces** the stored set, as the first fetch of a page
|
|
530
|
+
load does. The value is then chosen from it as usual, and the SDK's 3-minute updates go on from
|
|
531
|
+
there.
|
|
532
|
+
- It waits for start-up, and on a first visit for the device to be registered, before asking:
|
|
533
|
+
calling it straight after `Apptics.init()` is fine.
|
|
534
|
+
- **At most three cold fetches in any minute**, per page. One past that makes no request and
|
|
535
|
+
answers from the values the page already has, as `coldFetch: false` would; with
|
|
536
|
+
`console_log: true`, the console says so.
|
|
537
|
+
- Cold fetches made at the same time share one request.
|
|
538
|
+
- If it fails (offline, or a server error), it answers from the values fetched before, or `null`
|
|
539
|
+
with none fetched yet, as any fetch does.
|
|
540
|
+
|
|
541
|
+
`coldFetch` is `false` by default. Use it for the moments that need it, not on every read: each
|
|
542
|
+
one is a request for the whole rule set.
|
|
543
|
+
|
|
412
544
|
## Remote Logger
|
|
413
545
|
|
|
414
|
-
Send your app's log lines to the console's Remote Logger page with `AppticsLogger`,
|
|
415
|
-
|
|
416
|
-
it
|
|
546
|
+
Send your app's log lines to the console's Remote Logger page with `AppticsLogger`, from its own
|
|
547
|
+
entry point (`@zoho_apptics/apptics-js-sdk/remote-logger`) so apps that don't log don't ship it.
|
|
548
|
+
Nothing is logged on its own: only the lines your app writes, at five levels. A line is recorded as it is written, with no
|
|
549
|
+
switch to turn on first:
|
|
417
550
|
|
|
418
551
|
```ts
|
|
419
|
-
import { AppticsLogger } from '@zoho_apptics/apptics-js-sdk';
|
|
420
|
-
|
|
421
|
-
AppticsLogger.enable();
|
|
552
|
+
import { AppticsLogger } from '@zoho_apptics/apptics-js-sdk/remote-logger';
|
|
422
553
|
|
|
423
|
-
AppticsLogger.
|
|
424
|
-
AppticsLogger.
|
|
425
|
-
AppticsLogger.
|
|
426
|
-
AppticsLogger.
|
|
427
|
-
AppticsLogger.
|
|
428
|
-
|
|
429
|
-
AppticsLogger.disable(); // stops it again
|
|
554
|
+
AppticsLogger.verbose('Cache warmed');
|
|
555
|
+
AppticsLogger.debug('Cart loaded', { items: 3 });
|
|
556
|
+
AppticsLogger.info('Payment started', { orderId: 42, method: 'card' });
|
|
557
|
+
AppticsLogger.warn('Retrying the payment', { attempt: 2 });
|
|
558
|
+
AppticsLogger.error('Payment failed', err); // an Error as properties: sent with its stack
|
|
430
559
|
```
|
|
431
560
|
|
|
432
561
|
| Call | Level on the Remote Logger page |
|
|
433
562
|
|---|---|
|
|
434
|
-
| `AppticsLogger.
|
|
435
|
-
| `AppticsLogger.
|
|
436
|
-
| `AppticsLogger.
|
|
437
|
-
| `AppticsLogger.
|
|
438
|
-
| `AppticsLogger.
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
### SDK diagnostics
|
|
458
|
-
|
|
459
|
-
The SDK also reports its own failures to the same page — an event refused for a bad name, a batch
|
|
460
|
-
that never left, a session that couldn't open — tagged with the module it happened in (`Session`,
|
|
461
|
-
`Screen`, `Event`, `API`, `Properties`). It answers "this app reports no data, what is the SDK
|
|
462
|
-
doing out there?" and carries no app data. It is off by default and separate from `AppticsLogger`:
|
|
563
|
+
| `AppticsLogger.verbose(message, properties?)` | 1, Verbose |
|
|
564
|
+
| `AppticsLogger.debug(message, properties?)` | 2, Debug |
|
|
565
|
+
| `AppticsLogger.info(message, properties?)` | 3, Info |
|
|
566
|
+
| `AppticsLogger.warn(message, properties?)` | 4, Warning |
|
|
567
|
+
| `AppticsLogger.error(message, properties?)` | 5, Error |
|
|
568
|
+
|
|
569
|
+
`properties` is appended to the message: an object as JSON (`Payment started {"orderId":42,"method":"card"}`),
|
|
570
|
+
an `Error` as its stack. Each line records the time it was logged and the function, file and line
|
|
571
|
+
that logged it, even when logged before start-up finishes. Lines are stored before they are sent
|
|
572
|
+
and go out in batches of up to 50: a line survives a failed send and a reload, and is removed once
|
|
573
|
+
the server accepts it. At most 1 MB of lines waits at once, oldest dropped first,
|
|
574
|
+
and a line is trimmed to 10,000 characters. Nothing is recorded while the server has the remote
|
|
575
|
+
logger switched off for the app, or while tracking is off.
|
|
576
|
+
|
|
577
|
+
Lines go out about a second after they're logged: a browser tab can close at any moment, and waiting would lose them.
|
|
578
|
+
|
|
579
|
+
## In-App Feedback
|
|
580
|
+
|
|
581
|
+
The feedback form is its own entry point, so apps that don't use it don't download it. Its
|
|
582
|
+
`AppticsFeedback` has every feedback call: the form, sending without it, and the log and
|
|
583
|
+
diagnostics calls. With a `<script>` tag it is the `AppticsFeedback` global.
|
|
584
|
+
|
|
585
|
+
### Show feedback screen
|
|
463
586
|
|
|
464
587
|
```ts
|
|
465
|
-
|
|
588
|
+
import { AppticsFeedback } from '@zoho_apptics/apptics-js-sdk/feedback';
|
|
589
|
+
|
|
590
|
+
AppticsFeedback.feedbackFormOpen(); // show the form
|
|
591
|
+
AppticsFeedback.feedbackFormClose(); // close it from your own code, when needed
|
|
466
592
|
```
|
|
467
593
|
|
|
468
|
-
|
|
594
|
+
`feedbackFormOpen` takes one options object, which fills the form in for the visitor. Every key is
|
|
595
|
+
optional:
|
|
469
596
|
|
|
470
|
-
|
|
471
|
-
|
|
597
|
+
```ts
|
|
598
|
+
AppticsFeedback.feedbackFormOpen({
|
|
599
|
+
type: AppticsFeedback.AP_FEEDBACK_TYPE.BUG, // the tab it opens on: BUG, FEEDBACK, HELP or REPORT
|
|
600
|
+
message: 'The checkout button does nothing', // text already in the description
|
|
601
|
+
includeLog: true, // start with the log toggle on
|
|
602
|
+
includeDiagnostics: true, // start with the diagnostics toggle on
|
|
603
|
+
attachments: [screenshotFile], // files already attached (a FileList or File[])
|
|
604
|
+
logFiles: [appLogFile], // log files already attached
|
|
605
|
+
isAnonymous: false, // true starts the user picker on Anonymous
|
|
606
|
+
});
|
|
607
|
+
```
|
|
472
608
|
|
|
473
|
-
|
|
609
|
+
Passing values one after another, as `feedbackFormOpen(type, message)`, opens the form with its
|
|
610
|
+
defaults and a console warning.
|
|
611
|
+
|
|
612
|
+
The form brings its own styles, with the npm package and the CDN builds alike: the first
|
|
613
|
+
`feedbackFormOpen()` adds them to the page, so there is no stylesheet to import or link.
|
|
614
|
+
|
|
615
|
+
**Theme:** the form is `light`, `dark`, or `auto` (the default), which follows the visitor's system setting:
|
|
474
616
|
|
|
475
617
|
```ts
|
|
476
|
-
|
|
477
|
-
|
|
618
|
+
Apptics.init({ ...config, feedback_theme: 'dark' });
|
|
619
|
+
```
|
|
478
620
|
|
|
479
|
-
|
|
480
|
-
|
|
621
|
+
`auto` follows the operating system, not the page. A page with its own light and dark modes tells
|
|
622
|
+
the form which one it shows, whenever that changes; a form that is open is restyled at once:
|
|
623
|
+
|
|
624
|
+
```ts
|
|
625
|
+
AppticsFeedback.setFeedbackTheme(isDark ? 'dark' : 'light');
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
The colors are CSS variables on the form, so a page can restyle it without any SDK option. Override them
|
|
629
|
+
where the form is shown, for example to set a brand color:
|
|
630
|
+
|
|
631
|
+
```css
|
|
632
|
+
.zasdk-modal { --zasdk-primary-color: #0b5d8f; }
|
|
481
633
|
```
|
|
482
634
|
|
|
483
|
-
|
|
484
|
-
`
|
|
635
|
+
The main ones are `--zasdk-background-color`, `--zasdk-text-color`, `--zasdk-border-color`,
|
|
636
|
+
`--zasdk-input-background`, `--zasdk-primary-color` (the Send button), `--zasdk-button-text-color`,
|
|
637
|
+
`--zasdk-link-color` and `--zasdk-shadow`.
|
|
638
|
+
|
|
639
|
+
The form is a modal dialog for keyboards and screen readers: it takes focus when it opens, Escape or
|
|
640
|
+
the close control (with Enter or Space) closes it, and it honours `prefers-reduced-motion`.
|
|
485
641
|
|
|
486
|
-
The form offers
|
|
487
|
-
screen recording when the page also loads Zoho Quartz and `Apptics.init()` was given `DC`,
|
|
488
|
-
`quartz_workspace_key` and `quartz_department_key` (see [Configuration](#configuration)).
|
|
489
|
-
Otherwise — or with any of them set to `-` — the recording checkbox and its label are not shown.
|
|
642
|
+
The form offers Feedback (selected by default), Bug, Help and Report, with up to 5 attachments (10 MB total).
|
|
490
643
|
|
|
491
644
|
### Send Feedback/Bug Report programmatically
|
|
492
645
|
|
|
493
646
|
```ts
|
|
494
|
-
import {
|
|
495
|
-
import { AP_FEEDBACK_TYPE } from '@zoho_apptics/apptics-js-sdk';
|
|
647
|
+
import { AppticsFeedback } from '@zoho_apptics/apptics-js-sdk/feedback';
|
|
496
648
|
|
|
497
649
|
try {
|
|
498
|
-
await sendFeedback(
|
|
650
|
+
await AppticsFeedback.sendFeedback({
|
|
651
|
+
type: AppticsFeedback.AP_FEEDBACK_TYPE.BUG, // BUG (0), FEEDBACK (1, the default), HELP (2), REPORT (3)
|
|
652
|
+
message: 'Checkout is broken',
|
|
653
|
+
attachments: [screenshotFile], // at most 5, 10 MB in all
|
|
654
|
+
includeLog: true, // the addFeedbackLog() lines
|
|
655
|
+
includeDiagnostics: true, // the addDiagnosticsInfo() entries and the device details
|
|
656
|
+
isAnonymous: false, // true sends it from nobody
|
|
657
|
+
});
|
|
499
658
|
// sent
|
|
500
659
|
} catch (err) {
|
|
501
660
|
// not sent: the SDK hasn't started (no Apptics.init()), the browser is offline, or the server refused it
|
|
502
661
|
}
|
|
503
662
|
```
|
|
504
663
|
|
|
505
|
-
`sendFeedback(type
|
|
506
|
-
|
|
507
|
-
`
|
|
664
|
+
`AppticsFeedback.sendFeedback(options?)` takes `type`, `message`, `attachments`, `logFiles`,
|
|
665
|
+
`includeDiagnostics`, `includeLog` and `isAnonymous`, all optional. It is sent from the user
|
|
666
|
+
`AppticsUser.setUser` set, or from nobody with `isAnonymous: true`. It returns a Promise that resolves once the
|
|
667
|
+
feedback is sent and rejects when it wasn't. Passing values one after another, as
|
|
668
|
+
`sendFeedback(type, message)`, rejects rather than send an empty report.
|
|
669
|
+
|
|
670
|
+
Feedback is sent even when tracking is off (`NO_TRACKING`): the visitor is choosing to send it.
|
|
671
|
+
Only the feedback goes; nothing else is tracked.
|
|
508
672
|
|
|
509
673
|
### Attach logs and diagnostics with Feedback
|
|
510
674
|
|
|
511
675
|
```ts
|
|
512
|
-
import {
|
|
676
|
+
import { AppticsFeedback } from '@zoho_apptics/apptics-js-sdk/feedback';
|
|
513
677
|
|
|
514
|
-
addFeedbackLog('token refresh failed, retrying'); // one timestamped line
|
|
515
|
-
addDiagnosticsInfo('Auth', 'scheme', 'oauth'); // grouped key/value
|
|
516
|
-
addDiagnosticsInfo('Auth', 'expiry', 3600);
|
|
678
|
+
AppticsFeedback.addFeedbackLog('token refresh failed, retrying'); // one timestamped line
|
|
679
|
+
AppticsFeedback.addDiagnosticsInfo('Auth', 'scheme', 'oauth'); // grouped key/value
|
|
680
|
+
AppticsFeedback.addDiagnosticsInfo('Auth', 'expiry', 3600);
|
|
517
681
|
```
|
|
518
682
|
|
|
519
|
-
|
|
520
|
-
|
|
683
|
+
`addDiagnosticsInfo` needs all three: a heading, a key and a value (`0` and `false` count). An
|
|
684
|
+
entry without one is not recorded, and the console says why.
|
|
685
|
+
|
|
686
|
+
Both calls are on the `/feedback` entry's `AppticsFeedback`, which is where every feedback call
|
|
687
|
+
lives; the main entry point has no `AppticsFeedback`. Nothing is sent as it happens: entries wait in storage until feedback is sent,
|
|
521
688
|
and then travel with it as two text files.
|
|
522
689
|
|
|
523
690
|
| File | Holds | Sent when |
|
|
524
691
|
|---|---|---|
|
|
525
692
|
| `feedbacklog.txt` | `addFeedbackLog` lines, in order, each prefixed with its ISO timestamp | There are lines, unless `includeLog` is `false` |
|
|
526
|
-
| `dyninfo.txt` | `addDiagnosticsInfo` entries as `[heading]` blocks, then a `[Device Info]` block | There are diagnostics, or `
|
|
693
|
+
| `dyninfo.txt` | `addDiagnosticsInfo` entries as `[heading]` blocks, then a `[Device Info]` block | There are diagnostics, or `includeDiagnostics` is `true` |
|
|
527
694
|
|
|
528
695
|
Only the entries a submission actually carried are removed once the server has them, so anything
|
|
529
696
|
recorded while a submission is in flight waits for the next one. Entries older than
|
|
@@ -532,37 +699,35 @@ message is truncated at 10,000 characters, and neither file is sent above 2 MB.
|
|
|
532
699
|
|
|
533
700
|
## Heatmaps
|
|
534
701
|
|
|
535
|
-
Records where people click and how far they scroll, for the console's heatmaps.
|
|
536
|
-
point
|
|
702
|
+
Records where people click and how far they scroll, for the console's heatmaps. It is on the
|
|
703
|
+
main entry point and off until you turn it on.
|
|
537
704
|
|
|
538
705
|
```ts
|
|
539
|
-
import { Apptics } from '@zoho_apptics/apptics-js-sdk';
|
|
540
|
-
import { enableHeatmap } from '@zoho_apptics/apptics-js-sdk/heatmap';
|
|
706
|
+
import { Apptics, AppticsHeatmap } from '@zoho_apptics/apptics-js-sdk';
|
|
541
707
|
|
|
542
708
|
Apptics.init({ ...config, track_heatmap: true });
|
|
543
|
-
// or turn it on later:
|
|
709
|
+
// or turn it on later: AppticsHeatmap.setHeatmapTracking(true)
|
|
544
710
|
```
|
|
545
711
|
|
|
546
|
-
|
|
547
|
-
|
|
712
|
+
`track_heatmap: true` in `Apptics.init()` starts capture with the SDK. With a `<script>` tag it's
|
|
713
|
+
`AppticsHeatmap.setHeatmapTracking()` on the `AppticsHeatmap` global.
|
|
548
714
|
|
|
549
715
|
| Call | Notes |
|
|
550
716
|
|---|---|
|
|
551
|
-
| `
|
|
717
|
+
| `AppticsHeatmap.setHeatmapTracking(enabled?)` | Starts or stops capture; `enabled` defaults to `true`. |
|
|
552
718
|
|
|
553
719
|
Heatmap records go out with the rest of the stored data: on the flush timer, or when you call
|
|
554
|
-
`flush()`.
|
|
720
|
+
`Apptics.flush()`.
|
|
555
721
|
|
|
556
722
|
A click gives coordinates, normalized position, a label for the element, and whether it was
|
|
557
723
|
clickable, repeated in frustration (`is_rage_click`) or changed nothing (`is_dead_click`).
|
|
558
|
-
Scrolling is coalesced into one record per gesture
|
|
724
|
+
Scrolling is coalesced into one record per gesture: direction, duration, velocity and how far
|
|
559
725
|
down the page it left you. At most `heatmap_max_per_session` records per visit (default 500),
|
|
560
726
|
then capture pauses.
|
|
561
727
|
|
|
562
728
|
## Debugging
|
|
563
729
|
|
|
564
|
-
|
|
565
|
-
console logs in the browser.
|
|
730
|
+
Debug mode is off by default; you follow it in the Apptics web console.
|
|
566
731
|
|
|
567
732
|
### Debug mode
|
|
568
733
|
|
|
@@ -575,98 +740,100 @@ link to the server's logs for that request.
|
|
|
575
740
|
Apptics.init({ ...config, debug: true }); // start in debug mode
|
|
576
741
|
|
|
577
742
|
// or turn it on and off at any time
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
enableDebug(); // turn debug mode on
|
|
581
|
-
disableDebug(); // and off again
|
|
743
|
+
Apptics.enableDebug(); // turn debug mode on
|
|
744
|
+
Apptics.disableDebug(); // and off again
|
|
582
745
|
```
|
|
583
746
|
|
|
584
|
-
`enableDebug()` and `disableDebug()` don't need `Apptics.init()`: call it before `Apptics.init()`, while the SDK starts or at any
|
|
747
|
+
`Apptics.enableDebug()` and `Apptics.disableDebug()` don't need `Apptics.init()`: call it before `Apptics.init()`, while the SDK starts or at any
|
|
585
748
|
time after, and it takes effect at once. What the app chooses this way holds for the rest of the
|
|
586
|
-
page's life, over `debug` in `Apptics.init()` and through `reset()`, so a page whose config turns
|
|
587
|
-
debug mode on can still switch it off with `disableDebug()`. With a `<script>` tag they are
|
|
588
|
-
`
|
|
749
|
+
page's life, over `debug` in `Apptics.init()` and through `Apptics.reset()`, so a page whose config turns
|
|
750
|
+
debug mode on can still switch it off with `Apptics.disableDebug()`. With a `<script>` tag they are
|
|
751
|
+
the same calls on the `Apptics` global.
|
|
589
752
|
|
|
590
753
|
Debug mode changes where payloads go, not what is in them. It switches itself off after an hour
|
|
591
754
|
with nothing tracked, so a forgotten tab stops tracing on its own.
|
|
592
755
|
|
|
593
756
|
| Key / call | Default | Notes |
|
|
594
757
|
|---|---|---|
|
|
595
|
-
| `debug` | `false` | Start in debug mode, unless the app has already called `enableDebug()` or `disableDebug()`. |
|
|
596
|
-
| `enableDebug()` / `disableDebug()` | | Turn debug mode on or off, with or without `Apptics.init()`. |
|
|
758
|
+
| `debug` | `false` | Start in debug mode, unless the app has already called `Apptics.enableDebug()` or `Apptics.disableDebug()`. |
|
|
759
|
+
| `Apptics.enableDebug()` / `Apptics.disableDebug()` | | Turn debug mode on or off, with or without `Apptics.init()`. |
|
|
597
760
|
| `device_name` | unset | Names this device in the debug stream, so testers on the same build can tell their requests apart. Without it, while debug mode is on, a name is made from the browser and OS. |
|
|
598
761
|
|
|
599
|
-
### Console logs
|
|
600
|
-
|
|
601
|
-
Log the SDK's activity — what it tracks, stores and sends, and the trace of each debug-mode
|
|
602
|
-
request — to the browser console:
|
|
603
|
-
|
|
604
|
-
```ts
|
|
605
|
-
Apptics.init({ ...config, console_log: true });
|
|
606
|
-
```
|
|
607
|
-
|
|
608
762
|
## Configuration
|
|
609
763
|
|
|
610
764
|
Everything `Apptics.init(config)` accepts.
|
|
611
765
|
|
|
612
766
|
| Key | Required | Description |
|
|
613
767
|
|---|---|---|
|
|
614
|
-
| `
|
|
615
|
-
| `
|
|
616
|
-
| `
|
|
768
|
+
| `base_url` | yes | The Apptics host every request goes to, from the Apptics web console (a trailing slash is ignored) |
|
|
769
|
+
| `auth_key` | yes | The app's auth key, from the Apptics web console |
|
|
770
|
+
| `app_domain` | yes | The app's domain registered in the Apptics web console, e.g. `com.zylker.web` |
|
|
617
771
|
| `appversion` | yes | Your app's version, e.g. `2.4.0`. No default: everything the SDK reports is tied to the build it came from. Changing it registers the new version |
|
|
618
|
-
| `debug` | | Debug mode: follow requests in the Apptics web console (see [Debugging](#debugging)) |
|
|
619
|
-
| `
|
|
620
|
-
| `
|
|
621
|
-
| `
|
|
622
|
-
| `
|
|
623
|
-
| `show_logs` | | Also print the app's `AppticsLogger` lines to the browser console, like Android's `showLogs` (see [Remote Logger](#remote-logger)) |
|
|
624
|
-
| `track_api` | | Record the app's own fetch and XHR calls. Off by default; which hosts and endpoints, through `AppticsApiTracker.configure` (see [API Tracking](#api-tracking)) |
|
|
625
|
-
| `track_heatmap`, `heatmap_max_per_session` | | Record clicks and scrolls (see [Heatmaps](#heatmaps)) |
|
|
772
|
+
| `debug` | | Debug mode: follow requests in the Apptics web console (see [Debugging](#debugging)). Off by default |
|
|
773
|
+
| `ignore_do_not_track` | | Track even when the browser sends Do Not Track. Off by default |
|
|
774
|
+
| `track_api` | | Record the app's own fetch and XHR calls. Off by default; which hosts and endpoints, through `AppticsApi.configure` (see [API Tracking](#api-tracking)) |
|
|
775
|
+
| `track_heatmap` | | Record clicks and scrolls (see [Heatmaps](#heatmaps)). Off by default |
|
|
776
|
+
| `heatmap_max_per_session` | | Most heatmap records one visit may produce: 500 by default, 0 to 10000. Capture pauses past it |
|
|
626
777
|
| `track_screen` | | Record a screen view for every navigation, named by its path. On by default; `false` turns it off (see [Automatic screen tracking](#automatic-screen-tracking)) |
|
|
778
|
+
| `track_error` | | Record uncaught errors and unhandled promise rejections. On by default; `false` turns it off (see [Error Tracking](#error-tracking)) |
|
|
779
|
+
| `track_click` | | Record clicks on elements tagged `apeventaction`. On by default; `false` turns it off (see [Click tracking](#click-tracking)) |
|
|
780
|
+
| `screen_routes` | | How automatic screen tracking names a path: route patterns (`'/users/{id}/orders'`), `{ equals, name }` and `{ regex, name }` rules, tried in order (see [Automatic screen tracking](#automatic-screen-tracking)) |
|
|
781
|
+
| `feedback_theme` | | The feedback form's theme: `'light'`, `'dark'` or `'auto'` (the default, which follows the visitor's system setting). See [Show feedback screen](#show-feedback-screen) |
|
|
627
782
|
| `device_name` | | Names this device in debug mode (see [Debugging](#debugging)) |
|
|
628
|
-
| `DC`, `quartz_workspace_key`, `quartz_department_key` | | Enable Quartz screen recording in the feedback form (`DC`: US, EU, IN, AU, CN, CA, JP, SA, AE; `-` disables). The recording checkbox is shown only when all three are set and the page has loaded Quartz |
|
|
629
783
|
|
|
630
|
-
The
|
|
784
|
+
The earlier names still work, with a console warning naming the key to use: `serviceUrl` and
|
|
785
|
+
`base_domain` for `base_url`, `zak` and `token` for `auth_key`, and `identifier` for `app_domain`.
|
|
631
786
|
`aaid`, `zsoid` and `projectID` are no longer needed, and are ignored if passed.
|
|
632
787
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
788
|
+
**Changing `base_url`, `app_domain` or `auth_key`.** What the SDK stores in a browser belongs to
|
|
789
|
+
the app it was registered with. When a page starts with a different `base_url`, `app_domain` or
|
|
790
|
+
`auth_key` from the stored data's, the SDK clears all of it, unsent data included, and starts as on
|
|
791
|
+
a first visit: the app version and the device are registered again. Only a short fingerprint of
|
|
792
|
+
`auth_key` is stored, not the key itself.
|
|
636
793
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
| `batch_flush_interval` | `30000` | 1000 – 3600000 | How often stored data is sent, in milliseconds |
|
|
640
|
-
| `getupdates_interval` | `120000` | 10000 – 86400000 | How often the server's tracking settings are checked, in milliseconds; the server can ask for a longer wait |
|
|
641
|
-
| `batch_size` | `50` | 1 – 500 | Most items in one request (also capped at 1 MB) |
|
|
642
|
-
| `batch_request_timeout` | `7` | 1 – 30 | Days an unsent item is kept before it is dropped |
|
|
643
|
-
| `inactiveduration` | `30` | 1 – 1440 | Idle minutes that end a session |
|
|
644
|
-
| `min_session_duration` | `5000` | 0 – 60000 | Milliseconds a visit must last before its session is recorded; anything tracked sooner records it at once. `0` turns the wait off |
|
|
794
|
+
`Apptics.flush()` sends at most once every 15 seconds, however often it is called: a call sooner
|
|
795
|
+
than that sends nothing, and what is stored goes with the next send.
|
|
645
796
|
|
|
646
|
-
|
|
797
|
+
### Turning automatic tracking on and off
|
|
647
798
|
|
|
648
|
-
|
|
799
|
+
Each tracker the SDK runs on its own has a config key, read when `Apptics.init()` runs, and a call
|
|
800
|
+
to switch it while the page runs. The call takes `true` or `false`; with no argument it means
|
|
801
|
+
`true`.
|
|
649
802
|
|
|
650
|
-
|
|
|
651
|
-
|
|
652
|
-
|
|
|
653
|
-
|
|
|
654
|
-
|
|
|
655
|
-
|
|
|
656
|
-
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
803
|
+
| Tracker | Default | Config key | Call |
|
|
804
|
+
|---|---|---|---|
|
|
805
|
+
| Screen views from the URL | on | `track_screen` | `AppticsScreen.setScreenTracking(enabled)` |
|
|
806
|
+
| Uncaught errors and unhandled rejections | on | `track_error` | `AppticsError.setErrorTracking(enabled)` |
|
|
807
|
+
| Clicks on tagged elements | on | `track_click` | `AppticsEvent.setClickTracking(enabled)` |
|
|
808
|
+
| The app's fetch and XHR calls | off | `track_api` | `AppticsApi.setApiTracking(enabled)` |
|
|
809
|
+
| Clicks and scrolls for heatmaps | off | `track_heatmap` | `AppticsHeatmap.setHeatmapTracking(enabled)` |
|
|
810
|
+
|
|
811
|
+
- The config key decides at start-up. A call made before `Apptics.init()` is replaced by it, and
|
|
812
|
+
`Apptics.reset()` goes back to the config too.
|
|
813
|
+
- The calls you make yourself (`addEvent`, `inScreen`, `trackError`, `startTrackApi`) record
|
|
814
|
+
whichever way a switch is set.
|
|
815
|
+
- To stop all tracking for a visitor, use
|
|
816
|
+
`AppticsSettings.setTrackingStatus(AppticsSettings.AP_TRACKING_STATUS.NO_TRACKING)` instead (see
|
|
817
|
+
[Tracking settings](#tracking-settings)).
|
|
818
|
+
|
|
819
|
+
The 2.0.0-beta.1 names of three of these calls still work, with a console warning naming the one to
|
|
820
|
+
use: `AppticsApi.enableApiTracking`, `AppticsError.trackGlobalErrorHandler` and
|
|
821
|
+
`AppticsHeatmap.trackHeatmap`.
|
|
822
|
+
|
|
823
|
+
### Sessions
|
|
824
|
+
|
|
825
|
+
A session starts with the visit and goes on while the user comes back to the tab within
|
|
826
|
+
`inactiveduration` minutes (30 by default).
|
|
827
|
+
|
|
828
|
+
- When the tab goes inactive (hidden, minimised, or its window loses focus to another one), that
|
|
829
|
+
moment is the session's last active time. Moving focus into an iframe on the page does not count.
|
|
830
|
+
- Back within `inactiveduration`, the same session goes on.
|
|
831
|
+
- Not back by then, the session ends at its last active time and is sent, so the time away is not
|
|
832
|
+
counted. Coming back later starts a new session.
|
|
833
|
+
- A tab closed while inactive ends its session at its last active time too, not when it closed; a
|
|
834
|
+
tab closed while in use ends it then.
|
|
835
|
+
- While another tab of the site is still on the session, a tab that goes inactive or closes only
|
|
836
|
+
leaves it: the last one ends it.
|
|
670
837
|
|
|
671
838
|
## Loading from a CDN
|
|
672
839
|
|
|
@@ -674,35 +841,38 @@ For `<script type="module">`, load the minified ESM build (a few requests instea
|
|
|
674
841
|
|
|
675
842
|
```html
|
|
676
843
|
<script type="module">
|
|
677
|
-
import { Apptics,
|
|
678
|
-
//
|
|
679
|
-
|
|
844
|
+
import { Apptics, AppticsEvent } from 'https://static.zohocdn.com/apptics-js-sdk/2.0.0-beta.2/apptics.esm.min.js';
|
|
845
|
+
// Feedback, remote config and the remote logger are files of their own, so a page downloads
|
|
846
|
+
// only the ones it imports
|
|
847
|
+
import { AppticsFeedback } from 'https://static.zohocdn.com/apptics-js-sdk/2.0.0-beta.2/feedback.esm.min.js';
|
|
848
|
+
import { AppticsRemoteConfig } from 'https://static.zohocdn.com/apptics-js-sdk/2.0.0-beta.2/remoteconfig.esm.min.js';
|
|
849
|
+
import { AppticsLogger } from 'https://static.zohocdn.com/apptics-js-sdk/2.0.0-beta.2/remotelogger.esm.min.js';
|
|
680
850
|
|
|
681
851
|
Apptics.init({
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
852
|
+
base_url: 'YOUR_BASE_URL',
|
|
853
|
+
auth_key: 'YOUR_AUTH_KEY',
|
|
854
|
+
app_domain: 'YOUR_APP_DOMAIN',
|
|
685
855
|
appversion: 'YOUR_APPVERSION', // your app's version
|
|
686
856
|
});
|
|
687
857
|
// screens are tracked from the URL automatically
|
|
688
|
-
|
|
858
|
+
AppticsEvent.addEvent('signup', 'onboarding', { plan: 'pro' });
|
|
689
859
|
</script>
|
|
690
860
|
```
|
|
691
861
|
|
|
692
862
|
| File | For | Size (gzipped) |
|
|
693
863
|
|---|---|---|
|
|
694
|
-
| `
|
|
695
|
-
| `
|
|
696
|
-
| `
|
|
697
|
-
| `
|
|
698
|
-
| `
|
|
864
|
+
| `apptics.min.js` | `<script>` pages; sets `window.apptics`, includes every module | ~53 kB |
|
|
865
|
+
| `apptics.esm.min.js` | `<script type="module">`; the main entry (with the `chunks/` files it imports) | ~32 kB |
|
|
866
|
+
| `feedback.esm.min.js` | `AppticsFeedback`, the feedback form, for module pages | ~17 kB more |
|
|
867
|
+
| `remoteconfig.esm.min.js` | `AppticsRemoteConfig`, for module pages | ~7 kB more |
|
|
868
|
+
| `remotelogger.esm.min.js` | `AppticsLogger`, for module pages | ~1 kB more |
|
|
699
869
|
|
|
700
|
-
The module files share one copy of the SDK through `
|
|
870
|
+
The module files share one copy of the SDK through the `chunks/` folder beside them, so load them all from the same version's folder.
|
|
701
871
|
|
|
702
|
-
|
|
872
|
+
Every release is in a folder of its own, `https://static.zohocdn.com/apptics-js-sdk/{version}/`, holding `apptics.min.js`, `apptics.esm.min.js`, `feedback.esm.min.js`, `remoteconfig.esm.min.js`, `remotelogger.esm.min.js`, `chunks/` and the source maps. Add `defer` if you don't need the SDK before the page renders. For a subresource-integrity hash:
|
|
703
873
|
|
|
704
874
|
```bash
|
|
705
|
-
curl -s https://
|
|
875
|
+
curl -s https://static.zohocdn.com/apptics-js-sdk/2.0.0-beta.2/apptics.min.js \
|
|
706
876
|
| openssl dgst -sha384 -binary | openssl base64 -A
|
|
707
877
|
```
|
|
708
878
|
|
|
@@ -710,51 +880,67 @@ curl -s https://cdn.jsdelivr.net/npm/@zoho_apptics/apptics-js-sdk@2.0.0-beta/dis
|
|
|
710
880
|
<script src="…/apptics.min.js" integrity="sha384-…" crossorigin="anonymous"></script>
|
|
711
881
|
```
|
|
712
882
|
|
|
713
|
-
##
|
|
883
|
+
## Migrating from 1.0.2 to 2.0.0-beta.2
|
|
714
884
|
|
|
715
885
|
### What you need to change
|
|
716
886
|
|
|
717
|
-
- **
|
|
887
|
+
- **Every call is on the object of its feature.** Rename them everywhere, router hooks included: a
|
|
718
888
|
call to an old name left in place throws.
|
|
719
889
|
|
|
720
|
-
| 1.0.2 |
|
|
890
|
+
| 1.0.2 | 2.0.0-beta.2 |
|
|
721
891
|
|---|---|
|
|
722
892
|
| `apptics.init(config)` | `Apptics.init(config)` |
|
|
723
|
-
| `apptics.trackEvent(name, group, props)` | `
|
|
724
|
-
| `apptics.trackScreen(name, props)` | `
|
|
725
|
-
| `apptics.trackError(event, props)` | `
|
|
726
|
-
| `apptics.
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
893
|
+
| `apptics.trackEvent(name, group, props)` | `AppticsEvent.addEvent(eventName, groupName, properties)` |
|
|
894
|
+
| `apptics.trackScreen(name, props)` | `AppticsScreen.inScreen(screenName, properties)`, which also returns the view's id for `AppticsScreen.outScreen(id)` |
|
|
895
|
+
| `apptics.trackError(event, props)` | `AppticsError.trackError(error, properties)` |
|
|
896
|
+
| `apptics.enableGlobalErrorHandler(on)` | `AppticsError.setErrorTracking(enabled)`, or `track_error` in `Apptics.init()` |
|
|
897
|
+
| `apptics.setUser(userid, groupid, props)` | `AppticsUser.setUser(userid, groupid, properties)` |
|
|
898
|
+
| `apptics.getUser()`, `new users.UserBuilder()` | `AppticsUser.getUser()`, `new AppticsUser.UserBuilder()` |
|
|
899
|
+
| `apptics.setTrackingStatus(s)`, `getTrackingStatus()` | `AppticsSettings.setTrackingStatus(status)`, `AppticsSettings.getTrackingStatus()` |
|
|
900
|
+
| `apptics.flush()`, `reset()`, `ready()` | `Apptics.flush()`, `Apptics.reset()`, `Apptics.ready()` |
|
|
901
|
+
| `apptics.feedbackOpen()`, `feedbackClose()` | `AppticsFeedback.feedbackFormOpen(options)`, `AppticsFeedback.feedbackFormClose()` |
|
|
902
|
+
| `apptics.sendFeedback(type, message, …)` | `AppticsFeedback.sendFeedback({ type, message, … })`: one options object |
|
|
903
|
+
| `apptics.addFeedbackLog()`, `addDiagnosticsInfo()` | `AppticsFeedback.addFeedbackLog(message)`, `AppticsFeedback.addDiagnosticsInfo(heading, key, value)` |
|
|
904
|
+
|
|
905
|
+
- **`Apptics.init()` takes new config.** Pass `base_url`, `auth_key`, `app_domain` and `appversion`, all
|
|
906
|
+
required (1.0.2's `base_domain` and `token` still work, with a warning). The SDK gets `aaid` and the portal and project ids from the server itself, so
|
|
907
|
+
`aaid`/`aaID`, `zsoid` and `projectID` are no longer needed and are ignored if passed. Without a
|
|
908
|
+
required key, `Apptics.init()` logs which one is missing and returns `false`.
|
|
909
|
+
- **Every event needs a group.** 1.0.2 filed an event with no group under `default`; now it is
|
|
910
|
+
not logged, and the console says the group is missing. Pass one to every
|
|
911
|
+
`AppticsEvent.addEvent(eventName, groupName, properties?)`, and put an `apgroupaction` around
|
|
912
|
+
every element tracked with `apeventaction`. Defined events bring their own.
|
|
913
|
+
- **`appversion` is required.** 1.0.2 quietly defaulted it to `1.0`, which attributed every session,
|
|
914
|
+
error and crash to a version that was never shipped. Pass your real build version.
|
|
915
|
+
- **npm users can import the SDK.** 1.0.2 exported nothing, so it only worked alongside the console
|
|
916
|
+
snippet. Now:
|
|
733
917
|
|
|
734
918
|
```ts
|
|
735
919
|
import { Apptics } from '@zoho_apptics/apptics-js-sdk';
|
|
736
|
-
Apptics.init({
|
|
920
|
+
Apptics.init({ base_url, auth_key, app_domain, appversion });
|
|
737
921
|
```
|
|
738
922
|
|
|
739
|
-
- **The
|
|
923
|
+
- **The optional modules are their own entry points for npm users**, so an app ships only what it
|
|
924
|
+
uses: `AppticsFeedback` from `/feedback` (every feedback call, logs and diagnostics included; the
|
|
925
|
+
form adds its own styles), `AppticsRemoteConfig` from `/remote-config` and `AppticsLogger` from
|
|
926
|
+
`/remote-logger`. The `<script>` build has everything, as globals and on `window.apptics`.
|
|
740
927
|
|
|
741
928
|
### Behaviour you may notice
|
|
742
929
|
|
|
743
|
-
- **`debug: true` now turns on debug mode** (requests followed in the Apptics web console). In 1.0.2 it logged to the browser console
|
|
744
|
-
- When the Apptics server tells the SDK to stop tracking an app version, it stops; 1.0.2 ignored that signal.
|
|
745
|
-
- `ignore_do_not_track: true` now ignores the browser's Do Not Track setting; in 1.0.2 it disabled tracking.
|
|
746
|
-
- `mute()` and `unmute()` are gone. To stop tracking, use `setTrackingStatus(AP_TRACKING_STATUS.NO_TRACKING)`; unlike `mute()`, it is stored across visits.
|
|
747
|
-
- **Screens are tracked automatically**, from the URL, including single-page route changes. An `
|
|
748
|
-
- **Events and properties
|
|
749
|
-
- Calling `Apptics.init()` a second time is ignored; use `reset()` to start over.
|
|
750
|
-
- `Apptics.init()` still returns at once, but start-up finishes a few milliseconds later, once storage loads, so `window.appticsReady()` fires slightly later than in 1.0.2. Calls made in between are queued and replayed; `await
|
|
751
|
-
- `sendFeedback()` returns a Promise
|
|
930
|
+
- **`debug: true` now turns on debug mode** (requests followed in the Apptics web console). In 1.0.2 it logged to the browser console.
|
|
931
|
+
- When the Apptics server tells the SDK to stop tracking an app version, it stops; 1.0.2 ignored that signal. Events, screens, sessions, API calls and errors each follow their own switch in the Apptics console, so turning one off leaves the others on.
|
|
932
|
+
- `ignore_do_not_track: true` now ignores the browser's Do Not Track setting; in 1.0.2 it disabled tracking. Do Not Track is decided on every visit and never stored.
|
|
933
|
+
- `mute()` and `unmute()` are gone. To stop tracking, use `AppticsSettings.setTrackingStatus(AppticsSettings.AP_TRACKING_STATUS.NO_TRACKING)`; unlike `mute()`, it is stored across visits. Feedback is still sent with tracking off.
|
|
934
|
+
- **Screens are tracked automatically**, from the URL, including single-page route changes. An `AppticsScreen.inScreen()` called from your router replaces the automatic view of that navigation, so nothing is counted twice; `track_screen: false` turns automatic tracking off, and `screen_routes` names paths. Each screen view now records how long it lasted.
|
|
935
|
+
- **Events and properties are checked**: an event with a missing or invalid group is not logged, names and keys may not start with `ap_`, and a bad property is dropped on its own rather than taking the others with it. Booleans arrive as Boolean, and `1` / `0` as Number. An invalid name is said in the console.
|
|
936
|
+
- Calling `Apptics.init()` a second time is ignored; use `Apptics.reset()` to start over.
|
|
937
|
+
- `Apptics.init()` still returns at once, but start-up finishes a few milliseconds later, once storage loads, so `window.appticsReady()` fires slightly later than in 1.0.2. Calls made in between are queued and replayed; `await Apptics.ready()` waits for it. A first visit with no network starts once the browser is back online.
|
|
938
|
+
- `AppticsFeedback.sendFeedback()` returns a Promise. `includeLog` and `includeDiagnostics` are three-way: `true` always sends that file, `false` never does, and leaving it unset sends it when something is stored.
|
|
752
939
|
- `dyninfo.txt` carries the diagnostics entries and a `[Device Info]` block. Stored feedback logs and diagnostics are capped at 1,000 entries and 10,000 characters per message.
|
|
753
|
-
-
|
|
754
|
-
- Clicks tracked with `apeventaction` no longer need jQuery.
|
|
940
|
+
- Clicks tracked with `apeventaction` (or `data-apeventaction`) no longer need jQuery.
|
|
755
941
|
- Data moves from localStorage to IndexedDB on the first visit (device identity, consent, unsent events, feedback log entries), and the old keys are removed. Where IndexedDB is unavailable, the SDK keeps using localStorage.
|
|
756
942
|
- Queued data is sent when the page is hidden or closed, using `pagehide` / `visibilitychange` instead of `beforeunload`.
|
|
757
|
-
- New, and off until you use them: heatmaps, remote config, API tracking
|
|
943
|
+
- New, and off until you use them: heatmaps (`AppticsHeatmap.setHeatmapTracking()`), remote config, API tracking and the remote logger (`AppticsLogger`). Remote config, once imported, fetches its values on start-up.
|
|
758
944
|
|
|
759
945
|
## License
|
|
760
946
|
|