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

Angular SSR not updating dynamic meta tags and content received from API #53711

Closed
leandrotassi opened this issue Dec 27, 2023 · 40 comments
Closed
Labels
area: server Issues related to server-side rendering needs reproduction This issue needs a reproduction in order for the team to investigate further
Milestone

Comments

@leandrotassi
Copy link

Which @angular/* package(s) are the source of the bug?

platform-server

Is this a regression?

Yes

Description

I'm working on an Angular SSR application and I'm facing a problem when updating Open Graph meta tags after receiving content from the API, as in another component that updates directly (without consuming the API) there is no problem.
Although when viewing elements in the page source code, all meta tags are updated. The problem is that when sharing, they don't show the updated meta tags.

After I updated to Angular 17 it stopped working, but I'm not sure, because it was in some version that it stopped working and I had made several Angular updates.

Please provide a link to a minimal reproduction of the bug

Unfortunately, I have no way of reproducing the error for you to analyze, as the error only occurs in production and cannot be reproduced in stackblitz.

Please provide the exception or error you saw

ngOnInit(): void {
  this.metadataService.removeTags(); // Removing existing tags

  // ... (other initialization code)

  if (this.reNumber.test(sumarioId) && Number(sumarioId) > 0) {
    this.artigoService.GeArticle(sumarioId).subscribe({
      next: (res: Artigo) => {
        if (res != null) {
          this.artigo = res;
          // ... (other processing)
          this.updateMetaDataArticle();
        }
      },
      // ... (error and complete handlers)
    });
  }
}


private updateMetaDataArticle(): void {
  let meta: PageMetaData = new PageMetaData();
  // ... (other meta data setup)

  meta.title = this.artigo?.manuscriptTitle as string;
  meta.description = this.artigo?.abstract as string;

  if (this.metadataService) {
    this.metadataService.updateMetadata(meta);
    // ... (other actions)
  }
}

public updateMetadata(metadata: Partial<PageMetaData>): void {
  // ... (other metadata updates)
  this.metaTagService.addTags([
    { property: 'og:title', content: metadata.title },
    { property: 'og:description', content: metadata.description }
    // ... (other meta tags)
  ], false);
}

public removeTags(): void {
  if (!this._platform.isBrowser) return; // Avoid processing during server-side rendering

  this.metaTagService.removeTag('property="og:title"');
  this.metaTagService.removeTag('property="og:description"');
  // ... (other tag removals if relevant)
}

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 17.0.8
Node: 20.10.0
Package Manager: npm 10.2.5
OS: win32 x64

Angular: 17.0.8
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, platform-server
... router, ssr

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1700.8
@angular-devkit/build-angular   17.0.8
@angular-devkit/core            17.0.8
@angular-devkit/schematics      17.0.8
@angular/cdk                    17.0.4
@angular/material               17.0.4
@schematics/angular             17.0.8
rxjs                            7.8.1
typescript                      5.2.2
zone.js                         0.14.2

Anything else?

No response

@AndrewKushnir AndrewKushnir added needs reproduction This issue needs a reproduction in order for the team to investigate further area: server Issues related to server-side rendering labels Jan 2, 2024
@ngbot ngbot bot modified the milestone: Backlog Jan 2, 2024
@AndrewKushnir
Copy link
Contributor

@leandrotassi unfortunately we can't perform any investigation with the information that you've provided and we'd need a repro to see what's happening and whether there is anything on the framework side that should be fixed. You may not be able to reproduce the problem via Stackblitz (as you've mentioned), but you may try creating a new Angular app (via ng new) and try to reproduce a problem there. Note: please do not share the code of your app, create a minimal possible example code to illustrate a pattern that causes the problem.

@hieutranagi47
Copy link

@AndrewKushnir:
This is a link you can test: https://ssr-api-ivory.vercel.app/post/3
And this is the repo that I used to deploy into the above host: https://bitbucket.org/My_Profiles/ssr-api/src/main/
I think that we will have a solution to apply SSR in this use-case.

@kodetratech
Copy link

kodetratech commented Feb 16, 2024

@hieutranagi47: did you find any solution for this?
Is there any update on this? After upgrading to latest angular 17 version, it stopped working

@hieutranagi47
Copy link

@kodetratech I don't know the root cause of the issue in this case, Angular renders the home page first, then switch to the post detail page although I access the post detail page. I guess that it's Angular issue, so I don't know what the best solution for this should be.
If your page calls only one API => There is no problem.

@AndrewKushnir
Copy link
Contributor

@hieutranagi47 thanks for creating a test application! I've tried running it locally and I can see updated meta tags in the page source once the page is SSR'ed and HTML is delivered to a browser. Could you please provide a bit more info on how to reproduce the problem locally?

@hieutranagi47
Copy link

@kodetratech Thank you so much for your time.
We don't face the issue when we serve the project locally. The problem occurs when we build it as production and deploy it into a server. You can check it here: https://ssr-api-ivory.vercel.app/post/3

@yogeshbansal
Copy link

yogeshbansal commented Mar 8, 2024

@hieutranagi47 I am also facing the same problem. one thing I can tell something has happened after Angular version 17.0.3. I have an application that uses Angular 17.0.3, when I share the URL of my application to social media like Twitter or Facebook, it renders the dynamic meta tags correctly. But my other application which is running on angular 17.2.1, URLs are not working on social media sites. it renders the default value of the meta tags.
Example of app running on 17.03 ( dynamic meta tags working) : https://contentbuffer.com/issues/news/technical/telegram-now-lets-users-convert-personal-accounts-business-accounts
Example of app running on 17.2.1 ( dynamic meta tags not working): https://codebrainery.com/article/navigating-ai-revolution-software-development-chatgpt

@roosikem
Copy link

@hieutranagi47 I am also facing the same problem. project is working locally but in production it is not working. meta tags are not updating and not able to working in social media (not displaying correct meta tags and images, showing only default tags)

@hieutranagi47
Copy link

If you notice, you will see that Angular renders the root route ("/"), before render the actual route.

@roosikem
Copy link

I have notice that when updating the meta tags after receiving response from the api call it is not updating but without API call it is working.

Any solution for this

@monacodelisa
Copy link

I am also looking for a solution, please share updates whenever possible

@hieutranagi47
Copy link

@roosikem @monacodelisa @yogeshbansal : While we are waiting for the fix from the Angular core team, we could try the pre-render feature of Angular CLI. I tested it and it works.
https://angular.io/guide/prerendering#prerendering-parameterized-routes

@monacodelisa
Copy link

@roosikem cool thank you, I am actively trying different options, I will give it a try

@yogeshbansal
Copy link

yogeshbansal commented Mar 19, 2024

@hieutranagi47 @roosikem @AndrewKushnir Just wondering...Does anyone know the cause of this issue?

@leandrotassi
Copy link
Author

After careful analysis of the situation, I identified that when sharing a website on my own platform, the meta tag information was not being displayed correctly. Instead, default information from the index.html file was being loaded. This issue arises due to the behavior of certain social media crawlers, which do not wait for the website to be fully rendered before collecting information. For example, Twitter is more tolerant in this regard, while Facebook or LinkedIn are not.

To address this issue, I adopted a series of strategic measures:

  1. I used resolvers to consume the API and prepare the update of meta tags in the component, as the resolver is called before the route is activated. This way, when the route is activated, the meta tags are updated immediately.
  2. In the component, I obtained the data consumed in the resolver to update the meta tags.
  3. I am using version 17.3 of Angular. I started the project from scratch with default settings and later migrated the project from the previous version to this one, using the builder "@angular-devkit/build-angular:application" which comes pre-configured. When updating the Angular version with ng update, the builder was not updated.
  4. On the Ubuntu server hosting the site, I use NGINX and switched from Forever to PM2 to run the site. Forever has not been updated for a long time, and PM2 is always up-to-date and faster.

With these measures, I was able to completely resolve the sharing problem.

I hope these tips can help those facing the same issue.

@yogeshbansal
Copy link

@leandrotassi thanks for the response...I am also exactly doing the same. But it's not working for me. If I share the URL on Twitter or facebook, it's still picking the default meta tags.

@JeanMeche
Copy link
Member

Can anyone provide a minimal repo of this issue?
I wasn't able to reproduce with the bitbucket link provided by @hieutranagi47.

@hieutranagi47
Copy link

@JeanMeche We don't face the issue in the local environment. Please deploy it on a server (Production development) then you can see the issue. I have deployed it on Vercel here: https://ssr-api-ivory.vercel.app/post/3

@JeanMeche
Copy link
Member

I did build the app and run the dist locally without being able to reproduce your issue.

@JeanMeche
Copy link
Member

@hieutranagi47 Your issue is that you're not using SSR but prerendering (SSG). (ng-server-context="ssg" attribute in the DOM)
Check the output build and particularly prerendered-routes.json, it contains only

{
  "routes": [
    "/",
    "/post"
  ]
}

You app isn't prerendering each post entry which explains why the meta still contains the placeholder.

@monacodelisa
Copy link

@JeanMeche thank you for your comments, I wanted to ask something that I am not sure about - as far as I understand, right now both Netlify and Vercel only support SSG and do not fully support SSR - since for SSR you need to be running a Node server on a Node hosting environment like Render, Cyclic, AWS Lambda and so on ? Or can SSR be achieved fully on Netlify / Vercel ?

@JeanMeche
Copy link
Member

@monacodelisa You can deploy on Vercel serverless and Netlify Edge.

@monacodelisa
Copy link

@JeanMeche cool, thank you

@hieutranagi47
Copy link

@JeanMeche: Can you give me more info about this issue.
From the angular.json configure, when we set pretender: true, it means that Angular CLI will pre-render all available routes inside the project, and the others will run as client-side rendering if we deploy the project on a static server (ie: Vercel - I am not sure about it, AWS S3, ...).
To make sure that the project will be run as SSR, we have to deploy it into a node server (ie: Vercel Serverless)?

@JeanMeche
Copy link
Member

Yes this is what is hapeing in your case, CSR is what currently renders your posts . You need a node server to run SSR.

@hieutranagi47
Copy link

Thank you so much for the great support!

@leandrotassi
Copy link
Author

@yogeshbansal
Hmm, that's strange, but there's one thing I forgot to mention:
I believe implementing the bond strategy is also important. In the "app route" there is a title attribute to update the page title. If the title is dynamic, you can also use the resolver.

Could it be that the server that hosts your website is not influencing sharing behavior?

Did you make sure that the builder is "@angular-devkit/build-angular:application"?

Because it was these sets of measures, which I mentioned earlier, that made sharing work.

@yogeshbansal
Copy link

@leandrotassi: I have these 2 applications both are running on the same setup and server. One is working and other one is not.
Example of the app running on 17.03 ( dynamic meta tags working) : https://contentbuffer.com/issues/news/technical/telegram-now-lets-users-convert-personal-accounts-business-accounts
Example of app running on 17.2.1 ( dynamic meta tags not working): https://codebrainery.com/article/navigating-ai-revolution-software-development-chatgpt

@codewithbisky
Copy link

codewithbisky commented Mar 30, 2024

This is how I solved this. I created a ItemResolver and added it into my routes

`import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import {ItemService} from "../service/item.service";

@Injectable({
providedIn: 'root'
})
export class ItemResolver implements Resolve {
constructor(private dataService: ItemService) {}

async resolve(route: ActivatedRouteSnapshot) {
    const id = route.paramMap.get('id') ?? '';
    return await this.dataService.getItemPublicPromise(id);
}

}`

This is route configuration

{path: 'view-video/:id', component: ViewVideoPageComponent, resolve: { resolvedData: ItemResolver }},

I did this in onNit of ViewVideoPageComponent

`imageUrl: string = '';
item: any ;
ngOnInit(): Promise {
this.item = this.resolvedData = this.route.snapshot.data['resolvedData'];
this.imageUrl = your_domain+this.item.imagePath;

    this.updateMeta();

}

private updateMeta() {

    this.ngxSeoService.setSeo({
        title: this.item.title,
        meta: {
            description: this.item.metaDescription,
            image: this.imageUrl,
            type:"website"
        },
    });
}
`
I am using this dependency
"@avivharuzi/ngx-seo": "^16.0.0",


Everything is working. It is not showing the thumbnail on whatsapp. If you solve whatsapp let me know

Example of this is this one
https://www.codewithbisky.com/view-video/2b3fae4d-8e75-4d50-b9b0-e50857e2e83c

@yogeshbansal
Copy link

@codewithbisky This is how your link is looking on twitter when you try to post it.
see the attached image
Screenshot 2024-03-30 at 10 16 00 AM

@codewithbisky
Copy link

codewithbisky commented Mar 30, 2024 via email

@codewithbisky
Copy link

codewithbisky commented Mar 30, 2024 via email

@quedicesebas
Copy link

@codewithbisky works with Angular 17?

@codewithbisky
Copy link

codewithbisky commented Apr 3, 2024 via email

@quedicesebas
Copy link

Alerady using it :)

@liamong0422
Copy link

@codewithbisky I noticed that the content on the page you've shared wasn't loaded from API. I've tried your solution but it doesn't work either, I'm on Angular 17.3.3

@quedicesebas
Copy link

@liamong0422 if you need to load meta-data from an API, you should use resolvers:

const title = 'My Pizza place';
const seoResolver: ResolveFn<NgxSeo> = (route, state) => {
  return inject(MenuService)
    .getItemByUUID(route.params['itemUUID'])
    .pipe(
      map((item: MenuItem) => {
        return {
          title: route.params['itemUUID'] ? item.name : 'Menú | ' + title,
          meta: {
            description: route.params['itemUUID']
              ? item.description
              : 'Best pizza in town',
            image: item.imageUrl,
            type: 'website',
            url: 'https://mypizzaplace.com' + state.url,
          },
        };
      }),
    );
};

export const MENU_ROUTES: Routes = [
  {
    path: ':itemUUID',
    component: MenuComponent,
    resolve: { seo: seoResolver },
  }
  {
    path: '',
    component: MenuComponent,
    resolve: { seo: seoResolver },
  },
];

@liamong0422
Copy link

@liamong0422 if you need to load meta-data from an API, you should use resolvers:

const title = 'My Pizza place';
const seoResolver: ResolveFn<NgxSeo> = (route, state) => {
  return inject(MenuService)
    .getItemByUUID(route.params['itemUUID'])
    .pipe(
      map((item: MenuItem) => {
        return {
          title: route.params['itemUUID'] ? item.name : 'Menú | ' + title,
          meta: {
            description: route.params['itemUUID']
              ? item.description
              : 'Best pizza in town',
            image: item.imageUrl,
            type: 'website',
            url: 'https://mypizzaplace.com' + state.url,
          },
        };
      }),
    );
};

export const MENU_ROUTES: Routes = [
  {
    path: ':itemUUID',
    component: MenuComponent,
    resolve: { seo: seoResolver },
  }
  {
    path: '',
    component: MenuComponent,
    resolve: { seo: seoResolver },
  },
];

I'm already using the resolver but I am still experiencing the same issue. The website will load the home page first, then to the details page. But for pages that doesn't load API, it will go straight to the page and the metatags were successfully loaded in the page source.

@quedicesebas
Copy link

Yes, is not working :(

@yogeshbansal
Copy link

@JeanMeche Could you Please reopen this issue...we still don't have the solution for this. My angular app is running on AWS with nginx and SSR. Still meta tags are not getting updated dynamically, it loads the default tags

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: server Issues related to server-side rendering needs reproduction This issue needs a reproduction in order for the team to investigate further
Projects
None yet
Development

No branches or pull requests