|
1 |
| -# Getting Started with Create React App |
| 1 | +# User Analytics |
2 | 2 |
|
3 |
| -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). |
| 3 | +This library enables tracking of UI events when a user interacts with a React or React Native application. |
| 4 | + |
| 5 | +## Features |
| 6 | +- **Progressive** - Uses latest JavaScript features and design patterns for a React codebase. |
| 7 | +- **Extensible** - A modular architecture and usage of Dependency.Inversion patterns gives you flexibility and allows you to easily extend features. |
| 8 | +- **TypeScript support**. |
| 9 | + |
| 10 | +## Supported events |
| 11 | +- Form Events |
| 12 | + - `onChange` |
| 13 | +- Mouse Events |
| 14 | + - `onClick` |
| 15 | + - `onHover` |
| 16 | + |
| 17 | + |
| 18 | +## Work in Progress |
| 19 | +- Eventually, the library will have exhaustive coverage and support for many more events, such as: |
| 20 | + - Wheel Events |
| 21 | + - Touch Events |
| 22 | + - Keyboard Events |
| 23 | + - Mouse Events |
| 24 | + - and more. |
| 25 | + |
| 26 | +- User Interaction journey mapping |
| 27 | +- Session Recording |
| 28 | + |
| 29 | + |
| 30 | +## Instructions of Usage |
| 31 | +1. First, import the library in your project. |
| 32 | + |
| 33 | +2. In-order to add user-tracking ability to your component or element, import the `withTracking` function (Higher-order component) and wrap the component. Here's an example using a simple `Button` component: |
| 34 | + |
| 35 | +`export const ButtonWithTracking = withTracking(Button)` |
| 36 | + |
| 37 | +`ButtonWithTracking` will have all the features and properties of the `Button` component, but with interaction-tracking superpowers! |
| 38 | + |
| 39 | +3. Finally, use `ButtonWithTracking` inside your app anywhere where you'd like to track user-events occurring on this component, such as `onClick` or `onHover`. |
| 40 | + |
| 41 | +``` |
| 42 | +import Button, { ButtonWithTracking } from '../../elements/Button'; |
| 43 | +
|
| 44 | +function Home() { |
| 45 | +
|
| 46 | + function handleClick(e: React.MouseEvent<HTMLElement, MouseEvent>) { |
| 47 | + // app logic goes here |
| 48 | + } |
| 49 | +
|
| 50 | + function logEvent( |
| 51 | + event: React.MouseEvent<HTMLElement, MouseEvent>, |
| 52 | + interactionResource: UserInteractionResource |
| 53 | + ) { |
| 54 | + /* |
| 55 | + do whatever you want with the resource, |
| 56 | + like save it to IndexedDB, compress it, save it via API, etc |
| 57 | + */ |
| 58 | + console.log(interactionResource); |
| 59 | + } |
| 60 | +
|
| 61 | + return ( |
| 62 | + <ButtonWithTracking |
| 63 | + type="text" |
| 64 | + onClick={handleClick} |
| 65 | +
|
| 66 | + trackers={[ |
| 67 | + // track onClick event |
| 68 | + { |
| 69 | + action: "onClick", // event to track |
| 70 | + track: logEvent, // callback function that runs whenever the event occurs |
| 71 | + } |
| 72 | + ]} |
| 73 | + > |
| 74 | + ) |
| 75 | +} |
| 76 | +
|
| 77 | +export default Home; |
| 78 | +``` |
| 79 | + |
| 80 | +You can add multiple tracker objects within the `trackers` array if you need to track more than one event occurring within the component. |
| 81 | + |
| 82 | + |
| 83 | +## Advanced Usage |
| 84 | + |
| 85 | +### Mapping a user's journey |
| 86 | + |
| 87 | +**Use-case**: |
| 88 | +Say you have 2 react components - a `ButtonWithTracking` configured to track `onClick` events, and a `InputWithTracking` component configured to capture `onChange` events. These components are being used in 2 different pages or templates in your application - a login form, and a newsletter subscription form. |
| 89 | + |
| 90 | +In this scenario, it is useful to capture a global 'context' within which the events occur - such as the page or the container component details, and the app version. This information is useful to plot out the user's journey, which will give you a more contextual understanding of how the user navigates through your app. |
4 | 91 |
|
5 |
| -## Available Scripts |
| 92 | +- #### Provide and capture contextual data using React Context Provider `<DataContext.Provider>` |
| 93 | +Using the `<DataContext.Provider>`, you can provide the global 'context' to your tracking components without having to pass them explicitly via props. Here's how: |
6 | 94 |
|
7 |
| -In the project directory, you can run: |
| 95 | + - Create a `DataContext` object. |
| 96 | +``` |
| 97 | +const dataContext = { |
| 98 | + context: "Login Form", |
| 99 | + app: { |
| 100 | + version: "1", |
| 101 | + }, |
| 102 | +} as UserInteraction.DataContext; |
| 103 | +``` |
8 | 104 |
|
9 |
| -### `yarn start` |
| 105 | + - Next, wrap your template or container component within `DataContext.Provider` and provide it the `dataContext` value: |
10 | 106 |
|
11 |
| -Runs the app in the development mode.\ |
12 |
| -Open [http://localhost:3000](http://localhost:3000) to view it in the browser. |
| 107 | +``` |
| 108 | +import { DataContext } from '../../../library/user-analytics/react/contexts/dataContext'; |
| 109 | +import Button, { ButtonWithTracking } from '../../elements/Button'; |
13 | 110 |
|
14 |
| -The page will reload if you make edits.\ |
15 |
| -You will also see any lint errors in the console. |
| 111 | +function LoginForm() { |
16 | 112 |
|
17 |
| -### `yarn test` |
| 113 | + function logEvent( |
| 114 | + event: React.MouseEvent<HTMLElement, MouseEvent>, |
| 115 | + interactionResource: UserInteractionResource |
| 116 | + ) { |
| 117 | + console.log(interactionResource.app.version) // Will print "1" |
| 118 | + console.log(interactionResource.source.context); // Will print "Login Form" |
18 | 119 |
|
19 |
| -Launches the test runner in the interactive watch mode.\ |
20 |
| -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. |
| 120 | + } |
21 | 121 |
|
22 |
| -### `yarn build` |
| 122 | + return ( |
| 123 | + <DataContext.Provider value={dataContext}> // Pass the dataContext value |
| 124 | + <ButtonWithTracking |
| 125 | + type="text" |
| 126 | + onClick={handleClick} |
23 | 127 |
|
24 |
| -Builds the app for production to the `build` folder.\ |
25 |
| -It correctly bundles React in production mode and optimizes the build for the best performance. |
| 128 | + trackers={[ |
| 129 | + // track onClick event |
| 130 | + { |
| 131 | + action: "onClick", |
| 132 | + track: logEvent, |
| 133 | + |
| 134 | + data: { // pass optional custom data |
| 135 | + color: "blue", |
| 136 | + } |
| 137 | + } |
| 138 | + ]} |
| 139 | + > |
| 140 | + </DataContext.Provider> |
| 141 | + ) |
| 142 | +} |
26 | 143 |
|
27 |
| -The build is minified and the filenames include the hashes.\ |
28 |
| -Your app is ready to be deployed! |
| 144 | +export default LoginForm; |
29 | 145 |
|
30 |
| -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. |
| 146 | +``` |
31 | 147 |
|
32 |
| -### `yarn eject` |
| 148 | +This way, your tracking components nested anywhere within the provider will receive the `dataContext` object and will return it as part of the `UserInteractionResource` object. |
33 | 149 |
|
34 |
| -**Note: this is a one-way operation. Once you `eject`, you can’t go back!** |
35 | 150 |
|
36 |
| -If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. |
| 151 | +- #### Providing Data Context as regular props |
37 | 152 |
|
38 |
| -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. |
| 153 | +If you don't want to provide data using `DataContext.Provider` or want to override it with a different value, you can pass them explicitly via props: |
39 | 154 |
|
40 |
| -You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. |
| 155 | +``` |
| 156 | +function LoginForm() { |
41 | 157 |
|
42 |
| -## Learn More |
| 158 | + function logEvent( |
| 159 | + event: React.MouseEvent<HTMLElement, MouseEvent>, |
| 160 | + interactionResource: UserInteractionResource |
| 161 | + ) { |
| 162 | + console.log(interactionResource.app.version) // Will print "0" |
| 163 | + console.log(interactionResource.source.context); // Will print "Login Form" |
43 | 164 |
|
44 |
| -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). |
| 165 | + } |
45 | 166 |
|
46 |
| -To learn React, check out the [React documentation](https://reactjs.org/). |
| 167 | + return ( |
| 168 | + <ButtonWithTracking |
| 169 | + type="text" |
| 170 | + onClick={handleClick} |
| 171 | +
|
| 172 | + trackers={[ |
| 173 | + // track onClick event |
| 174 | + { |
| 175 | + action: "onClick", |
| 176 | + track: logEvent, |
| 177 | + |
| 178 | + data: { // pass optional custom data |
| 179 | + color: "blue", |
| 180 | + } |
| 181 | + } |
| 182 | + ]} |
| 183 | + |
| 184 | + dataContext={{ // Pass dataContext explicitly |
| 185 | + app: { |
| 186 | + version: "0", |
| 187 | + }, |
| 188 | + context: "Login Form" |
| 189 | + }} |
| 190 | + > |
| 191 | + ) |
| 192 | +} |
| 193 | +
|
| 194 | +export default LoginForm; |
| 195 | +
|
| 196 | +``` |
| 197 | + |
| 198 | +In-case you have both in your application, the data context passed via props will override the values from ` <DataContext.Provider>` |
| 199 | + |
| 200 | + |
| 201 | +## API |
| 202 | + |
| 203 | +### React |
| 204 | + |
| 205 | +- #### Tracking Component Props |
| 206 | + |
| 207 | + The tracking-enabled component will accept all props required for the original component, along with the following: |
| 208 | + |
| 209 | + | Props | Required | Description | Type | |
| 210 | + | :--- | :----: | :----: | ---: | |
| 211 | + | `trackers` |Yes |Each tracker object expects an `action` and `track` properties. Check the section below for the complete list of properties | `UserInteraction.Tracker[]` | |
| 212 | + | `origin` |Optional | To provide some contextual information for the event origin | `string` | |
| 213 | + | `dataContext` |Optional |an object property to provide context of the taken event | `UserInteraction.DataContext`| |
| 214 | + |
| 215 | + |
| 216 | +- #### `UserInteraction.Tracker` object properties |
| 217 | + |
| 218 | + | Property | Required | Description | Type | |
| 219 | + | :--- | :----: | :----: | ---: | |
| 220 | + | `action` | Yes | Type of event that needs to be tracked (React Synthetic events). Can take values such as `onClick`, `onChange` | `string` | |
| 221 | + | `track` | Yes| Callback that runs when above event occurs | `(e, interactionResource: UserInteractionResource) => void` | |
| 222 | + | `data` | Optional | Can be used to provide some custom data. Accessible within `UserInteractionResource.data` | `Object<any>` | |
| 223 | + |
| 224 | + |
| 225 | + |
| 226 | +### Interfaces |
| 227 | + |
| 228 | +- #### `UserInteractionResource` |
| 229 | +The `UserInteractionResource` object contains all properties from `BaseResource`, along with the following: |
| 230 | + |
| 231 | +``` |
| 232 | +type: typeof UserInteraction.TYPE; // "UserInteraction" |
| 233 | +action: UserInteraction.Action; // Type of the event, such as "onClick", "onChange" |
| 234 | +source: { |
| 235 | + context: string; // To capture a "global" context of the event, such as "Landing page" or "Login form" |
| 236 | + origin?: string; |
| 237 | + component: string; // Name of the React component |
| 238 | + element: { |
| 239 | + currentTarget: string; |
| 240 | + target: string; |
| 241 | + innerHTML?: string; |
| 242 | + innerText?: string; |
| 243 | + value?: string; |
| 244 | + }; |
| 245 | +}; |
| 246 | +data?: Object<any>; // Additional custom data that needs to be captured |
| 247 | +``` |
| 248 | + |
| 249 | +- #### `BaseResource` |
| 250 | + |
| 251 | +``` |
| 252 | +app: { |
| 253 | + version: string, |
| 254 | +}; |
| 255 | +date: Date; |
| 256 | +browser: { |
| 257 | + name: string, |
| 258 | + version: string, |
| 259 | + userAgent: string, |
| 260 | + platform: string, |
| 261 | + window: { |
| 262 | + width: number, |
| 263 | + height: number, |
| 264 | + } |
| 265 | +}; |
| 266 | +os: { |
| 267 | + name: string, |
| 268 | + version: string, |
| 269 | +}; |
| 270 | +
|
| 271 | +``` |
| 272 | + |
| 273 | +## Check out the [docs](./docs) folder for a complete list of API reference. |
| 274 | + |
| 275 | +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). |
0 commit comments