Giter VIP home page Giter VIP logo

react-gtm-hook's Introduction

Guido Porcaro Logo

Welcome, mate πŸ’œ

I'm Guido but I'm mostly known as elgorditosalsero both on the web and IRL.

About me

Working life πŸ’»

While working, I'm a Staff Software Engineer and Tech Lead of my team at Zendesk (GitHub)

When I have some free time from my best hobby that you'll discover soon, I contribute to the open source both via personal or someone projects.

Who I really am πŸ•Ί

While I'm NOT working, I'm a passionate salsa (and slightly bachata) dancer and you can have some sneak peeks on my Insta

Some other info about me

  • πŸ’» Β  I like to code in JavaScript, TypeScript and CSS.
  • πŸ–₯️ Β  I'm working mostly with and React
  • πŸ¦„ Β  In love with RxJS although I'm not using is as much as I wish 😒

Learn more about me

You can learn more about me and what I do on my Website or reading my Blog

Let's connect!

You can connect with me via Linktree

Contact me

If you need to contact me with some specific topic you can mail me here:

  • Say hello: hello[at]guidoporcaro.dev
  • Requesting information: info[at]guidoporcaro.dev
  • Issues with some projects: support[at]guidoporcaro.dev

Support

You can show support in many ways:


Elgorditosalsero's GitHub stats

react-gtm-hook's People

Contributors

benyap avatar cristianlivella avatar daisy1754 avatar dependabot[bot] avatar elgorditosalsero avatar iaurg avatar jafin avatar johantor avatar listiani13 avatar perfectial-stepan-mandryka avatar pkulcsarnr avatar simonsmith avatar sin-to-jin avatar ssijak avatar thebiltheory avatar thecoder93 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-gtm-hook's Issues

Sever connection when Consent gets disabled

Hi, I'm having the issue that once a user changes the consent from accept to deny to connection to GTM still persists. I have tried overwriting the gtmParms on consent change without success (arbitrary strings or undefined). Collect still pops up in the network tab.

Also I tried to tie useGTMDispatch to the condition of consent being true. Which works but once a consent change happens such as false, true, false, I still get data getting sent to GTM.

It seems no matter what what I do, once the react gtm hook connects to GTM ,its connection can not be disabled again.
Has anyone ever run into this problem or knows a way out?

Can't see any history tags with basic implementation ?

Hey,

I just implemented basic configuration as follow:

[...]
const {init} = useGTM();

useEffect(() => {
  init({id: environment.gtmId});
}, [init])

We are tracking History API of the browser for SPA. But can't see any tags of my pages!

Do i miss something ?

Feature request: Environments

Hey guys, what do you think about adding support for environments?
https://www.simoahava.com/analytics/better-qa-with-google-tag-manager-environments/

Would love to contribute for that!

Basically it boils down to parsing gtm_auth and gtm_preview params in a slightly different snippet:

<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl+ '&gtm_auth=<token>&gtm_preview=env-3&gtm_cookies_win=x';f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX);</script>

ire is not defined

Hey,

I'm trying to use your hook and for some events I'm getting weird error message:

Uncaught ReferenceError: ire is not defined
    at <anonymous>:1:1
    at gtm.js?id=GTM-AAAAAA:502:414
    at gtm.js?id=GTM-AAAAAA:503:118
    at b (gtm.js?id=GTM-AAAAAA:503:329)
    at Ge (gtm.js?id=GTM-AAAAAA:92:261)
    at e (gtm.js?id=GTM-AAAAAA:279:118)
    at gtm.js?id=GTM-AAAAAA:38:130
    at Array.<anonymous> (gtm.js?id=GTM-AAAAAA:280:475)
    at Object.execute (gtm.js?id=GTM-AAAAAA:280:231)
    at fs (gtm.js?id=GTM-AAAAAA:282:984)

which is this insertBefore part:

if ("SCRIPT" == String(h.nodeName).toUpperCase() && "text/gtmscript" == h.type) {
                            var n = H.createElement("script");
                            n.async = !1;
                            n.type = "text/javascript";
                            n.id = h.id;
                            n.text = h.text || h.textContent || h.innerHTML || "";
                            h.charset && (n.charset = h.charset);
                            var p = h.getAttribute("data-gtmsrc");
                            p && (n.src = p,
                            Yb(n, l));
                            d.insertBefore(n, null);
                            p || l()
                        } 

It's a simple event:

sendGTMData({ event: 'verification result code' });

