Jak skonfigurować Google Analytics dla React-Router?

86

Próbuję skonfigurować Google Analytics w mojej witrynie React i natknąłem się na kilka pakietów, ale żaden z nich nie jest tak skonfigurowany, jak ja, jeśli chodzi o przykłady. Miał nadzieję, że ktoś może rzucić na to trochę światła.

Pakiet, na który patrzę, to: react-ga .

Moja metoda renderowania index.jswygląda tak.

React.render((
<Router history={createBrowserHistory()}>
    <Route path="/" component={App}>
        <IndexRoute component={Home} onLeave={closeHeader}/>
        <Route path="/about" component={About} onLeave={closeHeader}/>
        <Route path="/gallery" component={Gallery} onLeave={closeHeader}/>
        <Route path="/contact-us" component={Contact} onLeave={closeHeader}>
            <Route path="/contact-us/:service" component={Contact} onLeave={closeHeader}/>
        </Route>
        <Route path="/privacy-policy" component={PrivacyPolicy} onLeave={closeHeader} />
        <Route path="/feedback" component={Feedback} onLeave={closeHeader} />
    </Route>
    <Route path="*" component={NoMatch} onLeave={closeHeader}/>
</Router>), document.getElementById('root'));
John Fu
źródło
4
Zamieszczona odpowiedź na react-router-4/ react-router-domponiżej, tutaj najlepsza odpowiedź dotyczy wcześniejszych wersji routera React i niestety nie będzie działać z wersją 4.
Peter Berg,
Jak mogę to dodać za pomocą StaticRouter, gdy używam Reagowania SSR?
Subhendu Kundu

Odpowiedzi:

85

Zachowaj odniesienie do obiektu historii. to znaczy

import { createBrowserHistory } from 'history';

var history = createBrowserHistory();

