nfl / react-metrics Goto Github PK
View Code? Open in Web Editor NEWAn analytics module for React
License: MIT License
An analytics module for React
License: MIT License
Is it possible add data from customParams
to track
event type?
When creating a custom method (as outlined here: https://github.com/nfl/react-metrics/blob/master/docs/Guides.md#api) the method always expects an argument to be passed, whether or not the method expects one. To recreate the issue, use the example in the docs, and use the metrics context object to call the method (i.e - this.context.metrics.someMethod()).
When no argument is passed, the method doesn't get called, but if anything is passed, the method gets called.
How do you view the collected metrics?
Related to #36. Our test suite throws warnings since we upgraded to 15.5.
https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html
I've got react-metrics set up with a React + Redux application. The analytics provider in use is Adobe Tag Manager (Omniture), and the configuration provided in the example was used.
I've got automatic pageView tracking enabled by decorating the react-router routes component with @metrics
. I've verified that the correct payload
is being sent in the Network debugger. However, when I set up a redux-middleware to track customLink
s, the payload sent in the pageView
call (from the earlier @metrics
) now contains fields set in the track
call in middleware.
This is what the middleware looks like -
const analyticsMiddleware = ({getState}) => {
return next => action => {
const returnValue = next(action);
let payload;
switch (action.type) {
default:
if (analyticsUtils.whitelist.has(action.type)) {
payload = {
abc: 'abc',
}
metrics.api.track('customLink', payload);
}
}
return returnValue;
};
};
The pageView
calls now have the key abc
(can be seen as a query param in network inspector), even though abc
is only set in the track call in middleware.
Hi,
Here are some lines of my unit test code that generate an Invariant Violation:
// src/app.js
@metrics(metricsConfig, metricsOptions)
class App extends Component {
...
}
export default App
// src/app.spec.js
describe('App ', () => {
it('should shallow render Hello', () => {
const tree = shallow(<App children="Hello" />)
expect(tree).toMatchSnapshot()
})
it('should shallow render World', () => {
const tree = shallow(<App children="World" />)
expect(tree).toMatchSnapshot()
})
})
When I run the tests, I have this error:
Invariant Violation: `metrics` should only be added once to the root level component. You have added to both App and App.
at invariant (node_modules/fbjs/lib/invariant.js:44:15)
at MetricsContainer.componentWillMount (node_modules/react-metrics/lib/react/metrics.js:94:49)
at node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:348:23
at measureLifeCyclePerf (node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:75:12)
at ShallowComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:347:9)
at ShallowComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/shallow/ReactCompositeComponent.js:258:21)
at Object.mountComponent (node_modules/react-test-renderer/lib/shallow/ReactReconciler.js:46:35)
at ReactShallowRenderer._render (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:138:23)
at _batchedRender (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:85:12)
at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactDefaultBatchingStrategy.js:60:14)
at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactUpdates.js:97:27)
at ReactShallowRenderer.render (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:112:18)
at ReactShallowRenderer.render (node_modules/enzyme/build/react-compat.js:180:39)
at node_modules/enzyme/build/ShallowWrapper.js:128:26
at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-test-renderer/lib/shallow/Transaction.js:140:20)
at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactDefaultBatchingStrategy.js:62:26)
at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactUpdates.js:97:27)
at ReactShallowRenderer.unstable_batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:130:25)
at performBatchedUpdates (node_modules/enzyme/build/ShallowWrapper.js:103:21)
at node_modules/enzyme/build/ShallowWrapper.js:127:9
at withSetStateAllowed (node_modules/enzyme/build/Utils.js:284:3)
at new ShallowWrapper (node_modules/enzyme/build/ShallowWrapper.js:126:38)
at shallow (node_modules/enzyme/build/shallow.js:19:10)
at shallow (jest/__mocks__/enzyme.js:133:30)
at Object.<anonymous> (src/__tests__/App.spec.js:22:36)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at process._tickCallback (internal/process/next_tick.js:109:7)
This is because the variable mountedInstances
is never reset.
I believe this variable is encapsulated in a closure and is not garbage collected.
What solutions do we have to test this main app component?
Thank you for your help
Import { PropTypes } from 'react-metrics' may collide with the PropTypes from 'https://www.npmjs.com/package/prop-types'
Suggest namespacing to this package
If I have, for example:
<a data-metrics-event-name="SomeEvent">
<img src="..." />
</a>
and the user clicks on the image... the events won't register because the event.target
is the image and has no data-metrics
. There should be an option or something to fix this to have it bubble to data-metrics. I have this problem here:
return (
<Link to={this.getPath()}>
<h4>
<u
data-metrics-event-name="ActivityRow:Title:Click"
data-metrics-activity-id={activity.id}>
{/* LEGACY */}
{activity.infoName || activity.name}
</u>
</h4>
</Link>
);
which is bad cause the <u>
tag should not have the event names.
Running into an issue with using react metrics on a site which enables quirks mode running in ie10.
Unable to get property 'attributes' of undefined or null reference in attrobj.js line 7
Is this a know issue?
The catalyst of this request comes from me stumbling across this from Dan Abramov: https://twitter.com/dan_abramov/status/749715530454622208
Backing this up, the react docs recommend not to use the context directly https://facebook.github.io/react/docs/context.html#why-not-to-use-context
I propose a "withMetrics" higher order component that accepts a react-redux style 'mapMetricsToProps' function to map metrics API functions to a components props.
import React from 'react';
import { withMetrics } from 'react-metrics';
class TopCheckoutButton extends React.Component {
render() {
const { trackCheckout } = this.props;
return <button onClick={() => trackCheckout('top')} />;
}
}
class BottomCheckoutButton extends React.Component {
render() {
const { trackCheckout } = this.props;
return <button onClick={() => trackCheckout('bottom')} />;
}
}
function trackCheckoutEvent(metrics) {
return (checkoutButtonPosition) => {
return metrics.track(`checkout_${checkoutButtonPosition}`);
};
}
function mapMetricsToProps(metrics) {
return {
trackCheckout: trackCheckoutEvent(metrics)
}
}
const TrackedTopCheckoutButton = withMetrics(mapMetricsToProps)(TopCheckoutButton);
const TrackedBottomCheckoutButton = withMetrics(mapMetricsToProps)(BottomCheckoutButton);
export TrackedTopCheckoutButton;
export TrackedBottomCheckoutButton;
The above example demonstrates the usage of such a HOC to compose tracked checkout buttons using a common curried function that wraps the track()
call from react-metrics.
A more simplistic example would be exposing the react-metrics API functions directly to the wrapped component
export default withMetrics(metrics => { trackSomething: metrics.track })(MyTrackedComponent); // Named tracking methods
export default withMetrics()(MyOtherTrackedComponent); // Default passing all react-metrics api functions as props
Interested to know if this feature sounds reasonable to implement directly into this repository and if you would accept PRs for such a feature.
Hi,
the metrics decorator is not very unit-test friendly. It allows mounting a component only once and remembers the instance on a global variable relative to the module.
There is no API to reset the instances right now, isn't it? Not even unmounting will help.
Please add a sane way to clear test cases.
Hi i submitted a PR which will pass the click element along with the track call. This is useful to us as we can default a lot of track metadata based on the type of element.
I have noticed you are importing the polyfill.js into this package which bloats the file size when you use it in a project. I would much prefer giving people the option to use their own polyfills if they need them for their projects.
At least remove the promise polyfill which adds 10kb. Add to the readme about the need to use your own promise polyfill.
side note
Ideally there will be better support for having ES5 and ES2015 npm modules together. Something like rollup has. So once webpack v2 is released then we can all do tree-shaking.
Hi. I'm working on a React project that is mixed ES5/ES6 and still uses React.createClass for creation of components. Is it possible to use the react-metrics package while using createClass for components?
Currently react-metrics throws an exception on this line when the site URI is malformed with an invalid query string:
https://github.com/nfl/react-metrics/blob/master/src/core/createMetrics.js#L13
Ideally, querystring.decode
would be wrapped in a try/catch, spit the error out in the console and set qs
to {}
so that the site doesn't partially render due to the unhandled js exception.
We are also trying to correct the invalid query string coming into our site, but we ideally would still render a working site even if the query string is malformed.
Is there any way to inherit higher level component or parent elements data-attributes to its children so I don't have to duplicate data attributes throughout the codebase?
I was able to create a PR but it broke some of the tests. Basically instead of traversing through the next specified root element (MetricsElement) it will traverse to the root Dom element on document body. It will then add any parent data attributes to the existing track call. Lower level attributes will override their parent as it is closer to the source of the click tracking.
Hey, using Segment as suggested in the docs, how did you figure out getting your Segment write key into the vendors?
Thanks!
Do you have an example for a site that supports SSR? I am using NextJS and I am not able to limit importing the vendor/GoogleAnalytics.js class to only client side rendering. How do I replace the GoogleAnalyticsStub below to get this working?
metrics.config.js
import { ga } from 'client-config'
import GoogleAnalytics from '../lib/GoogleAnalytics'
const MetricsConfig = {
vendors: [{
name: 'Google Analytics',
api: new GoogleAnalytics({
trackingId: ga.tracking_id
})
}],
pageViewEvent: 'pageLoad',
pageDefaults: () => {
return {
environment: ga.environment,
siteName: ga.siteName,
timestamp: Date.now(),
path: '/'
}
},
debug: ga.debug
}
export default MetricsConfig
Layout.js
import React from 'react'
import pageLoadTracking from '../lib/pageLoadTracking'
const Layout = ({ children }) => (
<Main>
{children}
</Main>
)
export default pageLoadTracking(Layout)
package.json
"dependencies": {
"above-the-fold-only-server-render": "^1.0.3",
"analytics.js": "^2.9.1",
"config": "^1.25.1",
"express": "^4.15.2",
"js-yaml": "^3.8.3",
"mkdirp": "^0.5.1",
"next": "^2.3.1",
"next-routes": "^1.0.26",
"prop-types": "^15.5.8",
"react": "^15.5.4",
"react-apollo": "^1.2.0",
"react-dom": "^15.5.4",
"react-ga": "^2.2.0",
"react-gpt": "^0.2.4",
"react-metrics": "^2.3.1",
"react-no-ssr": "^1.1.0",
"styled-components": "^1.4.5"
},
"devDependencies": {
"babel-eslint": "^7.2.3",
"babel-plugin-module-resolver": "^2.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.24.1",
"chai": "^3.5.0",
"enzyme": "^2.8.2",
"ignore-styles": "^5.0.1",
"jsdom": "^9.12.0",
"lighthouse": "^1.6.3",
"mocha": "^3.2.0",
"nightwatch": "^0.9.14",
"phantomjs-prebuilt": "^2.1.14",
"react-test-renderer": "^15.5.4",
"selenium-server": "^3.3.1",
"sinon": "^2.1.0",
"standard": "^10.0.1"
},
GoogleAnalytics.js
let analytics
if (process.browser) {
analytics = require('analytics.js') // eslint-disable-line global-require
}
/**
* Performs the tracking calls to Google Analytics.
* Utilizing Segment IO Analytics Integration.
*
* @module GoogleAnalytics
* @class
* @internal
*/
class GoogleAnalytics {
constructor (options = {}) {
this.name = 'Google Analytics'
this._loaded = false
this.options = options
}
/**
*
* @method pageView
* @param {String} eventName
* @param {Object} params
* @returns {Promise}
* @internal
*/
pageView (...args) {
return this.track(...args)
}
user (userId) {
return new Promise((resolve) => {
this.userId = userId
resolve({
userId
})
})
}
/**
*
* @method track
* @param {String} eventName
* @param {Object} params
* @returns {Promise}
* @internal
*/
track (eventName, params) {
return new Promise((resolve, reject) => {
this._load().then(() => {
this._track(eventName, params)
resolve({
eventName,
params
})
}).catch((error) => {
console.error('GA: Failed to initialize', error)
reject(error)
})
})
}
/**
*
* @method _track
* @param {String} eventName
* @param {Object} params
* @protected
*/
_track (eventName, params) {
if (eventName === 'pageView') {
analytics.page(params.category, params)
return
}
analytics.track(eventName, params)
}
/**
*
* @method _load
* @protected
*/
_load () {
return this._promise || (this._promise = new Promise((resolve) => {
if (this._loaded) {
resolve()
} else {
analytics.once('ready', () => {
this._loaded = true
resolve()
})
analytics.initialize({
'Google Analytics': this.options
})
}
}))
}
}
export default GoogleAnalytics
Hi there,
I've just cloned the repo and am running the examples. Everything works fine except for the React Router / Basic Example. Clicking on the "Basic Example" link gives the following error:
Uncaught TypeError: (0 , _reactMetrics2.default) is not a function
at Object.677 (react-router_basic.js:4716)
at __webpack_require__ (bootstrap 114f31eaf14d44e3980b:52)
at Object.628 (app.js:17)
at __webpack_require__ (bootstrap 114f31eaf14d44e3980b:52)
at Object.0 (react-router_basic.js:8)
at __webpack_require__ (bootstrap 114f31eaf14d44e3980b:52)
at webpackJsonpCallback (bootstrap 114f31eaf14d44e3980b:23)
at react-router_basic.js:1
Given I didn't do anything other than npm install, npm run examples I hope that is enough for you. Otherwise let me know if you need more info.
Hey guys, first of all, thank you for this awesome library.
I'm opening this issue because we noticed a common problem when using this library with React v15.5.0
.
Currently, react-metrics
is displaying the following warning on console:
Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.
As of React v15.5.0, PropTypes
has its own package, and now it shows a deprecation warning when using PropTypes
directly from React
package.
Related: https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html#new-deprecation-warnings
Just as a quick reference, this code now shows a warning:
import { PropTypes } from 'react';
Now, the "correct" way of using PropTypes
is via prop-types
package.
import PropTypes from 'prop-types';
Do you guys mind if I open a pull request to use this new prop-types
package instead of "main" PropTypes
?
Thank you!
Related: #38
There is logic in the code, if there is no any venders disable metrics with enabled:false
, but after this it returns error react-metrics: 'pageView' api needs to be defined for automatic page view tracking.
from https://github.com/nfl/react-metrics/blob/master/src/react/metrics.js#L143
. I guess, this line of code should check whether metrics enabled or not.
What feature demands IE 10 that IE 9 doesn't have?
Is there a way to get config from props for example in case of GoogleAnalytics I want to get trackingId from props.
Hi,
First thanks for this great library!
Is react-metrics supports react-router4?
If no is there any plan/timeline for this?
If yes, is there anything special need to be done?
Thanks!
Gilad
Error message
npm install --save react-metrics
npm ERR! fetch failed https://registry.npmjs.org/react-metrics/-/react-metrics-2.2.1.tgz
npm WARN retry will retry, error on last attempt: Error: fetch failed with status code 404
npm ERR! fetch failed https://registry.npmjs.org/react-metrics/-/react-metrics-2.2.1.tgz
npm WARN retry will retry, error on last attempt: Error: fetch failed with status code 404
Enhancement request. Would love to be able to have a data attribute that could trigger an element to be tracked when key pressing (enter key) or hovering over an element for a duration of time. This would pretty much allow us to keep all of our tracking code in data attributes.
Hi, this issue only occurs in IE. When clicking on an SVG icon in IE that is to be tracked through the use of , or is in a section to be tracked, an error is logged in the console stating that 'Unable to get property 'attributes' of undefined or null reference'.
It seems that element.parentElement is not supported for SVG elements in IE so needs to also use element.parentNode.
I have a PR ready to add as well which I will link to this issue.
Thanks.
A user can navigate using tab and hit enter as well as user can use mouse click (accessibility). What if we add handler for enter key after click event 'https://github.com/nfl/react-metrics/blob/master/src/core/useTrackBindingPlugin.js#L32'?
Essentially I am looking to build out my own metrics system to track performance of a widget embedded externally from my main application. Currently, the way that it works is I have an iFrame with a specific path for each widget and then I use Google Analytics's API to get data on those paths (pageviews and average time on page) but it's a pain in the ๐
I am looking for a solution where I can build out a component that tracks it's own performance without relying on a URL path - ie if someone embeds my widget somewhere without an iFrame, I want the component to be able to track it's own data and push it down to my DB.
I can imagine I'd be able to do so for pageviews but I don't see any documentation on average time on page.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.