I'm using it inside of useCallback in the custom hook, I'm honestly kinda struggle to find the solution, maybe you can point to the right direction?

Also in the debugger itself I can see that event is detected, plus additional event sent which is optimize.callback

Thank you

Update peerDependency to also support React 16.

This library is compatible with react 16 so we should not force the use of React 17 but rather support both as peerDependencies.

The required change is minimal, just inside pacakge.json

*** update this block ****

  "peerDependencies": {
    "react": ">=17"
  },

*** to this block ****

    "peerDependencies": {
    "react": "^16.13.1 || ^17.0.0"
  },

typescript error when upgrading to version v2.7.1

Disclaimer: this is my first issue report so I hope I can provide you the information that is needed ...

After the upgrade to version 2.7.1 I got an error when building my typescript application.

Type error: Argument of type '{ event: string; value: string; }' is not assignable to parameter of type 'ISendToGTM'.
Object literal may only specify known properties, and 'event' does not exist in type 'ISendToGTM'.

even if I use the demo-code it is not working:
const sendDataToGTM = useGTMDispatch(); sendDataToGTM({ event: 'awesomeButtonClicked', value: 'imAwesome' });

thank you very much, Tobias

[Bug]: Custom domain not working

Expected Behavior

Expecting the google tag manager to be https://custom.com/gtm.js when provided with a custom domain configuration

  const gtmParams: ISnippetsParams = {
     id: "GTM-ABCD",
+   customDomain: "https://custom.com",
  };


<GTMProvider state={gtmParams}>
   ...
</GTMProvider>

Current Behavior

Script url not being replaced with the cusotm domain =>https://www.googletagmanager.com/gtm.js?id=GTM-ABCD

Steps to Reproduce

  1. Wrap with @elgorditosalsero/react-gtm-hook Provider
  2. Configure a custom domain
  3. Inspect DOM

Disable hook conditionally