ReactDOM.render((
    <Router history={history}>
        [...]

Następnie dodaj odbiornik, aby rejestrować każdą odsłonę. (Zakłada się, że obiekt został już skonfigurowany window.gaw zwykły sposób).

history.listen((location) => {
    window.ga('set', 'page', location.pathname + location.search);
    window.ga('send', 'pageview');
});
David L. Walsh
źródło
16
Nie będzie to uwzględniać wysyłanych zdarzeń ani innych typów trafień. Będą nadal odnosić się do adresu URL w czasie ładowania strony. Zamiast tego musisz ustawić nową wartość w module śledzącym przed wysłaniem odsłony strony, np ga('set', 'page', location.pathname + location.search); ga('send', 'pageview');.
Philip Walton,
1
Cześć David, czy Twój przykład używa zwykłego kodu ga z witryny ga, czy też pakietu react-ga? Dzięki.
John Fu
Nie zdecydowałem jeszcze, jak to naprawić, ale ta informacja może być również przydatna: stackoverflow.com/questions/30052693/ (wyjaśnia, dlaczego atrybucja może nie działać poprawnie w niektórych przypadkach, a także wprowadza wysokie współczynniki odrzuceń ).
DeTeam
Nie chcesz trzeciego parametru w poleceniu wysyłania. „Chociaż z technicznego punktu widzenia polecenie wysyłania dla odwiedzin odsłony akceptuje opcjonalne pole strony jako trzeci parametr, przekazywanie pola strony w ten sposób nie jest zalecane w przypadku śledzenia aplikacji jednostronicowych. Dzieje się tak, ponieważ pola przekazane za pomocą polecenia wysyłania nie są ustawiane w module śledzącym. mają one zastosowanie tylko do aktualnego trafienia. Brak aktualizacji modułu śledzącego spowoduje problemy, jeśli Twoja aplikacja wyśle ​​jakiekolwiek działania niezwiązane z odsłoną (np. zdarzenia lub interakcje społecznościowe), ponieważ te trafienia będą powiązane z dowolną wartością strony, jaką posiadał moduł śledzący, gdy został utworzony. "
Joshua Robinson,
30

Zakładając, że Google Analytics jest ładowane i inicjowane z identyfikatorem śledzenia.

Oto rozwiązanie dla React-router w wersji 4 wykorzystujące <Route>komponent do śledzenia wyświetleń strony.

<Route path="/" render={({location}) => {
  if (typeof window.ga === 'function') {
    window.ga('set', 'page', location.pathname + location.search);
    window.ga('send', 'pageview');
  }
  return null;
}} />

Po prostu renderujesz ten komponent wewnątrz <Router>(ale nie jako bezpośrednie dziecko a <Switch>).

Dzieje się tak, że za każdym razem, gdy zmienia się właściwość lokalizacji, powoduje to ponowne renderowanie tego komponentu (a nie renderowanie niczego), który uruchamia odsłonę.

heyhugo
źródło
1
React-router 4. Czy jest coś, czego nie może zrobić ?!
Anthony Cregan
1
Poniżej zamieściłem kolejne rozwiązanie react-router-4, które nie wymaga modyfikacji poszczególnych tras. Niestety jest to zdecydowanie sytuacja typu „wybierz swoją truciznę”.
Peter Berg
1
Czy to nie znaczy, że przejście do „/” nic nie wyrenderuje?
Dana Woodman
3
Po prostu wybierz inną trasę, która emituje wszystko, co chcesz @DanaWoodman. Zakłada się, że trasa nie jest wSwitch
bozdoz
Czy spowoduje to śledzenie dwóch odsłon na stronie docelowej? Widząc, że GA automatycznie śledzi stronę docelową, wyzwalamy dla niej dodatkowe zdarzenie odsłony. A może GA to odfiltrowuje?
ArneHugo
27

Używam React Router v4 i Google Analytics globalnego tagu witryny , który wydaje się być zalecany w chwili pisania tego.

A oto moje rozwiązanie:

Utwórz komponent opakowany w withRouter z react-router-dom:

import React from 'react';
import { withRouter } from 'react-router-dom';
import { GA_TRACKING_ID } from '../config';

class GoogleAnalytics extends React.Component {
    componentWillUpdate ({ location, history }) {
        const gtag = window.gtag;

        if (location.pathname === this.props.location.pathname) {
            // don't log identical link clicks (nav links likely)
            return;
        }

        if (history.action === 'PUSH' &&
            typeof(gtag) === 'function') {
            gtag('config', GA_TRACKING_ID, {
                'page_title': document.title,
                'page_location': window.location.href,
                'page_path': location.pathname
            });
        }
    }

    render () {
        return null;
    }
}

export default withRouter(GoogleAnalytics);

Po prostu dodaj komponent do routera (uważam, że najlepiej po wszystkich trasach, które byłyby dopasowane, i dowolnych komponentach Switch, ponieważ funkcja analityczna nie powinna mieć pierwszeństwa przed renderowaniem witryny):

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import IndexPage from './IndexPage';
import NotFoundPage from './NotFoundPage';
import GoogleAnalytics from './GoogleAnalytics';

const App = () => (
    <Router>
        <Switch>
            <Route exact path="/" component={IndexPage} />
            <Route component={NotFoundPage} />
        </Switch>
        <GoogleAnalytics />
    </Router>
);

Jak wspomniano:

withRouter ponownie wyrenderuje swój komponent za każdym razem, gdy trasa zmieni się z tymi samymi właściwościami, co właściwości renderowania

Więc kiedy trasa się zmieni, GoogleAnalyticskomponent zostanie zaktualizowany, otrzyma nową lokalizację jako rekwizyty i history.actionbędzie albo PUSHdla nowego elementu historii, albo POPzasygnalizował cofnięcie się w historii (co myślę, że nie powinno wywołać wyświetlenia strony, ale można dostosować, jeśli oświadczenia componentWillUpdatezgodnie z potrzebami (można nawet spróbować componentDidUpdateze this.propszamiast, ale jestem pewien, co jest lepsze)).

bozdoz
źródło
bozdoz jak dodałeś globalny tag witryny do swojej strony. Czy właśnie dodałeś <script async src = " googletagmanager.com/gtag/js?id=GA_TRACKING_ID " > </… > do swojej strony html pod tagiem body?
me-me
1
@ me-me Yes. Ale w tagu body:<body> ... <script ...></script></body>
bozdoz
Potrzebnych było kilka poprawek dla najnowszego routera React i React. Zmień componentWillMountna componentDidMount. Zmień page_pathTO this.props.location.pathname. Owiń komponenty Switch i GoogleAnalytics w <div>
mjhm
Nie jestem pewien, gdzie widzisz componentWillMount, i nie jestem pewien, jak się page_pathróżni, ale spróbuję owinąć komponent Switch i GA <React.Fragment>zamiast div. Dzięki!
bozdoz
2
Hej @JoshuaRobinson, napisałem na dole: „... myślę, że nie powinienem uruchamiać wyświetlenia strony, ale możesz dostosować ...”. To pytanie dotyczyło integracji Google Analytics z React Router, a nie tego, które widoki należy rejestrować. Powiedziawszy to, mogę dostosować mój komponent, ponieważ Google będzie śledził go inaczej po ich końcu. Dzięki.
bozdoz
19

Uwaga, jeśli korzystasz z react-router-dompakietu react-router-4, możesz sobie z tym poradzić w następujący sposób:

import { Router, Route } from 'react-router-dom';
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
const initGA = (history) => {
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'YOUR_IDENTIFIER_HERE', 'auto');
  ga('send', 'pageview');

  history.listen((location) => {
    console.log("tracking page view: " + location.pathname);
    ga('send', 'pageview', location.pathname);
  });
};

initGA(history);

class App extends Component { //eslint-disable-line
  render() {
    return
      (<Router history={history} >
         <Route exact path="/x" component={x} />
         <Route exact path="/y" component={y} />
       </Router>)
  }
}

Zauważ, że wymaga to zainstalowania historypakietu ( npm install history). Jest to już zależność reakcja-router-dom, więc nie dodajesz tutaj żadnej wagi strony.

Uwaga: nie jest możliwe użycie komponentu BrowserRouter ORAZ instrumentu śledzenia ga w ten sposób. To jest w porządku, ponieważ komponent BrowserRouter jest po prostu bardzo cienką otoczką wokół obiektu Router. Odtworzyliśmy tutaj funkcjonalność BrowserRouter z <Router history={history}>miejscem, w którym const history = createBrowserHistory();.

Peter Berg
źródło
nigdy nie dzwoniłeś do initGA?
Muhammad Umer,
@MuhammadUmer prawda, właśnie to naprawiłem
Peter Berg,
Dlaczego po prostu nie dodasz GA do statycznego kodu HTML? Dałem ci plus. Ponieważ uważam, że słuchanie obiektu historii jest właściwą drogą.
Vince V.
@VinceV. Można sobie wyobrazić, że można zainicjować historyobiekt w swojej kompilacji, a następnie zapisać historię na windowobiekcie i uzyskać do niej dostęp w tagu skryptu w swoim, <head>ale myślę, że ostatecznie spowodowałoby to, że potok kompilacji byłby bardziej skomplikowany. ¯_ (ツ) _ / ¯
Peter Berg
Jeśli używasz BrowserRouterkomponentu, zobacz odpowiedź poniżej, która oferuje alternatywne rozwiązanie.
Toshe
14

Sugerowałbym użycie doskonałego react-router-gapakietu, który jest niezwykle lekki i łatwy w konfiguracji, szczególnie w przypadku korzystania z BrowserRouteropakowania.

Zaimportuj komponent:

import Analytics from 'react-router-ga';

Następnie po prostu dodaj <Analytics>w swoim BrowserRouter:

<BrowserRouter>
    <Analytics id="UA-ANALYTICS-1">
        <Switch>
            <Route path="/somewhere" component={SomeComponent}/>
        </Switch>
    </Analytics>
</BrowserRouter>
Toshe
źródło
Wydaje się, że jest to bardzo proste rozwiązanie, jeśli użytkownik chce śledzić tylko wyświetlenia stron. Bardzo chudy!
peyo
11

Podoba mi się to, co sugeruje tutaj Mark Thomas Müller :

W pliku index.js

import ReactGA from 'react-ga'

ReactGA.initialize('YourAnalyticsID')

ReactDOM.render(<App />, document.getElementById('root'))

Gdzie są twoje trasy:

import React, { Component } from 'react'
import { Router, Route } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
import ReactGA from 'react-ga'

const history = createHistory()
history.listen(location => {
    ReactGA.set({ page: location.pathname })
    ReactGA.pageview(location.pathname)
})

export default class AppRoutes extends Component {
    componentDidMount() {
        ReactGA.pageview(window.location.pathname)
    }

    render() {
        return (
            <Router history={history}>
                <div>
                    <Route path="/your" component={Your} />
                    <Route path="/pages" component={Pages} />
                    <Route path="/here" component={Here} />
                </div>
            </Router>
        )
    }
}

Krótkie, skalowalne i proste :)

