rangle / redux-beacon Goto Github PK
View Code? Open in Web Editor NEWAnalytics integration for Redux and ngrx/store
Home Page: https://rangle.gitbook.io/redux-beacon/
License: MIT License
Analytics integration for Redux and ngrx/store
Home Page: https://rangle.gitbook.io/redux-beacon/
License: MIT License
If one dispatched action changes multiple values inside a portion of the state, it is possible to create one event for every changed values?
A very basic example (this would be dynamic in a real ex.):
dispatch(setFiltersAction({
foo: 1,
bar: 2,
}))
const filtersChange = {
eventFields: action => (
{
hitType: 'event',
eventCategory: 'filters',
eventAction: 'set',
eventLabel: 'foo',
eventValue: action.data.foo,
},
{
hitType: 'event',
eventCategory: 'filters',
eventAction: 'set',
eventLabel: 'bar',
eventValue: action.data.bar,
},
),
};
const eventsMap = {
SET_FILTERS: filtersChange,
};
It'd be nice to include offline event collection in the example app for illustrative and testing purposes.
I have been seeing errors in Rollbar indicating that a variety of clients are generating the error Uncaught Error: window.analytics is not defined, Have you forgotten to include the Segment tracking snippet?
My best guess is that some clients are blocking the Segment script or else not evaling it for some reason. I wanted to turn redux-beacon off for those clients by checking if window.analytics
is defined in the EventDefinition
by essentially wrapping each in a function:
const ifSegmentDefined = (reducer: EventDefinition): EventDefinition => (
(action: any, prevState: IMyStore, nextState: IMyStore): any => {
const w = window as any;
return w && w.analytics ? reducer(action, prevState, nextState): null;
}
);
const segmentEventsMap: EventDefinitionsMap = {
// ...
[PROFILE.SAVE_SUCCESS]: ifSegmentDefined(myEventDefinition),
}
However, this doesn't work because it seems like redux-beacon
fires the "window.analytics is not defined" error even if my isSegmentDefined
wrapper returns null or undefined. It also fires even if I return a literal null
in my EventDefinition. I would have expected that the check for window.analytics
would happen after the check for an empty EventDefinition.
This isn't a big problem---I can work around it by creating a no-op middleware if windows.analytics is undefined. But I think that if there's a race condition on asynchronously loading the segment library, it would be nice to be able to have the check happen when the event is created, not during initialization.
I'm using redux-beacon in my Redux app with Segment target. I've configured storage as it's described in docs. Also I've added support for offlineWeb. Everything works fine, I have some written events for analytics associated with my Redux events.
However, the library somehow automatically generates a 'pageview' event when I initially open my web-app at some page that differs from root one and sends it to my Segment source.
Here is an event that I receive in Segment:
analytics.page({
path: '/eddca13c-a450-4cd6-a520-8b7e8f50c94c',
referrer: 'http://localhost:3000/eddca13c-a450-4cd6-a520-8b7e8f50c94c',
search: '',
title: 'React App',
url: 'http://localhost:3000/eddca13c-a450-4cd6-a520-8b7e8f50c94c'
});
Also, after I wrote a console.log(events);
here I haven't seen this event.
What's wrong with this case?
Custom dimensions and metrics are a powerful way to send custom data to Google Analytics. Web developers can use custom dimensions and metrics to segment and measure differences between logged in and logged out users, authors of pages, levels in games, or any other business data you have on a page.
https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets
So basic idea is to add support for this, the problem I see is that we don't know in advance the field key, as it would be anything between dimension1 and dimension20, and the same for metrics. (The number of custom dimensions and metrics varies between plans I believe)
One option would be to pass a dimensions object with numbers as keys, and then build the parameters from there. I will be happy to send a PR once agreed on the design.
Examples:
ga('send', 'pageview', {
'dimension15': 'My Custom Dimension'
});
ga('send', 'event', 'category', 'action', {
'metric18': 8000
});
I have multiple tracking instance running on my site as described here. The gist is that you create multiple instance by naming at least one of them:
ga('create', 'UA-XXXXX-Y', 'auto');
ga('create', 'UA-XXXXX-Z', 'auto', 'clientTracker');
and then target that instance, for example:
ga('clientTracker.send', 'pageview');
How can I target the named tracker using redux-beacon
? Is this possible?
All events passed to the Google Analytics target are either being filtered out as page views and sent to Google Analytics via a ga('set', 'page', <page>)
call, or as custom events that are sent via a ga('send', <event object>)
call.
As a redux-beacon user I'd like to use redux-beacon with the Google Analytics ecommerce plugin. This doesn't have to be the final API, but as an example and starting point I would like to be able to return an object like:
{
hitType: 'ecommerce:addItem',
id: '1234',
name: 'Fluffy Pink Bunnies',
}
From an event definition, and have redux-beacon make the following call to ga
:
ga('ecommerce:addItem', { 'id': '1234', 'name': 'Fluffy Pink Bunnies' });
What happens if the user forgets to add ga('require', 'ecommerce');
after the ga
snippet? Will ga
throw an error? Or will it fail silently? Is there a way we can throw a helpful error?
If additional properties are sent in an ecommerce event, how will that effect reporting? For example, say you sent ga('ecommerce:addItem', { hitType: 'ecommerce', id: '1234', name: 'Fluffy Pink Bunnies' });
does it matter that hitType is there?
A few of the target docs still use the old event definitions api. These should be updated to use the new function api.
When an eventFields method in an event definition returns undefined or null two undesirable things can happen:
a) if the event definition has an eventSchema then an error will be thrown in createEvents.js
whining that whatever property to test doesn't exist in undefined
or null
.
b) the event definition will be passed as undefined to the target, if the target isn't ready for this the target will throw an error.
We need to improve documentation on this and the developer experience when things like this happen.
dev
and prod
option in the library.your redux-beacon tag does not exist on stackoverflow.
The documentation for React Native Google Tag Manager refers specifically to the Legacy SDK and I didn't come across any other reference to Firebase SDK.
So I'm wondering if you could clarify whether this projects supports the Firebase SDK and Firebase IOS GTM containers?
Note: for support questions, please use stackoverflow with the redux-beacon
tag. This repository's issues are reserved for feature requests and bug reports.
(If this is a bug report, feel free to delete the ๐ and ๐
sections. Likewise, if this is a documentation or feature request, feel free to
delete the ๐ชฒ sections)
When tracking an ecommerce action that is not purchase or refund, the id is not required, but in the type definitions it is. Google Analytics documentation:
id | text | Yes* | The transaction ID (e.g. T1234).ย *Required if the action type isย purchaseย orย refund.
I think we should make it optional so we don't force a value.
@ngrx version: 4.0.5
@angular: 4.3.6
angular/cli: 1.3.2
When I try to compile Angular with AoT I get the following error:
ERROR in Error encountered resolving symbol values statically. Calling function 'createMetaReducer', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol analyticsMetaReducer in ...
I tried the following 3 versions (googled a bit and found people that did it like that but with other libraries):
import {createMetaReducer} from "redux-beacon";
import {GoogleAnalytics, PageView} from "redux-beacon/targets/google-analytics";
import {logger} from "redux-beacon/extensions/logger";
import {Action, compose, combineReducers} from "@ngrx/store";
import {ROUTER_NAVIGATION} from "@ngrx/router-store";
const pageView = (action: any): PageView => ({
hitType: "pageview",
page: action.payload.event.url,
});
export const eventsMap = {};
eventsMap[ROUTER_NAVIGATION] = pageView;
export const analyticsMetaReducer = compose(
combineReducers,
createMetaReducer(eventsMap, GoogleAnalytics, {logger: logger})
);
import {createMetaReducer} from "redux-beacon";
import {GoogleAnalytics, PageView} from "redux-beacon/targets/google-analytics";
import {logger} from "redux-beacon/extensions/logger";
import {Action, compose, combineReducers} from "@ngrx/store";
import {ROUTER_NAVIGATION} from "@ngrx/router-store";
const pageView = (action: any): PageView => ({
hitType: "pageview",
page: action.payload.event.url,
});
export const eventsMap = {};
eventsMap[ROUTER_NAVIGATION] = pageView;
export const analyticsMetaReducer = createMetaReducer(eventsMap, GoogleAnalytics, {logger: logger});
import {createMetaReducer} from "redux-beacon";
import {GoogleAnalytics, PageView} from "redux-beacon/targets/google-analytics";
import {logger} from "redux-beacon/extensions/logger";
import {Action, compose, combineReducers} from "@ngrx/store";
import {ROUTER_NAVIGATION} from "@ngrx/router-store";
const pageView = (action: any): PageView => ({
hitType: "pageview",
page: action.payload.event.url,
});
export const eventsMap = {};
eventsMap[ROUTER_NAVIGATION] = pageView;
export const analyticsMetaReducer = (reducer) => createMetaReducer(eventsMap, GoogleAnalytics, {logger: logger})(reducer);
There's a typo in the type definitions:
ERROR in redux-beacon/index.d.ts
(65,14): error TS1009: Trailing comma not allowed.
hi all,
i have a question.
sometimes i need call dataLayer.reset();
sample here
how do i call that method use by redux-beacon?
Currently in our codebase we have to do the following:
window.amplitude = require('amplitude-js')
module.exports = require('redux-beacon/targets/amplitude')
Which we then import and use:
import amplitude from 'amplitude-js'
import { createMiddleware } from 'redux-beacon'
import { Amplitude } from './redux-beacon-amplitude'
โฆ
amplitude.getInstance().init(โฆ)
createMiddleware(eventsMap, Amplitude, { offlineStorage })
It would be nice if redux-beacon-amplitude either required amplitude-js directly (peer dependency?) or could be passed in somehow (e.g. createMiddleware(eventsMap, amplitudeMiddleware(amplitude), { offlineStorage })
.
Would it be possible to let this library to just do nothing if setting up the middleware on server side render?
console:
ReferenceError: window is not defined
at myProject/node_modules/redux-beacon/targets/google-tag-manager/google-tag-manager.js:11:5
at Array.forEach (native)
at GoogleTagManager (myProject/node_modules/redux-beacon/targets/google-tag-manager/google-tag-manager.js:4:10)
at registerEvents (myProject/node_modules/redux-beacon/lib/register-events.js:31:5)
at Object.dispatch (myProject/node_modules/redux-beacon/lib/create-middleware.js:20:9)
Documentation for ngrx users is outdated Redux Beacon Quick Start (ngrx users) I was integrating redux-beacon with new version 4.x of ngrx and there are some differences. I made it to work after making those adjustments:
// Define an event
const pageView = (action: RouterNavigationAction<RouterStateSnapshot>): PageView => ({
hitType: 'pageview',
page: action.payload.routerState.url
});
// Map the event to an ngrx/store action
const eventsMap = {
'ROUTER_NAVIGATION': pageView,
};
I'm getting a error in IE 11 with the logger. Looking at the code, string.repeat isn't supported. Is there any way of replacing this with something else?
https://github.com/rangle/redux-beacon/blob/master/src/extensions/logger/logger.js#L26
Hi,
I'd like to add the following events to the redux-beacon RN GoogleAnalyticsTracker:
I'd also like to add the ability to add 'customDimensionsFieldsIndexMap' to the GA tracker.
This is all functionality which I imagine a lot of GA users should need. If you're happy to accept a PR then we'll get it done. Thanks
I am using redux-beacon with react-redux and GTM. Since GA has support for getting logged in user ID from datalayer variable, is there a way to push the userId to datalayer on login and keep in the datalayer till the user logs out?
Hi!
In a (really) few events I'm seeing some data arriving as undefined
. That data is being populated with info coming from nextState()
in the event definition. There is some scenario where the nextState()
arrives to the event definition as undefined
?
Thanks!
Problem: there are correct URLs for the pageView in Google Analytics, but page title is incorrect.
I was following Redux Beacon Quick Start (ngrx users) with some modifications (see Outdated documentation for ngrx users) because of the new version 4.x of ngrx.
Problem is that page title is changed in the page component's ngOnInit function:
export class DashboardPageComponent implements OnInit {
constructor(private titleService: Title) { }
ngOnInit() {
this.titleService.setTitle('Dashboard | Flex Funding');
}
}
so it is executed some time after ROUTER_NAVIGATION action. As a result I get incorrect (old) page titles in GA:
I did some workaround by introducing custom action after title is changed, but I would like to have some more generic solution:
export class DashboardPageComponent implements OnInit {
constructor(private store: Store<State>, private titleService: Title, private router: Router) { }
ngOnInit() {
this.titleService.setTitle('Dashboard | Flex Funding');
this.store.dispatch(new AppActions.PageChanged(this.router.routerState.snapshot.url));
}
}
const pageView = (action: any): PageView => ({
hitType: 'pageview',
page: action.payload
});
// Map the event to an ngrx/store action
const eventsMap: EventDefinitionsMap = {
//'ROUTER_NAVIGATION': pageView,
'[app] PAGE_CHANGED': pageView,
};
Any idea how to solve this problem?
I've worked a lot with redux-beacon using GTM target and this is my first try with Amplitude. I've follow almost exactly the docs, but when having a few events firing (at least I'm seeing everything ok in the logger) I noticed that the event are not being send to Amplitude. I started going through the code and I've found out that in the @redux-beacon/amplitude/dist/amplitude.js
, in the following validation
if (!window || !window.amplitude) {
return;
}
window.amplitude
is always undefined...
The code I've have so far is:
import { createMiddleware } from 'redux-beacon';
import amplitude from 'amplitude-js';
import Amplitude from '@redux-beacon/amplitude';
import reduxBeaconLogger from '@redux-beacon/logger';
import { logEvent } from '@redux-beacon/amplitude';
amplitude.getInstance().init('1234');
const target = Amplitude({ instance: amplitude.getInstance('INSTANCE_NAME') });
const customEvent = logEvent(action => ({
type: action.type,
}));
const eventsMap = {
[TRACK_EVENT]: customEvent,
};
const logger = process.env.NODE_ENV !== 'production' ? reduxBeaconLogger : null;
export default createMiddleware(eventsMap, target, { logger });
And the logger is showing this:
Am I missing something?
Hi!
I have implemented Redux Beacon with a React Native project that I'm working on using Google Tag Manager. I have created a middleware to dispatch events to GTM based my own action types but when I try to do the same for the dispatched actions that React Navigation uses, it doesn't trigger.
Have any of you got this working? The action types for React Navigation can be seen here.
The events map that I have set up looks like this:
const eventsMap = { 'Navigation/NAVIGATE': pageViewEvent, };
Navigation/NAVIGATE
is the action dispatched when navigating using the React Navigation library.
Any help is greatly appreciated :)
Is there any chance that you start an implementation of this package with Vuex store?
I have followed the provided documentation (as outlined here)
https://rangle.github.io/redux-beacon/docs/targets/react-native-google-tag-manager.html
Resulting in the following code:
import { Platform } from 'react-native'
import { createMiddleware } from 'redux-beacon'
import { GoogleTagManager as GTMBridge } from 'react-native-google-analytics-bridge'
import { GoogleTagManager } from 'redux-beacon/targets/react-native'
import { GTM_ID_ANDROID, GTM_ID_IOS } from '../config'
import { GTM_EVENT_NAME } from '../config'
const containerId = (Platform.OS === 'ios') ? GTM_ID_IOS : GTM_ID_ANDROID
const target = GoogleTagManager(containerId, GTMBridge)
console.log('everything initted')
const eventsMap = {
'EXAMPLE': (action) => {
console.log('foo')
return {
hitType: GTM_EVENT_NAME
}
}
}
const analyticsMiddleware = createMiddleware(eventsMap, GoogleTagManager)
reateStore(
initStore(AppNavigator, initRoute),
initData,
applyMiddleware(ReduxThunk, analyticsMiddleware)
)
This results in the following behaviour:
The application starts up just fine. However, when an 'EXAMPLE' event is emitted, the system crashes with:
console.js:26 Possible Unhandled Promise Rejection (id: 0):
Cannot read property 'openContainerWithId' of undefined
TypeError: Cannot read property 'openContainerWithId' of undefined
at GoogleTagManager (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:100639:12)
at registerEvents (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:100062:5)
at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:100026:9
at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:99982:16
at dispatch (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:53534:18)
at _callee$ (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:70225:13)
at tryCatch (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:21663:40)
at Generator.invoke [as _invoke] (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:21851:22)
at Generator.prototype.(anonymous function) [as next] (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:21688:21)
at tryCatch (
@redux-beacon/logger
That the payload for the pageView
event contains the GA Tracking ID in the trackingId
array.
{
page_location: undefined
page_path: "/topics"
page_title: undefined
trackingId: ["UA-XXXXXX-1"]
type: "page"
}
And that the page view is registered in the Google Analytics dashboard
The trackingId
array is empty:
{
page_location: undefined
page_path: "/topics"
page_title: undefined
trackingId: []
type: "page"
}
And the page view is not registered in Google Analytics
I've narrowed the bug down to this block inside google-analyitics-gtag.js
var trackingIds = [gaTrackingId];
if (typeof trackingId === 'string') {
trackingIds = [trackingId];
}
if (Array.isArray(trackingId)) {
trackingIds = trackingId;
}
trackingIds.forEach(function (id) {
gtag('config', id, params);
});
gtag()
is never called because trackingIds
is always an empty array.
Should be a a quick fix, but I haven't learned TypeScript yet otherwise I would raise a PR!
As detailed on GTM docs, it is possible to rename the data layer instance.
Default name is dataLayer
.
If I change it to something else, how can I tell redux-beacon to use the new name?
Thanks!
Note: for support questions, please use stackoverflow with the redux-beacon
tag. This repository's issues are reserved for feature requests and bug reports.
(If this is a bug report, feel free to delete the ๐ and ๐
sections. Likewise, if this is a documentation or feature request, feel free to
delete the ๐ชฒ sections)
No errors.
Typescript throws error [ts] Argument of type 'void' is not assignable to parameter of type 'Target'.
...Describe the feature or documentation you wish you had.
2.0.2
google analytics 1.0.2
Hi, and thanks for the great tool -- I'm trying to use multiple trackers along with 'ensure'. Ideally, I would like to map one event (one for for each tracker, let's say two trackers), to one redux action in eventsMap.
Is this possible? And, is it possible with 'ensure'? Should I be using combineEvents?
I have been trying to use the 'tracker' property, but no luck as of yet. It would be really awesome to have an example in the docs for such a use case.
Thanks so much!
I've noticed that none of the events were submitted to GTM anymore after updating to redux-beacon 0.4.0. I tried to find the reason for this, but I didn't get any errors in the console and nothing else helpful so the only way I could fix it is by reverting back to v0.3.0.
Are there any breaking changes that weren't mentioned? Otherwise this is probably a bug. In that case let me know if there's more info I could to provide to help with this.
Possibility to add a variable instead of event via target of Google Tag Manager.
Per Rangle's internal code review:
__tests__
sub folders in src
tests
, this folder doesn't need to exist.test.js
or .spec.js
file extension (for .eslintrc
)My React-Native iOS app crashed after deploying to AppStore TestFlight because the function console.group is only supported in browser, but not in node.js.
Can you make sure the logger is turned off by default on react-native production? This is a bit frustrating I need to check it inside my app code. The library should be checking that by itself IMO.
In one of our projects we need to use a custom tag manager (Tealium) , I think writing a custom target should be quite easy, would it be nice to put it in a pull request or do u think it would be better to publish it in a separate library?
Thanx
Hi!
I would like to uso a custom target to track events with an internal API. Is there a way I can make the target code inside my app (react/es6 app) or I need to have make it as a compilable package?
Hi guys, I noticed that redux-beacon
isn't working with Google Global Site Tag.
I started working on a PR for this, adding another module to targets
folder named google-global-site-tag
. Will update on progress!
I have page views working with segment, but I can't get an identify event to go through.
Code:
const pageView = {
eventFields: action => ({
hitType: 'pageview',
page: action.payload,
}),
};
const identify = {
eventFields: action => ({
hitType: 'identify',
userId: action.values.id,
}),
};
const eventsMap = {
LOCATION_CHANGE: pageView,
UPDATE_USER_INFO: identify,
};
const segmentMiddleware = createMiddleware(eventsMap, Segment);
Is this the proper way to do the identify call? Thanks!
I wish I had a possibility to change event map (passed to the metareducer of my ngrx store) in runtime. Our team needs to adjust analytics events data without rebuilding the application
I wish I had a possibility to send events to two or more receivers (targets)
It seems that react-router-redux@^5
is using @@router/LOCATION_CHANGE
instead of LOCATION_CHANGE
as currently documented in the docs.
Might be a good idea to document that. Also posting so others don't get stuck ๐
Note: for support questions, please use stackoverflow with the redux-beacon
tag. This repository's issues are reserved for feature requests and bug reports.
I'm referring to the page at https://rangle.gitbook.io/redux-beacon/targets/googletagmanager, and the lines:
I'm wondering when and why you'd want to use the hitType
property? Why not just use the event
property always? I originally assumed perhaps a hitType
property might not trigger a custom event, and may be a way of including an 'event' key without triggering an event. But it seems hitType
will trigger the event. So, why does hitType
exist?
Thanks for redux-beacon!
If you think a change to documentation is needed I'm happy to submit the PR.
https://rangle.github.io/redux-beacon/docs/targets/google-tag-manager.html
First bullet under Notes
.
The word just
is misspelled: jsut
.
Slack isn't an analytics platform, but in our app, we'd like to be notified to Slack with a similar set of events to what we use for Tag Manager.
I could probably work on developing this if you give me some guidance.
Looks like the last npm release was 26 October 2017, which means npm install
ing this package won't include the new features like GoogleAnalyticsGtag
(which I happen to personally need). Could you publish a new version to npm? Thanks! :)
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.