{"id":1496,"date":"2018-07-18T15:55:10","date_gmt":"2018-07-18T13:55:10","guid":{"rendered":"https:\/\/blog.thecodecampus.de\/?p=1496"},"modified":"2023-12-20T20:01:49","modified_gmt":"2023-12-20T19:01:49","slug":"angular-preserving-query-params-google-adwords","status":"publish","type":"post","link":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/","title":{"rendered":"Angular, Preserving Query Params and Google AdWords"},"content":{"rendered":"<h2>&#8230;\u00a0and how all this leads to an incorrect source of traffic in Google Analytics and incorrect conversion attribution.<\/h2>\n<p>&nbsp;<\/p>\n<p>The situation is as follows:<br \/>\nOn www.thecodecampus.de we run an Angular 6 page. We advertise our product with Google AdWords. If a visitor comes via Google AdWords, the URL is appended with a glcid and several campaign parameters as query params. This data is important for tracking, as Google Analytics determines to which source a conversion\/visit is to be attributed.<\/p>\n<p>Without this information, we cannot determine (in Google Analytics) whether a visit or booking was made through Google AdWords or any other source.\u00a0The data is accordingly important to us.\u00a0Unfortunately, Angular is configured by default to remove any query parameters when navigating.<\/p>\n<p>This means that the GCLID is still present on the initial page, but if the user clicks on another route within the Angular application, the URL is removed and the data is lost.<\/p>\n<p>In order to fix this problem you can either use\u00a0<code>queryParamsHandling<\/code> on <strong>each<\/strong> router.navigate() call and on <strong>each\u00a0<\/strong>routerLink.\u00a0But that is not practical.\u00a0Another option is to use a directive that updates each routerLink accordingly with the current query parameters as shown <a href=\"https:\/\/github.com\/angular\/angular\/issues\/12664#issuecomment-356339887\">here<\/a>. But this solution doesn&#8217;t cover router.navigate() calls from component classes.<\/p>\n<pre class=\"lang:default decode:true\">@Directive({\r\n  selector: 'a[routerLink]'\r\n})\r\nexport class PreserveQueryParamsDirective {\r\n  constructor(private link: RouterLinkWithHref, private route: ActivatedRoute ) {\r\n    this.route.queryParamMap.subscribe(queryParams =&gt; {\r\n      this.link.queryParams = Object.assign({}, this.route.snapshot.queryParams);\r\n    });\r\n  }\r\n}<\/pre>\n<p>Another solution is to use guards until the <a href=\"https:\/\/github.com\/angular\/angular\/issues\/12664#issue-186844950\">issue in the official repository<\/a> is resolved. But this requires you to set\u00a0runGuardsAndResolvers for the guard to always and to cancel all navigation requests and is a very hacky solution:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"lang:default decode:true \">import {Injectable} from '@angular\/core';\r\nimport {ActivatedRouteSnapshot, CanDeactivate, Router, RouterStateSnapshot} from '@angular\/router';\r\nimport {Observable} from 'rxjs\/Observable';\r\nimport {ParamMap} from '@angular\/router\/src\/shared';\r\n\r\n@Injectable()\r\nexport class QueryGuard implements CanDeactivate&lt;any&gt; {\r\n\r\n\r\n  constructor(private router: Router) {\r\n  }\r\n\r\n\r\n  \/**\r\n   * Well, why do I exist?\r\n   *\r\n   * Angular strips query params during route change and we lost a URL parameter that is required for Google AdWords.\r\n   * Therefore we prevent any route change where the currentState has query params and the nextState does not. Then\r\n   * cancelling the original navigation attempt and starting a new one with the queryParamsHandling set to preserve.\r\n   *\r\n   * Currently I am only slightly tested and may break existing logic like route rejection, data and so on.\r\n   * *\/\r\n  canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable&lt;boolean&gt; | Promise&lt;boolean&gt; | boolean {\r\n    \/\/ if there are no query params on the current route - do nothing.\r\n    if (currentRoute.root.queryParamMap.keys.length === 0) {\r\n      return true;\r\n    }\r\n\r\n    if (nextState) {\r\n      \/\/ if (nextState.root.queryParamMap.has(currentState.root.queryParamMap.keys[0])) {\r\n      if (this.comapreParmMaps(currentState.root.queryParamMap, nextState.root.queryParamMap)) {\r\n        \/\/ check only if the first key is present - then the guard has already done\r\n        \/\/ his job and we return true in order to avoid endless loop.\r\n        return true;\r\n      } else {\r\n        \/\/ Apparently the query params need to be added:\r\n        this.router.navigate([nextState.url], {\r\n          preserveFragment: true,\r\n          queryParamsHandling: 'preserve'\r\n        });\r\n\r\n        \/\/ Cancel initial navigation attempt\r\n        return false;\r\n      }\r\n    }\r\n  }\r\n\r\n\r\n  \/**\r\n   * Compares two routes and returns true if all params exist in both routes*\/\r\n  private comapreParmMaps(mapA: ParamMap, mapB: ParamMap): boolean {\r\n    return mapA.keys\r\n      .map(key =&gt; mapB.has(key))\r\n      .every(it =&gt; it);\r\n  }\r\n\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8230;\u00a0and how all this leads to an incorrect source of traffic in Google Analytics and incorrect conversion attribution. &nbsp; The situation is as follows: On www.thecodecampus.de we run an Angular 6 page. We advertise our product with Google AdWords. If a visitor comes via Google AdWords, the URL is appended with a glcid and several [&#8230;]<br \/><a class=\"meta-big\" href=\"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/\"> READ MORE<\/a><\/p>\n","protected":false},"author":29,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[73,2,92],"tags":[],"class_list":["post-1496","post","type-post","status-publish","format-standard","hentry","category-angular","category-javascript","category-others"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Angular, Preserving Query Params and Google AdWords - Web Development Blog<\/title>\n<meta name=\"description\" content=\"Elevate AdWords integration. Preserve Angular query params effortlessly, optimize tracking precision. Boost campaigns seamlessly. Try it now!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Angular, Preserving Query Params and Google AdWords - Web Development Blog\" \/>\n<meta property=\"og:description\" content=\"Elevate AdWords integration. Preserve Angular query params effortlessly, optimize tracking precision. Boost campaigns seamlessly. Try it now!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Development tips and tricks - theCodeCampus Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-07-18T13:55:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-20T19:01:49+00:00\" \/>\n<meta name=\"author\" content=\"theCodeCampus\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"theCodeCampus\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/\"},\"author\":{\"name\":\"theCodeCampus\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#\\\/schema\\\/person\\\/276bbda2f8da73154f22fb652201cfbc\"},\"headline\":\"Angular, Preserving Query Params and Google AdWords\",\"datePublished\":\"2018-07-18T13:55:10+00:00\",\"dateModified\":\"2023-12-20T19:01:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/\"},\"wordCount\":261,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#organization\"},\"articleSection\":[\"Angular\",\"JavaScript\",\"Others\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/\",\"url\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/\",\"name\":\"Angular, Preserving Query Params and Google AdWords - Web Development Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#website\"},\"datePublished\":\"2018-07-18T13:55:10+00:00\",\"dateModified\":\"2023-12-20T19:01:49+00:00\",\"description\":\"Elevate AdWords integration. Preserve Angular query params effortlessly, optimize tracking precision. Boost campaigns seamlessly. Try it now!\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/angular-preserving-query-params-google-adwords\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Angular, Preserving Query Params and Google AdWords\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/\",\"name\":\"Web Development tips and tricks - theCodeCampus Blog\",\"description\":\"Tips, tricks, and experiences about developing web and mobile applications with Angular, TypeScript, and Testing.\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#organization\",\"name\":\"theCodeCampus\",\"url\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/TCC-Logo-Bildmarke-quadratisch.jpg\",\"contentUrl\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/TCC-Logo-Bildmarke-quadratisch.jpg\",\"width\":156,\"height\":156,\"caption\":\"theCodeCampus\"},\"image\":{\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/#\\\/schema\\\/person\\\/276bbda2f8da73154f22fb652201cfbc\",\"name\":\"theCodeCampus\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/TCC-Logo-Bildmarke-quadratisch-96x96.jpg\",\"url\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/TCC-Logo-Bildmarke-quadratisch-96x96.jpg\",\"contentUrl\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/TCC-Logo-Bildmarke-quadratisch-96x96.jpg\",\"caption\":\"theCodeCampus\"},\"description\":\"Our knowledge is not simply gained through reading - it is trained, tested and constantly being expanded. Because first and foremost, we are all developers at W11K. The know-how that we acquire here as developers, consultants and information architects flows immediately into our training courses and articles for theCodeCampus.\",\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/showcase\\\/thecodecampus\\\/\"],\"url\":\"https:\\\/\\\/www.thecodecampus.de\\\/blog\\\/author\\\/admin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Angular, Preserving Query Params and Google AdWords - Web Development Blog","description":"Elevate AdWords integration. Preserve Angular query params effortlessly, optimize tracking precision. Boost campaigns seamlessly. Try it now!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/","og_locale":"en_US","og_type":"article","og_title":"Angular, Preserving Query Params and Google AdWords - Web Development Blog","og_description":"Elevate AdWords integration. Preserve Angular query params effortlessly, optimize tracking precision. Boost campaigns seamlessly. Try it now!","og_url":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/","og_site_name":"Web Development tips and tricks - theCodeCampus Blog","article_published_time":"2018-07-18T13:55:10+00:00","article_modified_time":"2023-12-20T19:01:49+00:00","author":"theCodeCampus","twitter_card":"summary_large_image","twitter_misc":{"Written by":"theCodeCampus","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/#article","isPartOf":{"@id":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/"},"author":{"name":"theCodeCampus","@id":"https:\/\/www.thecodecampus.de\/blog\/#\/schema\/person\/276bbda2f8da73154f22fb652201cfbc"},"headline":"Angular, Preserving Query Params and Google AdWords","datePublished":"2018-07-18T13:55:10+00:00","dateModified":"2023-12-20T19:01:49+00:00","mainEntityOfPage":{"@id":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/"},"wordCount":261,"commentCount":0,"publisher":{"@id":"https:\/\/www.thecodecampus.de\/blog\/#organization"},"articleSection":["Angular","JavaScript","Others"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/","url":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/","name":"Angular, Preserving Query Params and Google AdWords - Web Development Blog","isPartOf":{"@id":"https:\/\/www.thecodecampus.de\/blog\/#website"},"datePublished":"2018-07-18T13:55:10+00:00","dateModified":"2023-12-20T19:01:49+00:00","description":"Elevate AdWords integration. Preserve Angular query params effortlessly, optimize tracking precision. Boost campaigns seamlessly. Try it now!","breadcrumb":{"@id":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.thecodecampus.de\/blog\/angular-preserving-query-params-google-adwords\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.thecodecampus.de\/blog\/"},{"@type":"ListItem","position":2,"name":"Angular, Preserving Query Params and Google AdWords"}]},{"@type":"WebSite","@id":"https:\/\/www.thecodecampus.de\/blog\/#website","url":"https:\/\/www.thecodecampus.de\/blog\/","name":"Web Development tips and tricks - theCodeCampus Blog","description":"Tips, tricks, and experiences about developing web and mobile applications with Angular, TypeScript, and Testing.","publisher":{"@id":"https:\/\/www.thecodecampus.de\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.thecodecampus.de\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.thecodecampus.de\/blog\/#organization","name":"theCodeCampus","url":"https:\/\/www.thecodecampus.de\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.thecodecampus.de\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.thecodecampus.de\/blog\/wp-content\/uploads\/2024\/01\/TCC-Logo-Bildmarke-quadratisch.jpg","contentUrl":"https:\/\/www.thecodecampus.de\/blog\/wp-content\/uploads\/2024\/01\/TCC-Logo-Bildmarke-quadratisch.jpg","width":156,"height":156,"caption":"theCodeCampus"},"image":{"@id":"https:\/\/www.thecodecampus.de\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.thecodecampus.de\/blog\/#\/schema\/person\/276bbda2f8da73154f22fb652201cfbc","name":"theCodeCampus","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.thecodecampus.de\/blog\/wp-content\/uploads\/2024\/01\/TCC-Logo-Bildmarke-quadratisch-96x96.jpg","url":"https:\/\/www.thecodecampus.de\/blog\/wp-content\/uploads\/2024\/01\/TCC-Logo-Bildmarke-quadratisch-96x96.jpg","contentUrl":"https:\/\/www.thecodecampus.de\/blog\/wp-content\/uploads\/2024\/01\/TCC-Logo-Bildmarke-quadratisch-96x96.jpg","caption":"theCodeCampus"},"description":"Our knowledge is not simply gained through reading - it is trained, tested and constantly being expanded. Because first and foremost, we are all developers at W11K. The know-how that we acquire here as developers, consultants and information architects flows immediately into our training courses and articles for theCodeCampus.","sameAs":["https:\/\/www.linkedin.com\/showcase\/thecodecampus\/"],"url":"https:\/\/www.thecodecampus.de\/blog\/author\/admin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/posts\/1496","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/comments?post=1496"}],"version-history":[{"count":8,"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/posts\/1496\/revisions"}],"predecessor-version":[{"id":1504,"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/posts\/1496\/revisions\/1504"}],"wp:attachment":[{"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/media?parent=1496"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/categories?post=1496"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thecodecampus.de\/blog\/wp-json\/wp\/v2\/tags?post=1496"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}