I'm working on an Angular application and setting the SEO tags (like title, description, and meta tags) in the standard way. When I monitor the <head> section using a MutationObserver, I see that the tags are being re-applied on the client side. This is the normal behavior for an Angular application using Server-Side Rendering (SSR): first, the SSR output is delivered, and then the Client-Side Rendering (CSR) kicks in, running functions like ngOnInit, which often re-apply or update the meta tags. Our SEO Team believes this re-rendering is causing problems with Google indexing . My initial attempt was to ensure the tags were only set during SSR. However, this causes an issue with subsequent client-side navigations (routing within the app) because the tags are not updated after the initial load. So, I decided on a hybrid approach: I want to programmatically prevent the client-side re-application of the SEO tags **if it's the initial page load (i.e., not a subsequent client-side navigation). I tried implementing this logic as follows:** this._router.events .pipe( filter(event => event instanceof NavigationEnd), filter((event: NavigationEnd) => !event.urlAfterRedirects.startsWith('/assets') ), filter((event: NavigationEnd) => !event.urlAfterRedirects.startsWith('/blog') ), filter((event: NavigationEnd) => !event.urlAfterRedirects.match(/(robots\.txt|sitemap\.xml)/i) ), map((event: NavigationEnd) => { let route = this._activatedRoute.firstChild; let child = route; while (child) { if (child.firstChild) { child = child.firstChild; route = child; } else { child = null; } } return { route, event }; }), switchMap(({ route, event }) => route.data.pipe(map(data => ({ data, event })))) ) .subscribe(({ data, event }) => { if (this._transferStateService.tryGet<number>(TRANSFER_STATE_KEY.NAVIGATION_ID, 0) != event.id) { this._seoService.set(data?.title || DEFAULT_EMPTY, data?.description || DEFAULT_EMPTY, data?.canonical || DEFAULT_EMPTY); } if (PlatformInfo.IsPlatformServer) { this._transferStateService.set(TRANSFER_STATE_KEY.NAVIGATION_ID, event.id); } if (PlatformInfo.IsPlatformBrowser) { scrollTop(); window?.ChatModule?.sendLocationInfo(event.url); } }) I have an algorithm idea for conditional client-side rendering (CSR) based on navigation history, particularly focusing on the navigationId. The core assumption is: In Server-Side Rendering (SSR), we assume the navigationId is always 1. In the initial CSR load, we also assume the navigationId is 1. The logic: If the current navigationId is 1, there's no need to execute the specific CSR code/component rendering. This component should only be rendered when a second navigation (or subsequent navigation) occurs on the client side, meaning navigationId is greater than 1. My questions are: Is this approach correct and robust? Are there alternative or better methods to achieve this conditional rendering based on initial load vs. subsequent navigation? The reason I implemented blow conditional logic is because I've observed that faulty navigations/routes (e.g., failed navigations or errors during routing path:'**') fire the NavigationEnd event. How can I prevent this specific CSR code from running on those faulty/failed router events? filter((event: NavigationEnd) => !event.urlAfterRedirects.startsWith('/assets') //svg-icon ), filter((event: NavigationEnd) => !event.urlAfterRedirects.startsWith('/blog') // virtual-domain ), filter((event: NavigationEnd) => !event.urlAfterRedirects.match(/(robots\.txt|sitemap\.xml)/i) // dynamic create ), Continue reading...