Thanks @Ionaru I'll have a look.
Hi I have the same question. The problem I have is when doing ng build the script code in the index is not included.
I also created this question for the same reason
http://stackoverflow.com/questions/42388641/how-to-include-google-analytics-in-angular-cli-application
Any updates?
Thanks in advance
Be sure to put the script code outside the <app-root>
tags, because anything inside those tags gets replaced by the Angular application.
thanks @Ionaru including the tag in the HEAD is working for me.
The initial question has not really been answered here, I'm also wondering how that could be solved.
Consider if you add f.e. Google Tag Manager or Google Analytics integration to your site, and you have different workspaces (or properties in GA) setup for your different environments. The appropriate script&noscript tags area added to the head
and body
of index.html
but the tracking-id differs between environments.
Best case scenario would of course be if ng build --env=staging/prod
would produce two different index.html
s where the tracking id has been set via some dynamic variable.
Until there is support for that, what would be a decent workaround? I guess checking environment variables on server side and serve two different index.html files would be one option. Am using a simple static files server currently though so curious to whether there is some more elegant way of solving this as part of the build process instead
You could try adding some code to add different Analytics properties when running in different environments. Like this:
import { environment } from './environments/environment';
if (environment.production) {
document.write('<script type="text/javascript">// ProductionAnalyticsCodeHere</script>');
} else if (environment.staging) {
document.write('<script type="text/javascript">// StagingAnalyticsCodeHere</script>');
}
If you do this in main.ts, then the code gets added to the webpage as early as possible.
It is also possible to put document.write()
directly into environment.prod.ts, that might be neater.
The CLI doesn't provide any such functionality, no. This was requested in https://github.com/angular/angular-cli/issues/4288.
In past projects what I did was having Angular services that correctly run these scripts, and use the correct analytics token provided inside the environment files.
@Ionaru has provided some pretty good solutions though, cheers!
Wont this fail tests? (using document?)
@filipesilva I don't think it's a 'pretty good solution', it's mostly a workaround which fortunately works fine
@Ionaru solution is the best workaround I found so far.
import { enableProdMode } from '@angular/core';
import { env } from './environments/environment';
if (env.production) {
// add Google Analytics script to <head>
const script = document.createElement('script');
script.innerHTML = `(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;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');`;
document.head.appendChild(script);
// disable Angular development mode
enableProdMode();
}
Adding the <noscript>
section dynamicaly when bootstraping Angular makes no sense as it needs javascript to bootstrap but the tag is to track disabled javascript users.
So be ready to throw away non javascript users tracking if you want to use that workaround OR you could keep the <noscript>
section in the body of the index.html
file but you'll get tracking for non javascript user from every environments mixed together.
<body>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
...
</body>
Solution provided here will not work in Angular Universal, due to direct access to the document
object.
You should instead use the DOCUMENT
object exported @angular/common
. This way I could set a dynamic tagManager id for each environment.
So in the AppComponent:
import { DOCUMENT } from '@angular/common';
...
public constructor(
@Inject(DOCUMENT) private doc: any
) {
Then I used a private method called on ngOnInit()
to insert the tag in <head>
:
private setGTagManager() {
const s = this.doc.createElement('script');
s.type = 'text/javascript';
s.innerHTML = '(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;f.parentNode.insertBefore(j,f);})'
+ '(window,document,\'script\',\'dataLayer\',\'' + environment.tagManagerId + '\');';
const head = this.doc.getElementsByTagName('head')[0];
head.appendChild(s);
}
As you can see I imported the tagManager ID from the global environment
, so I could use different ones for dev and production.
Also if you use Angular Universal be sure to run this code only on the server, or it will import the script twice in the browser.
Hope this helps.
For analytics you can use multiple index.html pages (like index.prod.html, etc) and fileReplacements (https://github.com/angular/angular-cli/wiki/stories-application-environments).
It works for html files starting from Angular CLI 6.1.0-beta.2.
@pbazurin-softheme how to change between different index.html files with configurations, any example or snippets? I tried with changing "options" but it didnt worked.
{
...
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
},
{
"replace": "src/index.html",
"with": "src/index.prod.html"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"staging": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
},
{
"replace": "src/index.html",
"with": "src/index.staging.html"
}
],
...
}
@ramk-bharathi This is my angular.json
.
You can add as many additional build configurations as you want
@pbazurin-softheme it seems like your snippet would work for my needs (adding tags instead of
Most helpful comment
You could try adding some code to add different Analytics properties when running in different environments. Like this:
If you do this in main.ts, then the code gets added to the webpage as early as possible.
It is also possible to put
document.write()
directly into environment.prod.ts, that might be neater.