Jöcker
źródło
dlaczego jest śledzenie, jedno globalne, jedno lokalne?
Thellimist
11

Ponieważ react-router v5.1.0można to rozwiązać o wiele łatwiej za pomocą useLocation.

usePageTracking.js

import { useEffect} from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga";

const usePageTracking = () => {
  const location = useLocation();

  useEffect(() => {
    ReactGA.initialize("UA-000000000-0");
    ReactGA.pageview(location.pathname + location.search);
  }, [location]);
};

export default usePageTracking;

App.js

const App = () => {
  usePageTracking();

  return (...);
};

Zobacz też:

Oto nieco inteligentniejsza wersja:

usePageTracking.js

import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga";

const usePageTracking = () => {
  const location = useLocation();
  const [initialized, setInitialized] = useState(false);

  useEffect(() => {
    if (!window.location.href.includes("localhost")) {
      ReactGA.initialize("UA-000000000-0");
    }
    setInitialized(true);
  }, []);

  useEffect(() => {
    if (initialized) {
      ReactGA.pageview(location.pathname + location.search);
    }
  }, [initialized, location]);
};

export default usePageTracking;
to mój projekt
źródło
Nie jestem pewien, czy jest to konieczne w przypadku najnowszego „gtag”. Kiedy nawiguję, debugger ga wydaje się poprawnie rejestrować zdarzenie push: Processing data layer push: {event: "gtm.historyChange-v2", gtm.historyChangeSource: "pushState", gtm.oldUrlFragment: "", gtm.newUrlFragment: "", gtm.oldHistoryState: null, gtm.newHistoryState: {key: "j5xoc4", state: undefined}, gtm.oldUrl: "https://site/", gtm.newUrl: "https://site/new-url?search-params", gtm.triggers: "1_36"}i nowy widok strony jest wyświetlany na pulpicie nawigacyjnym ga
Dattaya,
6