I would like to use this library in a larger project. On certain (dev) environments data should not be sent to GTM. Is it possible to disable GTM integration completely, e.g. by checking the value of an environment variable (if GTM_CONTAINER_ID is set then activate, else don't)? To my understanding, since useGTMDispatch is a hook it cannot be called conditionally. Is there any way to deactivate the dispatch anyway?

Recommended approach for sending Consent mode data

Hello! Thank you for this amazing library. I'd like to ask you whether there's any recommended approach how to send consent events using react-gtm-hook

  gtag('consent', 'update', {
    'ad_storage': 'granted',
    'analytics_storage': 'granted',
    'ad_user_data': 'granted',
    'ad_personalization': 'granted'
  });

thank you in advance ✌️

Support custom gtm.js file name

One of the main reason to move to server side GTM is to avoid being blocked by browsers and adblocks. For this reason it is possible to change the custom domain and the name of the file as well. For example tracking.mydomain.com/t.js. For now it is not possible to set the name of the file in this package.

How To Use Without Init'ing

Hi all, love the hook. We are using it with Gatsby and from v2.0.3 backwards, we were able to use it with gatsby-plugin-google-tag-manager which inlines the GTM inclusion script into the compiled HTML. After v2.0.3, the API changed (for the better it seems) but now it is impossible to use without the provider doing some initing. Would it be possible to have the new provider have an option to not include the GTM script?

Also, release v2.0.5 should have been a major version release, bumping it to v3.0.0. The reason I am saying this is that npm will silently upgrade bugfix versions like this, but won't if it's a major version release. When an API changes in a major way (in this case, the default export was removed and the provider names changed), it usually wise to bump up the major so it doesn't break builds.

Missing possibility to disable GTM connection

Background
We'd like to be able to conditionally disable the GTM data collection (e.g. Based on user consent or feature switch). However, there is no API for that. This is important due to GDPR legislation which requires explicit user approval before any data collection is happening.

Feature Request
Extend the GtmProvider with a prop enabled that prevents all communication with Google in case it is false

const Providers = ({ children }) => (
  <GTMProvider state={{
    id,
    environment,
    enabled=isGtmEnabled()
   }}> {children} </GTMProvider>
)

Workarounds we tried
As we couldn't find an API to disable GTM, we tried the following workarounds:

  • Not rendering the GTM provider => useGTMDispatch() throws an error due to missing provider

  • Conditionally not calling the useGTMDispatch() => Not possible due to React Hook limitations

  • Conditionally pass in empty GTM ID => Works but shows errors in the Console

  • Wrap the hook usage into an additional component and render it if the feature is enabled (see below) => Works without issues. Just is boilerplate that could be replaced with the enabled prop

      const _Page = () => (<div> This is a nice page </div>)
      const _PageWithGtm = () => { useGTMDispatch() ; return <Page /> }
      const Page = gtmIsEnabled() ? _PageWithGtm : _Page
    

How to trigger preview mode with the associated environment in the code?

Is it possible to open preview mode in GTM for the environment specified in the code?

Currently, I have to select the environment via GTM UI (see images) to debug the specific environment. The code doesn't seem to force the preview mode to the desired environment (eg. staging).

Initialization code:

  const { init, UseGTMHookProvider } = useGTM();
  
  useEffect(() => {
    init({
        id: process.env.REACT_APP_GTM as string,
        environment: {
          gtm_auth: '<GTM_AUTH_STRING>',
          gtm_preview: 'env-128',
        };,
      });
    }, []);

image
image

Thanks for the lib @elgorditosalsero πŸ™

Unable to install with NPM and react 17.0.2

Running npm with React 17.0.1 or above you get the following error.

Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"17.0.2" from the root project
npm ERR!   peer react@">=17" from @elgorditosalsero/[email protected]
npm ERR!   node_modules/@elgorditosalsero/react-gtm-hook
npm ERR!     @elgorditosalsero/react-gtm-hook@"2.0.7" from the root project
npm ERR!   29 more (@material-ui/core, react-dom, @material-ui/icons, ...)

Possibility to add multiple tag-ids

I would be great to add a possibility to supply multiple tag-ids. There's @tymate/react-gtm which does that, but the lib is written only in js

Question: how to send data on initialization?

Hi there,

I'm creating a custom consent modal that saves consents in a cookie.

So everything works fine when I'm using sendDataToGTM in a callback function. But on a refresh of the page I would like to immediately send the needed triggers (saved in a cookie) to GTM. When using sendDataToGTM in a useEffect it gives me the following error:

TypeError: Cannot read property 'push' of undefined

How should I set the initial dataLayer object to push events on init?

I tried passing a dataLayer array but that didn't work:

init({ id: "GTM-XXX", dataLayer: [{ event: "my-event"} ] })

Thanks in advance!

Thoughts about lib

Hey, pals, thanks for lib!
I've been using your project to work with GTM and I ran into bugs like twice mounting or cannot push to undefined (#16 #13)
So I was thinking, maybe there is a way to make it better.
Firstly, because the init function is called twice sometimes it causes some troubles, so what if we pass the initial state directly into the GTM Provider Params?

    <GTMProvider state={gtmParams}>
        <SomeComponentHere />
    </GTMProvider>

And secondly, why not separate sendGTMData (dispatchGTMEvent) hook and UseGTMHookProvider (GTMProvider)? So we would just initialize it only one time and after that, we would be able to set the data directly through the dispatchGTMEvent hook?

/**
 * Contexts
 */
export const GTMContext = createContext<ISnippetsParams | undefined>(initialState)
export const GTMContextDispatch = createContext<any | undefined>(undefined)

function dataReducer(state: ISnippetsParams, data: any) {
  sendToGTM({ data, dataLayerName: state?.dataLayerName! })
  return state
}

/**
 * The Google Tag Manager Provider
 */
function GTMProvider({ state, children }: GTMHookProviderProps): JSX.Element {
  const [store, dispatch] = useReducer(dataReducer, { ...initialState, ...state })

  useEffect(() => {
    initGTM({
      dataLayer: state.dataLayer,
      dataLayerName: state.dataLayerName,
      environment: state.environment,
      id: state.id
    })
  }, [state])

  return (
    <GTMContext.Provider value={store}>
      <GTMContextDispatch.Provider value={dispatch}>{children}</GTMContextDispatch.Provider>
    </GTMContext.Provider>
  )
}

function dispatchGTMEvent() {
  const context = useContext(GTMContextDispatch)
  if (context === undefined) {
    throw new Error('dispatchGTMEvent must be used within a GTMProvider')
  }

  return context
}

export { GTMProvider, dispatchGTMEvent }

Would be really pleased to hear your thoughts about it!

Question about the `send_to` attribute

It's not clear for me from the docs whether I should provide send_to attribute in the object passed to sendDataToGTM.

Original snippet I got from google:

gtag('event', 'conversion', {'send_to': 'my-gta-id/some-randomly-looking-string'});

So I guess my question is, should the code look like this:

sendDataToGTM({
  event: "conversion",
  send_to: "my-gta-id/some-randomly-looking-string",
  currency: order.currency,
  value: order.value,
});

or should I leave out send_to as it's not a custom attribute and the hook is already handling this:

sendDataToGTM({
  event: "conversion",
  currency: order.currency,
  value: order.value,
});

or maybe I should place send_to inside config object passed to the init function call?

react-hooks/exhaustive-deps will warn due to init not being listed as a dependency.

Using the example in the codebase, when I add eslint + react-hooks/exhaustive-deps rule and run a lint check
Will receive warning due to init not being listed as a dependency in useEffect:

11:5  warning  React Hook React.useEffect has a missing dependency: 'init'. 
Either include it or remove the dependency array  react-hooks/exhaustive-deps
  React.useEffect(
    () => init({ id: 'GTM-xxxx', dataLayer: { customInitValue: 'imCustom' }, dataLayerName: 'customDL' }),
    []
  )

If init is added as a dep, then a circular loop will occur.

I created a PR to see if that is the fix, #7

useGTMHook mounts children components twice

I don't know why but the <UseGTMHookProvider></UseGTMHookProvider> provider mounts children components two times:

  1. Mounts all children.
  2. Unmounts all children.
  3. Mounts them again.

I didn't expect the behavior to happen. Is it fine? I attached the code below.

Here is the code:

// index.js
import useGTM from 'https://cdn.skypack.dev/@elgorditosalsero/[email protected]';
import React, { useEffect } from 'https://cdn.skypack.dev/[email protected]';
import ReactDOM from 'https://cdn.skypack.dev/[email protected]';

const App = () => {
  const { init, UseGTMHookProvider } = useGTM()
  const gtmParams = {
    id: 'GTM-ID',
    dataLayerName: 'customDataLayerName'
  }
 
  useEffect(() => init(gtmParams), [])
 
  return (
    <UseGTMHookProvider>
      <MyComponent />
    </UseGTMHookProvider>
  )
}

const MyComponent = () => {

  useEffect(() => {
    alert('I was mounted');
    console.log('I was mounted');

    return () => {
      console.log('I was unmounted');
    }
  }, [])
  
  return (<div>
    My awesome app;
  </div>);
}

const ROOT_MOUNT = document.querySelector('#app');
ReactDOM.render(<App />, ROOT_MOUNT)
<!-- index.html -->
<div id="app"></div>

Here is the same code but in the code pen: https://codepen.io/vduding/pen/JjRjmLy

Thank you!

How to clean dataLayer when page changes on Next.js ? Avoid persistance of data in dataLayer

Hello,

I use this repo for few weeks now and it works fine and very cool, thank you for that.
I just would ask a question about if it's possible to reset dataLayer when page changes.

For example :

Code

I have this in my _app.tsx

const gtmParams = {
    id: process.env.NEXT_PUBLIC_GOOGLE_GTM_ID as string,
    dataLayerName: "dataLayer",
    dataLayer: {},
};

<GTMProvider state={gtmParams}>
    <Component {...pageProps} />
</GTMProvider>

And this, in my index.tsx

  const sendDataToGTM = useGTMDispatch()
  const handleClick = () => sendDataToGTM({ 
      ecommerce: {
        add: {
          products: [
            {
              name: space.label,
            },
          ],
        },
      },
})
  
  <button onClick={handleClick}>My Awesome Button</button>

And this, in my contact.tsx

  const sendDataToGTM = useGTMDispatch()
  const handleClick = () => sendDataToGTM({ 
      ecommerce: {
        detail: {
          products: [
            {
              id: space.id,
            },
          ],
        },
      },
})
  
  <button onClick={handleClick}>My Awesome Button</button>

Workflow

  1. So I go to my index then click on my button
  2. Then go the my contact page then click on my button

Result

The result of that is

      ecommerce: {
        add: {
          products: [
            {
              name: "Space 1",
            },
          ],
        },
      },
      ecommerce: {
        add: {
          products: [
            {
              name: "Space 1",
            },
          ],
        },
        detail: {
          products: [
            {
              id: "1',
            },
          ],
        },
      },

instead :

    ecommerce: {
        detail: {
          products: [
            {
              id: "1',
            },
          ],
        },
      },

I would like to not merge previous state with the new one.

Is there a way to do that please ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.