@zoho_apptics/apptics-js-sdk 2.0.0-beta → 2.0.0-beta.1

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