Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to add props to script and noscript tags #50

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 41 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[![npm downloads](https://img.shields.io/npm/dm/react-gtm-module.svg?style=flat-square)](https://www.npmjs.com/package/react-gtm-module)

# react-gtm-module

### React Google Tag Manager Module

This is a Javascript module to [React](https://facebook.github.io/react/) based apps that implement Google Tag Manager. It is designed to use [GTM](https://developers.google.com/tag-manager/quickstart) snippet.
Expand Down Expand Up @@ -71,7 +72,6 @@ ReactDOM.render(<Router routes={routes} />, app)

```


### Multiple dataLayer example:

If you need send multiple custom dataLayer you can initialize GTM Module on different components sending different dataLayers
Expand Down Expand Up @@ -134,6 +134,33 @@ export default Home

```

### Adding properties to GTM script and noscript tags

You can also add attributes to your script and noscript tags,
if you need to do so for accessibility or security.

```js
import React from 'react'
import ReactDOM from 'react-dom'
import Router from 'react-router'
import routes from './routes'

...
import TagManager from 'react-gtm-module'

const tagManagerArgs = {
gtmId: 'GTM-000000',
scriptProps: { nonce: 'abcdef' },
noscriptProps: { 'aria-hidden': 'true' }
}

TagManager.initialize(tagManagerArgs)
...

const app = document.getElementById('app')
ReactDOM.render(<Router routes={routes} />, app)

```

## Events

Expand Down Expand Up @@ -188,27 +215,26 @@ TagManager.initialize(tagManagerArgs)
```

##### How can I find auth and preview?

Go to Google Tag Manager -> ADMIN -> Environments -> Actions -> Get Snippet.
Look for gtm_auth and gtm_preview

##### Don't know to use GTM environments?
- https://support.google.com/tagmanager/answer/6311518
- https://www.simoahava.com/analytics/better-qa-with-google-tag-manager-environments/


##### Don't know to use GTM environments?

|Value|Type|Required|Notes|
|------|-----|-----|-----|
|gtmId| `String`| Yes | GTM id, must be something like `GTM-000000`.|
|dataLayer| `Object`| No | Object that contains all of the information that you want to pass to Google Tag Manager.|
|dataLayerName| `String`| No | Custom name for dataLayer object.|
|events| `Object`| No | Additional events such as 'gtm.start': new Date().getTime(),event:'gtm.js'.|
|auth| `String` | No | used to set environments. |
|preview| `String` | No | used to set environments, something like `env-00`. |
- https://support.google.com/tagmanager/answer/6311518
- https://www.simoahava.com/analytics/better-qa-with-google-tag-manager-environments/

| Value | Type | Required | Notes |
| ------------- | -------- | -------- | ---------------------------------------------------------------------------------------- |
| gtmId | `String` | Yes | GTM id, must be something like `GTM-000000`. |
| dataLayer | `Object` | No | Object that contains all of the information that you want to pass to Google Tag Manager. |
| dataLayerName | `String` | No | Custom name for dataLayer object. |
| events | `Object` | No | Additional events such as 'gtm.start': new Date().getTime(),event:'gtm.js'. |
| auth | `String` | No | used to set environments. |
| preview | `String` | No | used to set environments, something like `env-00`. |

### Note:

- Disabling javascript in the browser can prevent the correct operation of this library if React is only being rendered on the client side.

- Before implementing GTM in your application ensure that you have at least one published container, otherwise Google Tag Manager snippet will return 404.
- Before implementing GTM in your application ensure that you have at least one published container, otherwise Google Tag Manager snippet will return 404.
40 changes: 27 additions & 13 deletions dist/TagManager.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
'use strict';
"use strict";

var _Snippets = require('./Snippets');
var _Snippets = require("./Snippets");

var _Snippets2 = _interopRequireDefault(_Snippets);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var TagManager = {
dataScript: function dataScript(dataLayer) {
var script = document.createElement('script');
var script = document.createElement("script");
script.innerHTML = dataLayer;
return script;
},
gtm: function gtm(args) {
var snippets = _Snippets2.default.tags(args);

var noScript = function noScript() {
var noscript = document.createElement('noscript');
var noScript = function noScript(props) {
var noscript = document.createElement("noscript");
if (props) {
Object.keys(props).forEach(function (pk) {
noscript.setAttribute(pk, props[pk]);
});
}
noscript.innerHTML = snippets.iframe;
return noscript;
};

var script = function script() {
var script = document.createElement('script');
var script = function script(props) {
var script = document.createElement("script");
if (props) {
Object.keys(props).forEach(function (pk) {
script.setAttribute(pk, props[pk]);
});
}
script.innerHTML = snippets.script;
return script;
};
Expand All @@ -41,11 +51,15 @@ var TagManager = {
events = _ref$events === undefined ? {} : _ref$events,
dataLayer = _ref.dataLayer,
_ref$dataLayerName = _ref.dataLayerName,
dataLayerName = _ref$dataLayerName === undefined ? 'dataLayer' : _ref$dataLayerName,
dataLayerName = _ref$dataLayerName === undefined ? "dataLayer" : _ref$dataLayerName,
_ref$auth = _ref.auth,
auth = _ref$auth === undefined ? '' : _ref$auth,
auth = _ref$auth === undefined ? "" : _ref$auth,
_ref$preview = _ref.preview,
preview = _ref$preview === undefined ? '' : _ref$preview;
preview = _ref$preview === undefined ? "" : _ref$preview,
_ref$scriptProps = _ref.scriptProps,
scriptProps = _ref$scriptProps === undefined ? {} : _ref$scriptProps,
_ref$noscriptProps = _ref.noscriptProps,
noscriptProps = _ref$noscriptProps === undefined ? {} : _ref$noscriptProps;

var gtm = this.gtm({
id: gtmId,
Expand All @@ -56,13 +70,13 @@ var TagManager = {
preview: preview
});
if (dataLayer) document.head.appendChild(gtm.dataScript);
document.head.insertBefore(gtm.script(), document.head.childNodes[0]);
document.body.insertBefore(gtm.noScript(), document.body.childNodes[0]);
document.head.insertBefore(gtm.script(scriptProps), document.head.childNodes[0]);
document.body.insertBefore(gtm.noScript(noscriptProps), document.body.childNodes[0]);
},
dataLayer: function dataLayer(_ref2) {
var _dataLayer = _ref2.dataLayer,
_ref2$dataLayerName = _ref2.dataLayerName,
dataLayerName = _ref2$dataLayerName === undefined ? 'dataLayer' : _ref2$dataLayerName;
dataLayerName = _ref2$dataLayerName === undefined ? "dataLayer" : _ref2$dataLayerName;

if (window[dataLayerName]) return window[dataLayerName].push(_dataLayer);
var snippets = _Snippets2.default.dataLayer(_dataLayer, dataLayerName);
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

87 changes: 56 additions & 31 deletions src/TagManager.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,78 @@
import Snippets from './Snippets'
import Snippets from "./Snippets";

const TagManager = {
dataScript: function (dataLayer) {
const script = document.createElement('script')
script.innerHTML = dataLayer
return script
dataScript: function(dataLayer) {
const script = document.createElement("script");
script.innerHTML = dataLayer;
return script;
},
gtm: function (args) {
const snippets = Snippets.tags(args)
gtm: function(args) {
const snippets = Snippets.tags(args);

const noScript = () => {
const noscript = document.createElement('noscript')
noscript.innerHTML = snippets.iframe
return noscript
}
const noScript = props => {
const noscript = document.createElement("noscript");
if (props) {
Object.keys(props).forEach(pk => {
noscript.setAttribute(pk, props[pk]);
});
}
noscript.innerHTML = snippets.iframe;
return noscript;
};

const script = () => {
const script = document.createElement('script')
script.innerHTML = snippets.script
return script
}
const script = props => {
const script = document.createElement("script");
if (props) {
Object.keys(props).forEach(pk => {
script.setAttribute(pk, props[pk]);
});
}
script.innerHTML = snippets.script;
return script;
};

const dataScript = this.dataScript(snippets.dataLayerVar)
const dataScript = this.dataScript(snippets.dataLayerVar);

return {
noScript,
script,
dataScript
}
};
},
initialize: function ({ gtmId, events = {}, dataLayer, dataLayerName = 'dataLayer', auth = '', preview = '' }) {
initialize: function({
gtmId,
events = {},
dataLayer,
dataLayerName = "dataLayer",
auth = "",
preview = "",
scriptProps = {},
noscriptProps = {}
}) {
const gtm = this.gtm({
id: gtmId,
events: events,
dataLayer: dataLayer || undefined,
dataLayerName: dataLayerName,
auth,
preview
})
if (dataLayer) document.head.appendChild(gtm.dataScript)
document.head.insertBefore(gtm.script(), document.head.childNodes[0])
document.body.insertBefore(gtm.noScript(), document.body.childNodes[0])
});
if (dataLayer) document.head.appendChild(gtm.dataScript);
document.head.insertBefore(
gtm.script(scriptProps),
document.head.childNodes[0]
);
document.body.insertBefore(
gtm.noScript(noscriptProps),
document.body.childNodes[0]
);
},
dataLayer: function ({dataLayer, dataLayerName = 'dataLayer'}) {
if (window[dataLayerName]) return window[dataLayerName].push(dataLayer)
const snippets = Snippets.dataLayer(dataLayer, dataLayerName)
const dataScript = this.dataScript(snippets)
document.head.appendChild(dataScript)
dataLayer: function({ dataLayer, dataLayerName = "dataLayer" }) {
if (window[dataLayerName]) return window[dataLayerName].push(dataLayer);
const snippets = Snippets.dataLayer(dataLayer, dataLayerName);
const dataScript = this.dataScript(snippets);
document.head.appendChild(dataScript);
}
}
};

module.exports = TagManager
module.exports = TagManager;
45 changes: 30 additions & 15 deletions src/__tests__/TagManager.spec.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
import React from 'react'
import TagManager from '../TagManager'
import React from "react";
import TagManager from "../TagManager";

describe('TagManager', () => {
it('should render tagmanager', () => {
TagManager.initialize({gtmId: 'GTM-000000'})
expect(window.dataLayer).toHaveLength(1)
})
describe("TagManager", () => {
it("should render tagmanager", () => {
TagManager.initialize({ gtmId: "GTM-000000" });
expect(window.dataLayer).toHaveLength(1);
});

it('should render datalayer', () => {
it("should render datalayer", () => {
const gtmArgs = {
gtmId: 'GTM-000000',
gtmId: "GTM-000000",
dataLayer: {
userInfo: 'userInfo'
userInfo: "userInfo"
}
}
TagManager.initialize(gtmArgs)
expect(window.dataLayer).toHaveLength(1)
})
})
};
TagManager.initialize(gtmArgs);
expect(window.dataLayer).toHaveLength(1);
});

it("should render script and noscript props when provided", () => {
TagManager.initialize({
gtmId: "GTM-000000",
scriptProps: { "data-foo": "bar" },
noscriptProps: { "data-foo": "baz" }
});
expect(window.dataLayer).toHaveLength(1);
expect(
window.document.querySelector('script[data-foo="bar"]')
).toBeDefined();
expect(
window.document.querySelector('noscript[data-foo="baz"]')
).toBeDefined();
});
});