Zawsze postępuj zgodnie z zaleceniami biblioteki

W dokumentacji React-GA dodali komponent społeczności zalecany do używania z React Router: https://github.com/react-ga/react-ga/wiki/React-Router-v4-withTracker

Realizacja

import withTracker from './withTracker';

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <Route component={withTracker(App, { /* additional attributes */ } )} />
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root'),
);

Kod

import React, { Component, } from "react";
import GoogleAnalytics from "react-ga";

GoogleAnalytics.initialize("UA-0000000-0");

const withTracker = (WrappedComponent, options = {}) => {
  const trackPage = page => {
    GoogleAnalytics.set({
      page,
      ...options,
    });
    GoogleAnalytics.pageview(page);
  };

  // eslint-disable-next-line
  const HOC = class extends Component {
    componentDidMount() {
      // eslint-disable-next-line
      const page = this.props.location.pathname + this.props.location.search;
      trackPage(page);
    }

    componentDidUpdate(prevProps) {
      const currentPage =
        prevProps.location.pathname + prevProps.location.search;
      const nextPage =
        this.props.location.pathname + this.props.location.search;

      if (currentPage !== nextPage) {
        trackPage(nextPage);
      }
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };

  return HOC;
};

export default withTracker;
Paras
źródło
1
jeśli używam SSR (renderowanie po stronie serwera), GA nie zna rzeczywistego tytułu strony bez odświeżania strony.
Francis Rodrigues,
1
Możesz zmienić tytuł na wierzchu za pomocą React
Paras
Dzięki za wiadomość!
Sailesh Kotha
skąd storepochodzi?
user_78361084
Skąd pochodzi Provideri ConnectedRouterskąd? To jest niepełna odpowiedź i powinna zostać odrzucona
user_78361084,
2

Najpierw w pliku index.js ustaw funkcję onUpdate, aby wywołać ga

import ga from 'ga.js';
onUpdate() {
  console.log('=====GA=====>', location.pathname);
  console.log('=====GA_TRACKING_CODE=====>', GA_TRACKING_CODE);
  ga("send", "pageview", location.pathname);
}

render() {
  return (
    <Router onUpdate={this.onUpdate.bind(this)}>...</Router>
  );
}

Oraz ga.js:

'use strict';
if(typeof window !== 'undefined' && typeof GA_TRACKING_CODE !== 'undefined') {
  (function(window, document, script, url, r, tag, firstScriptTag) {
    window['GoogleAnalyticsObject']=r;
    window[r] = window[r] || function() {
      (window[r].q = window[r].q || []).push(arguments)
    };
    window[r].l = 1*new Date();
    tag = document.createElement(script),
    firstScriptTag = document.getElementsByTagName(script)[0];
    tag.async = 1;
    tag.src = url;
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  })(
    window,
    document,
    'script',
    '//www.google-analytics.com/analytics.js',
    'ga'
  );

  var ga = window.ga;

  ga('create', GA_TRACKING_CODE, 'auto');

  module.exports = function() {
    return window.ga.apply(window.ga, arguments);
  };
} else {
  module.exports = function() {console.log(arguments)};
}
WeiYuan
źródło
która wersja routera jest tutaj używana?
Pavan
to jest dla routera reakcja dom v2 lub v3, a nie v4
Hugo Gresse
2

oto najprostszy sposób śledzenia wszystkich ścieżek z pewnymi obejściami:

npm i --save history react-ga

utwórz plik history.js

import { createBrowserHistory } from "history"
import ReactGA from "react-ga"

ReactGA.initialize(process.env.REACT_APP_GA)

const history = createBrowserHistory()
history.listen((location) => {
    ReactGA.pageview(location.pathname)
})

// workaround for initial visit
if (window.performance && (performance.navigation.type === performance.navigation.TYPE_NAVIGATE)) {
    ReactGA.pageview("/")
}

export default history

a następnie zaimportuj go do miejsca, w którym jest ustawiony plik Router

import history from "./history"

...

class Route extends Component {
render() {
    return (
        <Router history={history}>
            <Switch>
              <Route path="/" exact component={HomePage} />
              ...
            </Switch>
        </Router>
    )
}

export default Route

Bibliografia:

Gustavo Gonzalez | medium.com

Historia | GitHub

fsilva
źródło
2

Proponuję skorzystać z biblioteki analitycznej segmentu i postępować zgodnie z przewodnikiem szybkiego startu React, aby śledzić wywołania stron za pomocą biblioteki React -router . Możesz zezwolić <Route />komponentowi na obsługę renderowania strony i używać go componentDidMountdo wywoływania pagepołączeń. Poniższy przykład pokazuje jeden sposób, w jaki możesz to zrobić:

    const App = () => (
      <div>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
        </Switch>
      </div>
    );

    export default App;
    export default class Home extends Component {
      componentDidMount() {
        window.analytics.page('Home');
      }

      render() {
        return (
          <h1>
            Home page.
          </h1>
        );
      }
    }

Jestem opiekunem https://github.com/segmentio/analytics-react . Dzięki Segmentowi możesz włączać i wyłączać różne miejsca docelowe za pomocą przełącznika, jeśli chcesz wypróbować wiele narzędzi analitycznych (obsługujemy ponad 250 miejsc docelowych) bez konieczności pisania dodatkowego kodu. 🙂

William
źródło
1

Jeśli korzystasz z skrótu lub historii przeglądarki, możesz:

import trackingHit from 'tracking';

import { Router, browserHistory } from 'react-router';
browserHistory.listen(trackingHit);
// OR
import { Router, hashHistory } from 'react-router';
hashHistory.listen(trackingHit);

gdzie ./tracking.es6

export default function(location) {
    console.log('New page hit', location.pathname);
    // Do your shizzle here
}
sidonaldson
źródło
0

podstawowa implementacja reakcji-ga z Twoim index.js

var ReactGA = require('react-ga'); // require the react-ga module
ReactGA.initialize('Your-UA-ID-HERE'); // add your UA code 

function logPageView() { // add this function to your component
  ReactGA.set({ page: window.location.pathname + window.location.search });
  ReactGA.pageview(window.location.pathname + window.location.search);
}

React.render((
<Router history={createBrowserHistory()} onUpdate={logPageView} > // insert onUpdate props here
    <Route path="/" component={App}>
        <IndexRoute component={Home} onLeave={closeHeader}/>
        <Route path="/about" component={About} onLeave={closeHeader}/>
        <Route path="/gallery" component={Gallery} onLeave={closeHeader}/>
        <Route path="/contact-us" component={Contact} onLeave={closeHeader}>
            <Route path="/contact-us/:service" component={Contact} onLeave={closeHeader}/>
        </Route>
        <Route path="/privacy-policy" component={PrivacyPolicy} onLeave={closeHeader} />
        <Route path="/feedback" component={Feedback} onLeave={closeHeader} />
    </Route>
    <Route path="*" component={NoMatch} onLeave={closeHeader} />
</Router>), document.getElementById('root'));
Isaac Pak
źródło
@BigDong Nie wiem, co to jest closeHeader. Musiałbyś zadać OP to pytanie, ponieważ kod renderowania jest jego. Po prostu pokazuję, jak zaimplementowałbyś reakcję-ga dla jego kodu (poszukaj moich // komentarzy)
Isaac Pak
0

Na podstawie sugestii @ david-l-walsh i @bozdoz

I stworzył hoc wykonać ten window.ga('set','page','{currentUrl})i window.ga('send', 'pageview');funkcję i jest w łatwy stosowany bezpośrednio na stronie routera ...

to jest HOC:

import React from 'react';
import { history } from '../../store'; // or wherever you createBrowserHistory(); invokation is

function withGAHistoryTrack(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
    }

    componentDidMount() {
      const { location } = history;
      const page = location.pathname + location.search;

      if (typeof window.ga === 'function') {
        window.ga('set', 'page', page);
        window.ga('send', 'pageview');
      }
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}

export default withGAHistoryTrack;

i jest używany w ten sposób na stronie routera:

<Route
 path={'yourPath'}
 component={withGAHistoryTrack(yourComponent)}
 exact
/>
Yuri Scarbaci
źródło
0

Aby dynamicznie aktualizować adres URL w niektórych zdarzeniach (takich jak onClick itp.), Można użyć:

 //Imports
 import ReactGA from "react-ga";
 import { createBrowserHistory } from "history";

 // Add following on some event, like onClick (depends on your requirement)
 const history = createBrowserHistory();
 ReactGA.initialize("<Your-UA-ID-HERE>");
 ReactGA.pageview(history.location.pathname);
Santosh Pillai
źródło