|
| 1 | +# Hawk JavaScript Catcher |
| 2 | + |
| 3 | +Error tracking for JavaScript/TypeScript applications. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- 🦅 Automatic error catching |
| 8 | +- 💎 Manual error and logs sending |
| 9 | +- 🙂 Attaching user information |
| 10 | +- 📦 Attaching additional context |
| 11 | +- 🛡️ Sensitive data filtering |
| 12 | +- 🌟 Source maps consuming |
| 13 | +- 💬 Console logs tracking |
| 14 | +- <img src="https://cdn.svglogos.dev/logos/vue.svg" width="16" height="16"> Vue support |
| 15 | +- <img src="https://cdn.svglogos.dev/logos/react.svg" width="16" height="16"> React support |
| 16 | + |
| 17 | + |
| 18 | +## Installation |
| 19 | + |
| 20 | +We recommend adding Hawk script to page above others to prevent missing any errors. |
| 21 | + |
| 22 | +### Install via NPM or Yarn |
| 23 | + |
| 24 | +Install package |
| 25 | + |
| 26 | +```shell |
| 27 | +npm install @hawk.so/javascript --save |
| 28 | +``` |
| 29 | + |
| 30 | +```shell |
| 31 | +yarn add @hawk.so/javascript |
| 32 | +``` |
| 33 | + |
| 34 | +Then import `@hawk.so/javascript` module to your code. |
| 35 | + |
| 36 | +```js |
| 37 | +import HawkCatcher from '@hawk.so/javascript'; |
| 38 | +``` |
| 39 | + |
| 40 | +### Load from CDN |
| 41 | + |
| 42 | +Get a specific version bundle path from [@hawk.so/javascript](https://www.jsdelivr.com/package/npm/@hawk.so/javascript) |
| 43 | +— open the page and copy the link. Do not use @latest, as your setup may break in case of a major API update. |
| 44 | + |
| 45 | +Then require this script on your site. |
| 46 | + |
| 47 | +``` |
| 48 | +<script src="..." async></script> |
| 49 | +``` |
| 50 | + |
| 51 | +## Usage |
| 52 | + |
| 53 | +### Get an Integration Token |
| 54 | + |
| 55 | +First of all, you should register an account on |
| 56 | +[hawk.so](https://hawk-tracker.ru/signup?utm_source=github&utm_medium=readme&utm_campaign=js_sdk&utm_content=signup_link). |
| 57 | + |
| 58 | +Then create a Workspace and a Project in there. You'll get an Integration Token. |
| 59 | + |
| 60 | +### Initialize Catcher |
| 61 | + |
| 62 | +Create `HawkCatcher` class instance when script will be ready and pass your Integration Token: |
| 63 | + |
| 64 | +```js |
| 65 | +const hawk = new HawkCatcher({token: 'INTEGRATION_TOKEN'}); |
| 66 | + |
| 67 | +// or |
| 68 | + |
| 69 | +const hawk = new HawkCatcher('INTEGRATION_TOKEN'); |
| 70 | +``` |
| 71 | + |
| 72 | +Alternately, add `onload="const hawk = new HawkCatcher({token: 'INTEGRATION_TOKEN'})"` attribute to the `<script>` tag. |
| 73 | + |
| 74 | +```html |
| 75 | +<script src="https://cdn.jsdelivr.net/npm/@hawk.so/javascript@latest/dist/hawk.js" |
| 76 | + onload="const hawk = new HawkCatcher({token: 'INTEGRATION_TOKEN'})"></script> |
| 77 | +``` |
| 78 | + |
| 79 | +Initialization settings: |
| 80 | + |
| 81 | +| name | type | required | description | |
| 82 | +|-------------------------------|-----------------------------------------------------------|--------------|-------------------------------------------------------------------------------------| |
| 83 | +| `token` | string | **required** | Your project's Integration Token | |
| 84 | +| `release` | string/number | optional | Unique identifier of the release. Used for source map consuming (see below) | |
| 85 | +| `user` | {id: string, name?: string, image?: string, url?: string} | optional | Current authenticated user | |
| 86 | +| `context` | object | optional | Any data you want to pass with every message. Has limitation of length. | |
| 87 | +| `vue` | Vue constructor | optional | Pass Vue constructor to set up the [Vue integration](#integrate-to-vue-application) | |
| 88 | +| `disableGlobalErrorsHandling` | boolean | optional | Do not initialize global errors handling | |
| 89 | +| `disableVueErrorHandler` | boolean | optional | Do not initialize Vue errors handling | |
| 90 | +| `consoleTracking` | boolean | optional | Initialize console logs tracking | |
| 91 | +| `breadcrumbs` | false or BreadcrumbsOptions object | optional | Configure breadcrumbs tracking (see below) | |
| 92 | +| `beforeSend` | function(event) => event | optional | This Method allows you to filter any data you don't want sending to Hawk | |
| 93 | + |
| 94 | +Other available [initial settings](types/hawk-initial-settings.d.ts) are described at the type definition. |
| 95 | + |
| 96 | +## Manual sending |
| 97 | + |
| 98 | +You can send errors or other messages to the Hawk manually, for example at your `catch` blocks or any debug conditions. |
| 99 | + |
| 100 | +Use the `.send(message, context)` method for that. This method accepts the `message` of type `Error` or `string` |
| 101 | +as the first parameter. The second parameter is optional, it allows passing any additional data with the event. |
| 102 | +If you specify the `context` with the `HawkCatcher` constructor, it will be merged with the context passed to the `send` |
| 103 | +method. |
| 104 | + |
| 105 | +```js |
| 106 | +// init Hawk Catcher instance |
| 107 | +const hawk = new HawkCatcher({token: 'INTEGRATION_TOKEN'}); |
| 108 | + |
| 109 | +// somewhere in try-catch block or other custom place |
| 110 | +hawk.send(new Error('Something went wrong'), { |
| 111 | + myOwnDebugInfo: '1234', |
| 112 | +}); |
| 113 | +``` |
| 114 | + |
| 115 | +## User Management |
| 116 | + |
| 117 | +You can dynamically manage user information after the catcher is initialized: |
| 118 | + |
| 119 | +```js |
| 120 | +const hawk = new HawkCatcher({token: 'INTEGRATION_TOKEN'}); |
| 121 | + |
| 122 | +// Set user information |
| 123 | +hawk.setUser({ |
| 124 | + id: 'user123', |
| 125 | + name: 'John Doe', |
| 126 | + url: '/users/123', |
| 127 | + image: 'https://example.com/avatar.jpg', |
| 128 | +}); |
| 129 | + |
| 130 | +// Clear user (revert to generated user) |
| 131 | +hawk.clearUser(); |
| 132 | +``` |
| 133 | + |
| 134 | +## Context Management |
| 135 | + |
| 136 | +You can dynamically update context data that will be sent with all events: |
| 137 | + |
| 138 | +```js |
| 139 | +const hawk = new HawkCatcher({token: 'INTEGRATION_TOKEN'}); |
| 140 | + |
| 141 | +// Set context data |
| 142 | +hawk.setContext({ |
| 143 | + feature: 'user-dashboard', |
| 144 | + version: '2.1.0', |
| 145 | + environment: 'production', |
| 146 | +}); |
| 147 | +``` |
| 148 | + |
| 149 | +## Breadcrumbs |
| 150 | + |
| 151 | +Breadcrumbs track user interactions and events leading up to an error, providing context for debugging. |
| 152 | + |
| 153 | +### Default Configuration |
| 154 | + |
| 155 | +By default, breadcrumbs are enabled with tracking for fetch/XHR requests, navigation, and UI clicks: |
| 156 | + |
| 157 | +```js |
| 158 | +const hawk = new HawkCatcher({ |
| 159 | + token: 'INTEGRATION_TOKEN' |
| 160 | + // breadcrumbs enabled by default |
| 161 | +}); |
| 162 | +``` |
| 163 | + |
| 164 | +### Disabling Breadcrumbs |
| 165 | + |
| 166 | +To disable breadcrumbs entirely: |
| 167 | + |
| 168 | +```js |
| 169 | +const hawk = new HawkCatcher({ |
| 170 | + token: 'INTEGRATION_TOKEN', |
| 171 | + breadcrumbs: false |
| 172 | +}); |
| 173 | +``` |
| 174 | + |
| 175 | +### Custom Configuration |
| 176 | + |
| 177 | +Configure breadcrumbs tracking behavior: |
| 178 | + |
| 179 | +```js |
| 180 | +const hawk = new HawkCatcher({ |
| 181 | + token: 'INTEGRATION_TOKEN', |
| 182 | + breadcrumbs: { |
| 183 | + maxBreadcrumbs: 20, // Maximum breadcrumbs to store (default: 15) |
| 184 | + trackFetch: true, // Track fetch/XHR requests (default: true) |
| 185 | + trackNavigation: true, // Track navigation events (default: true) |
| 186 | + trackClicks: true, // Track UI clicks (default: true) |
| 187 | + beforeBreadcrumb: (breadcrumb, hint) => { |
| 188 | + // Filter or modify breadcrumbs before storing |
| 189 | + if (breadcrumb.category === 'fetch' && breadcrumb.data?.url?.includes('/sensitive')) { |
| 190 | + return null; // Discard this breadcrumb |
| 191 | + } |
| 192 | + return breadcrumb; |
| 193 | + } |
| 194 | + } |
| 195 | +}); |
| 196 | +``` |
| 197 | +
|
| 198 | +### Breadcrumbs Options |
| 199 | +
|
| 200 | +| Option | Type | Default | Description | |
| 201 | +|--------------------|------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 202 | +| `maxBreadcrumbs` | `number` | `15` | Maximum number of breadcrumbs to store. When the limit is reached, oldest breadcrumbs are removed (FIFO). | |
| 203 | +| `trackFetch` | `boolean` | `true` | Automatically track `fetch()` and `XMLHttpRequest` calls as breadcrumbs. Captures request URL, method, status code, and response time. | |
| 204 | +| `trackNavigation` | `boolean` | `true` | Automatically track navigation events (History API: `pushState`, `replaceState`, `popstate`). Captures route changes. | |
| 205 | +| `trackClicks` | `boolean` | `true` | Automatically track UI click events. Captures element selector, coordinates, and other click metadata. | |
| 206 | +| `beforeBreadcrumb` | `function` | `undefined` | Hook called before each breadcrumb is stored. Receives `(breadcrumb, hint)` and can return modified breadcrumb, `null` to discard it, or the original breadcrumb. Useful for filtering sensitive data or PII. | |
| 207 | + |
| 208 | +### Manual Breadcrumbs |
| 209 | + |
| 210 | +Add custom breadcrumbs manually: |
| 211 | + |
| 212 | +```js |
| 213 | +hawk.breadcrumbs.add({ |
| 214 | + type: 'logic', |
| 215 | + category: 'auth', |
| 216 | + message: 'User logged in', |
| 217 | + level: 'info', |
| 218 | + data: { userId: '123' } |
| 219 | +}); |
| 220 | +``` |
| 221 | +
|
| 222 | +### Breadcrumb Methods |
| 223 | +
|
| 224 | +```js |
| 225 | +// Add a breadcrumb |
| 226 | +hawk.breadcrumbs.add(breadcrumb, hint); |
| 227 | + |
| 228 | +// Get current breadcrumbs |
| 229 | +const breadcrumbs = hawk.breadcrumbs.get(); |
| 230 | + |
| 231 | +// Clear all breadcrumbs |
| 232 | +hawk.breadcrumbs.clear(); |
| 233 | +``` |
| 234 | +
|
| 235 | +## Source maps consuming |
| 236 | +
|
| 237 | +If your bundle is minified, it is useful to pass source-map files to the Hawk. After that you will see beautiful |
| 238 | +original source code lines in Hawk Garage instead of minified code. |
| 239 | +
|
| 240 | +To enable source map consuming you should do two things: |
| 241 | +
|
| 242 | +- Send the source map and the release identifier to the Hawk after you build a new version of the script. For example |
| 243 | + with the [Hawk Webpack Plugin](https://github.com/codex-team/hawk.webpack.plugin) or with cURL request. |
| 244 | +- Pass the release identifier to the Hawk Catcher using `release` option. |
| 245 | +
|
| 246 | +## Testing and server responses |
| 247 | +
|
| 248 | +To make sure that Hawk is working right, call `test()` method from `HawkCatcher` class instance in browser's console. |
| 249 | +`test()` method sends fake error to server. Then, open Hawk and find a test event at the Project's page. |
| 250 | +
|
| 251 | +## Sensitive data filtering |
| 252 | +
|
| 253 | +You can filter any data that you don't want to send to Hawk. Use the `beforeSend()` hook for that reason. |
| 254 | +
|
| 255 | +```js |
| 256 | +window.hawk = new HawkCatcher({ |
| 257 | + token: 'INTEGRATION TOKEN', |
| 258 | + beforeSend(event) { |
| 259 | + if (event.user && event.user.name) { |
| 260 | + delete event.user.name; |
| 261 | + } |
| 262 | + |
| 263 | + return event; |
| 264 | + } |
| 265 | +}) |
| 266 | +``` |
| 267 | +
|
| 268 | +## Dismiss error |
| 269 | +
|
| 270 | +You can use the `beforeSend()` hook to prevent sending a particular event. Return `false` for that. |
| 271 | +
|
| 272 | +## Usage with <img src="https://cdn.svglogos.dev/logos/vue.svg" width="22"> Vue.js |
| 273 | +
|
| 274 | +Vue apps have their own error handler, so if you want to catcher errors thrown inside Vue components, you should set up |
| 275 | +a Vue integration. |
| 276 | +
|
| 277 | +Pass the Vue constructor with the initial settings: |
| 278 | +
|
| 279 | +```js |
| 280 | +import Vue from 'vue'; |
| 281 | + |
| 282 | +const hawk = new HawkCatcher({ |
| 283 | + token: 'INTEGRATION_TOKEN', |
| 284 | + vue: Vue // the Vue constructor you tweak |
| 285 | +}); |
| 286 | +``` |
| 287 | +
|
| 288 | +or pass it any moment after Hawk Catcher was instantiated: |
| 289 | +
|
| 290 | +```js |
| 291 | +import Vue from 'vue'; |
| 292 | + |
| 293 | +const hawk = new HawkCatcher({ |
| 294 | + token: 'INTEGRATION_TOKEN', |
| 295 | +}); |
| 296 | + |
| 297 | +hawk.connectVue(Vue) |
| 298 | +``` |
| 299 | +
|
| 300 | +## Usage with <img src="https://cdn.svglogos.dev/logos/react.svg" width="22"> React |
| 301 | +
|
| 302 | +React is suppported out of the box. No additional setup required. |
| 303 | +
|
| 304 | +Create the Hawk Catcher instance in a `index.js` file of your project. |
| 305 | +
|
| 306 | +```js |
| 307 | +import HawkCatcher from '@hawk.so/javascript'; |
| 308 | + |
| 309 | +const hawk = new HawkCatcher({ |
| 310 | + token: 'INTEGRATION_TOKEN' |
| 311 | +}); |
| 312 | +``` |
0 commit comments