Browse Source

Doc Overhaul (#78)

Revamp docs to be more example-focused and easier to browse
master
Dustin Larimer 7 years ago
committed by GitHub
parent
commit
5ab18c1148
  1. 8
      CONTRIBUTING.md
  2. 1033
      README.md
  3. 72
      docs/README.md
  4. 61
      docs/cookies.md
  5. 25
      docs/defer-events.md
  6. 101
      docs/extend-events.md
  7. 142
      docs/helpers.md
  8. 127
      docs/installation.md
  9. 118
      docs/listeners.md
  10. 100
      docs/record-events.md
  11. 25
      docs/timers.md
  12. 74
      docs/upgrade-guide.md

8
CONTRIBUTING.md

@ -1,11 +1,6 @@
# We <3 Contributions!
This is an open source project and we love involvement from the community! Hit us up with pull requests and issues. The more contributions the better!
**TODO:**
* [ ] Validate `Keen.utils.listener()` form submit binding on IE8
* [ ] Expose `A` element click event and `FORM` element submit event timeouts (default: 500ms)
This is an open source project and we love involvement from the community! Hit us up with pull requests and issues.
Run the following commands to install and build this project:
@ -52,4 +47,3 @@ Fetch the branch and/or deploy to staging to test the following:
## Related tickets?
```

1033
README.md

File diff suppressed because it is too large

72
docs/README.md

@ -0,0 +1,72 @@
# Documentation
* [Installation](./installation.md)
* [Record events](./record-events.md) to the API individually or in batches
* [Extend events](./extend-eventsmd) to build intricate, useful data models and ease instrumentation
* [Defer events](./defer-events.md) to be recorded at a given interval, or when the queue reaches a given capacity
---
### Utilities
* [Cookies](./cookies.md) (browser-only) for persisting data from one page to the next
* [Listeners](./listeners.md) (browser-only) for capturing and taking action during common DOM events like click, scroll, and submit
* [Timers](./timers.md) for tracking time before and between user or system interactions
---
### Helpers
* [Datetime index](./helpers.md#datetime-index) for decomposing a date object into a set of properties like "hour_of_day" or "day_of_month"
* [Unique ID](./helpers.md#unique-id) for generating UUIDs
* [DOM node path](./helpers.md#dom-node-path) for returning the xPath for a given DOM element
* [Screen profile](./helpers.md#screen-profile) for generating a set of properties describing the current device screen, like "height", "availHeight", and "orientation"
* [Window profile](./helpers.md#window-profile) for generating a set of properties describing the current window, like "height", "scrollHeight", and "ratio" to screen dimensions
* [Browser profile](./helpers.md#browser-profile) for generating a set of properties describing the current browser, like "useragent", "online" status, and "language", plus [screen](./helpers.md#screen-profile) and [window](./helpers.md#window-profile) profiles
---
### Debugging
Dev console errors and messages are turned off by default, but can be activated by setting `Keen.debug = true;`. Additionally, you can disable writing events to the API by setting `Keen.enabled = false;`.
```javascript
import Keen from 'keen-tracking';
// Track errors and messages in the dev console
Keen.debug = true;
// Disable event writes to the API
Keen.enabled = false;
const client = new Keen({ /*configure*/ });
// Observe what's happening in each method
client.on('recordEvent', Keen.log);
client.on('recordEvents', Keen.log);
client.on('deferEvent', Keen.log);
client.on('deferEvents', Keen.log);
client.on('recordDeferredEvents', Keen.log);
client.on('extendEvent', Keen.log);
client.on('extendEvents', Keen.log);
```
---
### Contributing
This is an open source project and we love involvement from the community! Hit us up with pull requests and issues.
[Learn more about contributing to this project](../CONTRIBUTING.md).
---
### Support
Need a hand with something? Shoot us an email at [team@keen.io](mailto:team@keen.io). We're always happy to help, or just hear what you're building! Here are a few other resources worth checking out:
* [API status](http://status.keen.io/)
* [API reference](https://keen.io/docs/api)
* [How-to guides](https://keen.io/guides)
* [Data modeling guide](https://keen.io/guides/data-modeling-guide/)
* [Slack (public)](http://slack.keen.io/)

61
docs/cookies.md

@ -0,0 +1,61 @@
# Cookies
`Keen.utils.cookie(key)` finds or creates a cookie with a given key (string) value, and returns an object with several methods for managing the data contained in that cookie.
This utility uses [js-cookie](https://github.com/js-cookie/js-cookie).
```javascript
var sessionCookie = Keen.utils.cookie('visitor-stats');
// Set a single value
sessionCookie.set('user_id', '222323843234');
// Set multiple values
sessionCookie.set({
user_id: '222323843234',
first_referrer: 'https://github.com/keen/keen-tracking.js'
})
// Get a single value, if it exists
sessionCookie.get('user_id');
// Returns '222323843234' or null
// Get all values
sessionCookie.get();
// Returns { user_id: '222323843234' }
sessionCookie.enabled();
// Returns true or false
// Expire the cookie
sessionCookie.expire();
// Set options on the cookie
sessionCookie.options({
domain: '...',
secure: true
});
```
**Important:** Some browsers do not allow cookies to be created or accessed from a local file (`file://dev/index.html`), which can make local development and testing problematic. `.set()` and `.get()` methods will only function correctly when cookies are enabled.
<a name="cookie-migration"></a>
Prior to the 1.0 release, this library used [Cookies.js](https://github.com/ScottHamper/Cookies), but incorrectly encoded the cookie data twice. Data stored in cookies by v0.1.1 or earlier can be accessed and resolved like so:
```javascript
var cookies = document.cookie.split(';');
var myCookie = Keen.utils.cookie('your-cookie-name');
var badData, newData;
for (var i = 0; i < cookies.length; i++) {
if (cookies[i].indexOf('your-cookie-name=') < 0) continue;
badData = cookies[i].split('your-cookie-name=')[1];
newData = JSON.parse(
decodeURIComponent(
decodeURIComponent(badData)
)
);
myCookie.set(newData);
break;
}
```

25
docs/defer-events.md

@ -0,0 +1,25 @@
# Defer Events
These methods handle an internal queue of events, which is pushed to the [events](https://keen.io/docs/api/#record-multiple-events) API resource on a given interval (default: 15 seconds), or when the queue reaches a maximum capacity (default: 5000).
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
// Single event from the previous example
client.deferEvent('purchase', purchaseEvent);
// Multiple events from the previous example
client.deferEvents(multipleEvents);
// Flush the deferred queue
client.recordDeferredEvents();
// Record events when queue contains at least N events (default: 5000)
client.queueCapacity(5000);
client.queueCapacity(); // 5000
// Record events every N seconds (default: 15)
client.queueInterval(15);
client.queueInterval(); // 15
```

101
docs/extend-events.md

@ -0,0 +1,101 @@
# Extend Events
These methods extend the event body of every event sent through `recordEvent()` or `recordEvents()`, for all or specified collections, and accepts either a predefined object (static) or a function that returns an object (dynamic). This returned object is then grafted into the original event body with a deep-extend operation that seamlessly blends nested objects.
`extendEvents` transforms will be applied first, followed by collection-specific `extendEvent` transforms. In either case, transforms will be applied in the order that they are defined. Properties provided in the originating `recordEvent/s()` call will override any matching properties (static or dynamic) returned by these methods.
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
// Extend events for a single collection
client.extendEvent('transaction', {});
client.extendEvent('transaction', function(){
return {};
});
// Extend events for all collections
client.extendEvents({});
client.extendEvents(function(){
return {};
});
// Example usage
var userProps = {
full_name: 'User Dude',
email: 'name@domain.com',
id: 'f1233423h',
username: 'userdude213'
};
// Include a predefined 'user' object with every purchase event
client.extendEvent('purchases', {
'user': userProps
});
// Include a predefined 'user' object with every event
client.extendEvents({
'user': userProps
});
// Include a dynamic 'keen.timestamp' property with every event
client.extendEvents(function(){
return {
keen: {
timestamp: new Date().toISOString()
}
};
});
```
**Example usage:**
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
// Object (static)
client.extendEvents({
page: {
href: document.location.href,
title: document.title
},
referrer: document.referrer,
user: {
email: 'name@domain.com',
id: 'f1233423h',
username: 'someuser123'
}
});
// Function that returns an object (dynamic)
// Useful for attaching time-sensitive data
client.extendEvents(function(){
return {
keen: {
timestamp: new Date().toISOString()
}
}
});
//
client.recordEvent('pageviews');
/* Resulting event body:
{
user: {
email: 'name@domain.com',
id: 'f1233423h',
username: 'someuser123'
},
page: {
href: 'https://github.com/keen/keen-tracking.js#extend-events',
title: document.title
},
referrer: 'https://github.com/keen/',
keen: {
timestamp: '2015-06-28T22:01:38.824Z'
}
}
*/
```

142
docs/helpers.md

@ -0,0 +1,142 @@
# Helpers
These helpers are designed to generate useful properties and objects for event data models, and can be used when recording, deferring or extending events.
### Datetime index
**Important:** This is now supported by the API as an add-on! Learn more here: https://keen.io/docs/api/#datetime-parser
`Keen.helpers.getDatetimeIndex()` returns a set of properties like "hour_of_day" or "day_of_month". This helper accepts an optional Date object as an argument, otherwise it will construct and return a datetime index object based on "now".
This helper works with a new `Date` object, and therefore the value returned is localized and not UTC. [Read more about this issue here](https://github.com/keen/keen-tracking.js/issues/49).
```javascript
import Keen from 'keen-tracking';
const datetimeIndex = Keen.helpers.getDatetimeIndex();
/*
// Monday, June 29th, 2015
{
'hour_of_day': 14,
'day_of_week': 2,
'day_of_month': 29,
'month': 6,
'year': 2015
}
*/
```
### Unique ID
`Keen.helpers.getUniqueId()` returns a UUID. This is useful in conjunction with `Keen.utils.cookie()` for identifying and tracking unauthenticated site visitors.
```javascript
import Keen from 'keen-tracking';
const uniqueId = Keen.helpers.getUniqueId();
// '150caf6b-ef9f-48cd-ae32-43e2f5bb0fe8'
```
### DOM node path
`Keen.helpers.getDomNodePath(el)` returns the xPath for a given DOM element.
```javascript
import Keen from 'keen-tracking';
const btn = document.getElementById('signup-button');
const domNodePath = Keen.helpers.getDomNodePath(btn);
// 'body > div#nav > ul > li:eq(1) > a#signup-button'
```
### Screen profile
`Keen.helpers.getScreenProfile()` returns a set of properties describing the current device screen, like "height", "availHeight", and "orientation".
```javascript
import Keen from 'keen-tracking';
const screenProfile = Keen.helpers.getScreenProfile();
/*
{
height: 900,
width: 1440,
colorDepth: 24,
pixelDepth: 24,
availHeight: 878,
availWidth: 1436,
orientation: {
angle: 0,
type: 'landscape'
}
}
*/
```
### Window profile
`Keen.helpers.getWindowProfile()` returns a set of properties describing the current window, like "height", "scrollHeight", and "ratio" to screen dimensions.
```javascript
import Keen from 'keen-tracking';
const windowProfile = Keen.helpers.getWindowProfile();
/*
{
height: 436,
width: 1209,
scrollHeight: 13834,
ratio: {
height: 0.5,
width: 0.84
}
}
*/
```
### Browser profile
`Keen.helpers.getBrowserProfile()` returns a set of properties describing the current browser, like "useragent", "online" status, and "language", plus [screen](#screen-profile) and [window](#window-profile) profiles.
```javascript
import Keen from 'keen-tracking';
const browserProfile = Keen.helpers.getBrowserProfile();
/*
{
cookies: true,
codeName: 'Mozilla',
language: 'en-US',
name: 'Netscape',
online: true,
platform: 'MacIntel',
useragent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36',
version: '5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36',
// includes Keen.helpers.getScreenProfile();
screen: {
height: 900,
width: 1440,
colorDepth: 24,
pixelDepth: 24,
availHeight: 878,
availWidth: 1436,
orientation: {
angle: 0,
type: 'landscape'
}
},
// includes Keen.helpers.getWindowProfile();
window: {
height: 436,
width: 1209,
scrollHeight: 13834,
ratio: {
height: 0.5,
width: 0.84
}
}
}
*/
```

127
docs/installation.md

@ -0,0 +1,127 @@
# Installation
Install this package from npm:
```ssh
$ npm install keen-tracking --save
```
Or load it from our CDN:
```html
<script src="https://d26b395fwzu5fz.cloudfront.net/keen-tracking-1.1.4.min.js"></script>
```
Prefer asynchronous loading? Copy/paste this snippet of JavaScript above the `</head>` tag of your page to load the tracking library asynchronously. This technique sneaks the library into your page without significantly impacting page load speed.
```html
<script>
// Loads the library asynchronously from any URI
!function(name,path,ctx){
var latest,prev=name!=='Keen'&&window.Keen?window.Keen:false;ctx[name]=ctx[name]||{ready:function(fn){var h=document.getElementsByTagName('head')[0],s=document.createElement('script'),w=window,loaded;s.onload=s.onerror=s.onreadystatechange=function(){if((s.readyState&&!(/^c|loade/.test(s.readyState)))||loaded){return}s.onload=s.onreadystatechange=null;loaded=1;latest=w.Keen;if(prev){w.Keen=prev}else{try{delete w.Keen}catch(e){w.Keen=void 0}}ctx[name]=latest;ctx[name].ready(fn)};s.async=1;s.src=path;h.parentNode.insertBefore(s,h)}}
}('Keen','https://d26b395fwzu5fz.cloudfront.net/keen-tracking-1.1.4.min.js',this);
// Executes when the library is loaded and ready
Keen.ready(function(){
// Create a new client instance
var client = new Keen({
projectId: 'YOUR_PROJECT_ID',
writeKey: 'YOUR_WRITE_KEY'
});
// Record an event!
client.recordEvent('pageviews', {
// Define your event data model
title: document.title
});
});
</script>
```
This loader works a little differently than all the previous versions we have released.
Notice the last line of the asynchronous loader snippet: `}('Keen', './filename.js', this);`. These three arguments can be overwritten, allowing you to customize important details about the installation process.
1. **Namespace:** Define a custom namespace for the library, instead of the default `Keen`, like `MyCustomKeenBuild`.
2. **Script URI:** Define the location of the script to load. You don't need to rely on our CDN. You can use your own, or host the file locally.
3. **Context:** Define where the library should be installed. Global pollution is a problem. This helps you fight back.
Here's an example that uses all of these features together:
```javascript
var modules = {};
!function(name,path,ctx){
//~ .etc
}('MyKeenBuild','/assets/js/custom-keen-tracking.js', modules);
modules.MyKeenBuild.ready(function(){
var client = new modules.MyKeenBuild.Client({
projectId: 'YOUR_PROJECT_ID',
writeKey: 'YOUR_WRITE_KEY'
});
// client.recordEvent('pageviews', {});
});
```
**Important:** This update brings an important change to note. In past versions of keen-js, we shimmed tracking-methods so you could begin using them immediately without the `.ready()` callback wrapper. This created a lot of strange edge cases and version conflicts. Now, everything must be initialized from within the `.ready(function(){ ... })` wrapper.
### RequireJS
The library is published with an explicitly named module ID of 'keen-tracking'. This presents a light configuration step, but prevents anonymous define() mismatch mayhem.
To use this module, configure a paths record, like so:
```html
<script data-main="path/to/app.js" src="require.js"></script>
```
```javascript
// app.js
requirejs.config({
paths: {
'keen-tracking': 'path/to/keen-tracking.js'
}
});
require([
'keen-tracking'
], function(KeenAMD) {
var client = new KeenAMD.Client({
projectId: "123",
writeKey: "456"
});
});
```
Also note a global `Keen` object will still be defined. This is meant to ensure the library can initialize in environments where neighboring scripts are unknown or uncontrollable.
## Client instances
The client instance is the core of the library and will be required for all API-related functionality. The `client` variable defined below will also be used throughout this document.
```javascript
import Keen from 'keen-tracking';
const client = new Keen({
projectId: 'YOUR_PROJECT_ID',
writeKey: 'YOUR_WRITE_KEY',
host: 'api.keen.io',
protocol: 'https',
requestType: 'jsonp' // Also: 'xhr', 'beacon'
});
// Optional accessor methods are available too
client.projectId('PROJECT_ID');
client.writeKey('WRITE_KEY');
```
**Important notes about client configuration options:**
* `host` and `writePath`: these options can be overwritten to make it easier than ever to proxy events through your own intermediary host.
* `protocol`: older versions of IE feature a fun little quirk where cross-domain requests to a secure resource (https) from an insecure host (!https) fail. In these rare cases the library will match the current host's protocol.
* `requestType`: this option sets a default for GET requests, which is only supported when recording single events. There are limits to the URL string length of a request, so if this limit is exceeded we'll attempt to execute a POST instead, using XHR. In rare cases where XHR isn't supported, the request will fail.

118
docs/listeners.md

@ -0,0 +1,118 @@
# DOM Listeners
`Keen.utils.listener()` helps surface common DOM element events like "click", "scroll", and "submit". There is also a `Keen.listenTo()` method for quickly setting a series of listeners (below)
**Important:** Form submits and clicks will be delayed by 500ms, unless the event is cancelled within a given listener's callback.
```javascript
import Keen from 'keen-tracking';
// Listen to DOM events
// Create a new element listener (assigned)
var navLinks = Keen.utils.listener('.nav li > a');
// Listen for a given event
navLinks.on('click', function(e){
// You have 500ms to record an event!
});
// Listen for event once
myClicker.once('click', function(e){
// First click!
});
// Cancel a given event listener
function clickHandler(e){
// do something!
}
myClicker.on('click', clickHandler);
myClicker.off('click', clickHandler);
// Cancel all listeners for a given event
myClicker.off('click');
// .. or all events
myClicker.off();
var formListener = Keen.utils.listener('form#signup');
formListener.on('submit', function(e){
client.recordEvent('signup', {
// record signup data
});
});
```
#### Keen.listenTo()
This is a convenience function for quickly creating multiple listeners. These listeners are constructed with the `Keen.utils.listener` utility, so the behavior will be identical to calling `Keen.utils.listener(selector).on(eventType, callback);`.
```javascript
import Keen from 'keen-tracking';
Keen.listenTo({
'click .nav li > a': function(e){
// You have 500ms to record an event!
},
'submit form#signup': function(e){
// Record a signup event
}
});
```
This technique does not return a reference to the listener, but can be deactivated by defining a listener with the same selector and calling the `.off(eventType)` event:
```JavaScript
import Keen from 'keen-tracking';
Keen.utils.listener('.nav li > a').off('click');
Keen.utils.listener('form#signup').off('submit');
```
#### Window events
```javascript
import Keen from 'keen-tracking';
var winListener = Keen.utils.listener('window')
.once('scroll', function(e){
// user is interacting with the page
})
.on('hashchange', function(e){
// user clicked an internal anchor (eg: /#some-heading)
})
.on('resize', function(e){
// ...
});
```
**Generally supported events:**
* click (see below for `<a>` clicks)
* submit (see below for `<form>` submits)
* keydown
* keypress
* keyup
* mousedown
* mousemove
* mouseout
* mouseover
* mouseup
**Important note about `<a>` and `<form>` elements:** `<a>` tag **clicks** (when navigating away from the current page) and `<form>` **submits** are deferred for 500ms to allow for quick, asynchronous API calls.
**`window` events:**
* blur
* focus
* hashchange
* resize
* scroll
**Not currently supported:**
* dblclick
* error
* onload
* unload

100
docs/record-events.md

@ -0,0 +1,100 @@
# Record events
These methods push single or multiple events to their respective API endpoints. Wondering what you should record? Browse our [data modeling guide](https://keen.io/guides/data-modeling-guide/), and let us know if you don't find what you're looking for.
### Record a single event
Here is an example for recording a "purchases" event. Note that dollar amounts are tracked in cents:
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
// Create a data object with the properties you want to record
var purchaseEvent = {
item: 'golden gadget',
price: 2550, // track dollars as cents
referrer: document.referrer,
keen: {
timestamp: new Date().toISOString()
}
};
client.recordEvent('purchases', purchaseEvent, function(err, res){
if (err) {
// there was an error!
}
else {
// see sample response below
}
});
```
**API response for recording a single event:**
```jsonp
{
"created": true
}
```
### Record multiple events
Here is an example for how to record multiple events with a single API call. Note that dollar amounts are tracked in cents:
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
var multipleEvents = {
purchases: [
{
item: 'golden gadget',
price: 2550,
transaction_id: 'f029342'
},
{
item: 'a different gadget',
price: 1775,
transaction_id: 'f029342'
}
],
transactions: [
{
id: 'f029342',
items: 2,
total: 4325
}
]
};
// Send multiple events to several collections
client.recordEvents(multipleEvents, function(err, res){
if (err) {
// there was an error!
}
else {
// see sample response below
}
});
```
**API response for recording multiple events:**
```json
{
"purchases": [
{
"success": true
},
{
"success": true
}
],
"transactions": [
{
"success": true
}
]
}
```

25
docs/timers.md

@ -0,0 +1,25 @@
# Timers
`Keen.utils.timer()` creates an object that tracks time, and can be paused, restarted, or initialized with a known value (seconds). It seems simple, but these little do-dads are excellent for recording the duration of sessions or specific interactions.
```javascript
import Keen from 'keen-tracking';
var userActivity = Keen.utils.timer();
// Start the timer
userActivity.start();
// Pause the timer
userActivity.pause();
// Return the value of the timer (seconds)
userActivity.value(); // 10
// Clear the current value of the timer
userActivity.clear();
// Start from a given number
var historicalActivity = Keen.utils.timer(3132).start();
historicalActivity.pause();
```

74
docs/upgrade-guide.md

@ -0,0 +1,74 @@
# Upgrade Guide
There are several new methods and name changes from earlier versions of [keen-js](https://github.com/keen/keen-js), but fear not! We have included shims and legacy methods to make this library fully backward-compatible with the core functionality of keen-js, aside from one breaking change to the `client.url()` method (detailed below).
### Deprecated methods
The following legacy methods are now deprecated:
* `addEvent` and `addEvents` are now [`recordEvent`](./record-events.md) and [`recordEvents`](./record-events.md)
* `setGlobalProperties` is now handled by the [`extendEvents`](./extend-events.md) methods
* `trackExternalLinks` is now handled by the [DOM listeners](./listeners.md) utility (browser-only)
Please avoid using these deprecated methods, as they will eventually get axed. Deprecation messages will be visible in the developer console if [debugging](#debugging) is enabled.
### Breaking changes
The previous implementation of `client.url()` automatically included `https://api.keen.io/3.0/projects/PROJECT_ID` plus a `path` argument ('/events/whatever'). This design severely limited its utility, so we've revamped this method.
This method now references an internal collection of resource paths, and constructs URLs using client configuration properties like `host` and `projectId`:
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
var url = client.url('projectId');
// Renders {protocol}://{host}/3.0/projects/{projectId}
// Returns https://api.keen.io/3.0/projects/PROJECT_ID
```
Default resources:
* 'base': '`{protocol}`://`{host}`',
* 'version': '`{protocol}`://`{host}`/3.0',
* 'projects': '`{protocol}`://`{host}`/3.0/projects',
* 'projectId': '`{protocol}`://`{host}`/3.0/projects/`{projectId}`',
* 'events': '`{protocol}`://`{host}`/3.0/projects/`{projectId}`/events'
Unmatching strings will be appended to the base resource, like so:
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
var url = client.url('/3.0/projects');
// Returns https://api.keen.io/3.0/projects
```
You can also pass in an object to append a serialized query string to the result, like so:
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
var url = client.url('events', { api_key: 'YOUR_API_KEY' });
// Returns https://api.keen.io/3.0/projects/PROJECT_ID/events?api_key=YOUR_API_KEY
```
Resources can be returned or added with the `client.resources()` method, like so:
```javascript
import Keen from 'keen-tracking';
const client = new Keen({ /*configure*/ });
client.resources()
// Returns client.config.resources object
client.resources({
'new': '{protocol}://analytics.mydomain.com/my-custom-endpoint/{projectId}'
});
client.url('new');
// Returns 'https://analytics.mydomain.com/my-custom-endpoint/PROJECT_ID'
```
Loading…
Cancel
Save