├── .babelrc ├── .eslintignore ├── .eslintrc ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── History.md ├── LICENSE ├── README.md ├── dist └── index.js ├── gulpfile.js ├── package.json ├── src ├── BrowserRouter.jsx ├── GoogleAnalytics.jsx └── index.js └── tests └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", {"loose": true}], 4 | "stage-0", 5 | "react", 6 | ], 7 | "plugins": [ 8 | "transform-decorators", 9 | "transform-class-properties", 10 | "add-module-exports" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "rules": { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [seeden] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | node_modules 3 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 0.1.16 / 2015-11-23 2 | ================== 3 | 4 | * added History log 5 | * bump eslint 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Zlatko Fedor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Google Analytics 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | 5 | [npm-image]: https://img.shields.io/npm/v/react-g-analytics.svg?style=flat-square 6 | [npm-url]: https://www.npmjs.com/react-g-analytics 7 | [github-url]: https://github.com/seeden/react-g-analytics 8 | 9 | ## Motivation 10 | 11 | I needed google analytics working in combination with react-router. 12 | 13 | ## Install 14 | ```sh 15 | npm install react-g-analytics 16 | ``` 17 | 18 | ## Features 19 | 20 | * Automatically load google analytics scripts (optional - id parameter) 21 | * Automatically send pageview when user will change current route of react-router 22 | 23 | # Support us 24 | 25 | Star this project on [GitHub][github-url]. 26 | 27 | ## Notice 28 | 29 | Use version 0.3.x of the react-g-analytics if you want to use it with react-router 4.x 30 | Use version 0.2.x of the react-g-analytics if you want to use it with react-router 2.x or 3.x 31 | 32 | ## Usage 33 | 34 | ### Example react-router 4.x 35 | 36 | User BrowserRouter from react-g-analytics instead of react-router. 37 | 38 | ```js 39 | import { BrowserRouter } from 'react-g-analytics'; 40 | 41 | export default function MyComponent() { 42 | return ( 43 | 44 | ... your application 45 | 46 | ); 47 | } 48 | 49 | > 50 | ``` 51 | 52 | ### Example react-router 3.x and bellow 53 | 54 | ### App.jsx 55 | 56 | Application part (load google analytics script to your webpage on the client side). 57 | ReactGAnalytics has parameter ID (use your own ID) 58 | 59 | ```js 60 | var React = require('react'); 61 | var GoogleAnalytics = require('react-g-analytics'); 62 | 63 | var App = module.exports = React.createClass({ 64 | render: function() { 65 | return ( 66 |
67 | 68 | 69 |
70 | ); 71 | } 72 | }); 73 | ``` 74 | 75 | ### routes.jsx 76 | 77 | Define your routes here. 78 | 79 | ```js 80 | var React = require('react'); 81 | var Router = require('react-router'); 82 | var Route = Router.Route; 83 | var DefaultRoute = Router.DefaultRoute; 84 | var Index = require('./Index.jsx'); 85 | var App = require('./App.jsx'); 86 | 87 | var routes = module.exports = ( 88 | 89 | 90 | 91 | ); 92 | ``` 93 | 94 | ### client.js 95 | 96 | Here is a simple client side 97 | 98 | ```js 99 | var React = require('react'); 100 | var app = require('./App.jsx'); 101 | var routes = require('./routes.jsx'); 102 | 103 | var router = Router.create({ 104 | routes: routes 105 | }); 106 | 107 | router.run(function(Handler, state) { 108 | React.render(React.createElement(Handler, {}), node); 109 | }); 110 | ``` 111 | 112 | ## Set 113 | 114 | If you want to set google analytics parameters after load you can use property named set. Here is small example: 115 | 116 | ```js 117 | var React = require('react'); 118 | var GoogleAnalytics = require('react-g-analytics'); 119 | var RouteHandler = require('react-router').RouteHandler; 120 | 121 | var set = { 122 | anonymizeIp: true 123 | }; 124 | 125 | var App = module.exports = React.createClass({ 126 | render: function() { 127 | return ( 128 |
129 | 130 | 131 |
132 | ); 133 | } 134 | }); 135 | ``` 136 | 137 | ## Skip loading google analytics scripts 138 | 139 | If you are loading the GA in different way. You can skip autoload of the GA script simply: 140 | Do not enter your google analytics ID as parameter. 141 | 142 | ## Try our other React components 143 | 144 | - Translate your great project [react-translate-maker](https://github.com/CherrySoftware/react-translate-maker) 145 | - Forms [react-form-controlled](https://github.com/seeden/react-form-controlled) 146 | - Google AdSense via Google Publisher Tag [react-google-publisher-tag](https://github.com/seeden/react-google-publisher-tag) 147 | 148 | # Support us 149 | 150 | Star this project on [GitHub][github-url]. 151 | 152 | ## Credits 153 | 154 | [Zlatko Fedor](http://github.com/seeden) 155 | 156 | ## License 157 | 158 | The MIT License (MIT) 159 | 160 | Copyright (c) 2016 Zlatko Fedor zlatkofedor@cherryprojects.com 161 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | exports.BrowserRouter = undefined; 5 | 6 | var _BrowserRouter2 = require('./BrowserRouter'); 7 | 8 | var _BrowserRouter3 = _interopRequireDefault(_BrowserRouter2); 9 | 10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 11 | 12 | exports.BrowserRouter = _BrowserRouter3.default; -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import babel from 'gulp-babel'; 3 | 4 | gulp.task('build', () => { 5 | return gulp.src('./src/**/*.{js,jsx}') 6 | .pipe(babel()) 7 | .pipe(gulp.dest('./dist')); 8 | }); 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-g-analytics", 3 | "version": "0.4.2", 4 | "description": "React google analytics with support for react-router", 5 | "author": { 6 | "name": "Zlatko Fedor", 7 | "email": "zfedor@gmail.com", 8 | "url": "http://www.cherryprojects.com/" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/seeden/react-g-analytics.git" 13 | }, 14 | "keywords": [ 15 | "react", 16 | "react-component", 17 | "react-router", 18 | "analytics", 19 | "google", 20 | "google analytics" 21 | ], 22 | "private": false, 23 | "license": "MIT", 24 | "main": "./dist/index.js", 25 | "engines": { 26 | "node": ">= 0.12.0" 27 | }, 28 | "scripts": { 29 | "prepublish": "npm run build", 30 | "test": "jest", 31 | "build": "babel-node ./node_modules/gulp/bin/gulp.js build", 32 | "eslint": "node ./node_modules/eslint/bin/eslint.js --ext .js,.jsx ." 33 | }, 34 | "dependencies": { 35 | "history": "^4.6.1", 36 | "prop-types": "^15.5.8" 37 | }, 38 | "devDependencies": { 39 | "babel-cli": "^6.24.1", 40 | "babel-core": "^6.24.1", 41 | "babel-eslint": "^7.2.2", 42 | "babel-plugin-transform-decorators": "^6.24.1", 43 | "babel-plugin-transform-class-properties": "^6.24.1", 44 | "babel-preset-es2015": "^6.24.1", 45 | "babel-preset-react": "^6.24.1", 46 | "babel-preset-stage-0": "^6.24.1", 47 | "babel-preset-stage-1": "^6.24.1", 48 | "babel-plugin-add-module-exports": "^0.2.1", 49 | "eslint": "3.19.0", 50 | "eslint-config-airbnb": "^14.1.0", 51 | "eslint-loader": "^1.7.1", 52 | "eslint-plugin-react": "^6.10.3", 53 | "eslint-plugin-jsx-a11y": "^4.0.0", 54 | "eslint-plugin-import": "^2.2.0", 55 | "gulp": "^3.9.1", 56 | "gulp-babel": "^6.1.2", 57 | "gulp-util": "^3.0.8", 58 | "react": "^15.5.4", 59 | "react-dom": "^15.5.4", 60 | "react-router-dom": "^4.1.1" 61 | }, 62 | "peerDependencies": { 63 | "react": "15.x", 64 | "react-router-dom": "4.x" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/BrowserRouter.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Router, BrowserRouter } from 'react-router-dom'; 4 | import createBrowserHistory from 'history/createBrowserHistory'; 5 | import GoogleAnalytics from './GoogleAnalytics'; 6 | 7 | export default class GABrowserRouter extends Component { 8 | static propTypes = { 9 | ...BrowserRouter.propTypes, 10 | history: PropTypes.object, 11 | children: PropTypes.node, 12 | id: PropTypes.string.isRequired, 13 | set: PropTypes.object, 14 | }; 15 | 16 | static childContextTypes = { 17 | history: PropTypes.object.isRequired, 18 | }; 19 | 20 | getChildContext() { 21 | return { 22 | history: this.history, 23 | }; 24 | } 25 | 26 | componentWillMount() { 27 | const { 28 | history, 29 | basename, 30 | forceRefresh, 31 | getUserConfirmation, 32 | keyLength, 33 | } = this.props; 34 | 35 | this.history = history || createBrowserHistory( 36 | basename, 37 | forceRefresh, 38 | getUserConfirmation, 39 | keyLength, 40 | ); 41 | } 42 | 43 | render() { 44 | const { 45 | id, 46 | set, 47 | children, 48 | } = this.props; 49 | 50 | return ( 51 | 52 | 53 | {children} 54 | 55 | 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/GoogleAnalytics.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function loadScript() { 5 | const gads = document.createElement('script'); 6 | gads.async = true; 7 | gads.type = 'text/javascript'; 8 | gads.src = '//www.google-analytics.com/analytics.js'; 9 | 10 | const head = document.getElementsByTagName('head')[0]; 11 | head.appendChild(gads); 12 | } 13 | 14 | function initGoogleAnalytics(id, set) { 15 | if (window.ga || !id) { 16 | return; 17 | } 18 | 19 | window.ga = window.ga || function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; // eslint-disable-line 20 | 21 | loadScript(); 22 | 23 | window.ga('create', id, 'auto'); 24 | 25 | if (set) { 26 | Object.keys(set).forEach((key) => { 27 | window.ga('set', key, set[key]); 28 | }); 29 | } 30 | } 31 | 32 | export default class GoogleAnalytics extends Component { 33 | static propTypes = { 34 | id: PropTypes.string, 35 | set: PropTypes.object, 36 | children: PropTypes.node, 37 | }; 38 | 39 | static contextTypes = { 40 | history: PropTypes.object.isRequired, 41 | }; 42 | 43 | static command(what, options, ...args) { 44 | if (!window.ga) { 45 | throw new Error('Google analytics is not initialized'); 46 | } 47 | 48 | if (typeof options === 'string') { 49 | return window.ga(what, options, ...args); 50 | } 51 | 52 | return window.ga(what, options); 53 | } 54 | 55 | static set(...options) { 56 | return GoogleAnalytics.command('set', ...options); 57 | } 58 | 59 | static send(...options) { 60 | return GoogleAnalytics.command('send', ...options); 61 | } 62 | 63 | componentDidMount() { 64 | initGoogleAnalytics(this.props.id, this.props.set); 65 | 66 | const { history } = this.context; 67 | this.unlisten = history.listen(this.onLocationChange); 68 | 69 | // send current pageview 70 | this.pageview(history.location); 71 | } 72 | 73 | onLocationChange = (location, action) => { 74 | this.pageview(location); 75 | } 76 | 77 | componentWillUnmount() { 78 | if (this.unlisten) { 79 | this.unlisten(); 80 | this.unlisten = null; 81 | } 82 | } 83 | 84 | pageview(location) { 85 | const path = location.pathname + location.search; 86 | if (this.latestUrl === path) { 87 | return; 88 | } 89 | 90 | this.latestUrl = path; 91 | 92 | // user can change the title 93 | setTimeout(() => { 94 | GoogleAnalytics.set({ 95 | page: path, 96 | title: document.title, 97 | location: document.location, 98 | }); 99 | 100 | GoogleAnalytics.send({ 101 | hitType: 'pageview', 102 | }); 103 | }, 0); 104 | } 105 | 106 | render() { 107 | return this.props.children; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export BrowserRouter from './BrowserRouter'; 2 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeden/react-g-analytics/538e8b3820629f9a4b0fbe38ac4e961b6fbfe622/tests/test.js --------------------------------------------------------------------------------