vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.68k stars 26.61k forks source link

duplicate meta tags in head #38877

Open macrozone opened 2 years ago

macrozone commented 2 years ago

Verify canary release

Provide environment information

Operating System: Platform: darwin Arch: x64 Version: Darwin Kernel Version 21.4.0: Fri Mar 18 00:45:05 PDT 2022; root:xnu-8020.101.4~15/RELEASE_X86_64 Binaries: Node: 14.20.0 npm: 6.14.17 Yarn: 1.22.18 pnpm: N/A Relevant packages: next: 12.2.2 eslint-config-next: 12.0.10 react: 17.0.2 react-dom: 17.0.2

What browser are you using? (if relevant)

chrome, safari

How are you deploying your application? (if relevant)

No response

Describe the Bug

some meta tags in the head are duplicated.

this can be even seen on the official nextjs page (viewport meta tag):

Bildschirmfoto 2022-07-21 um 18 25 32

interestingly, in chrome this happens on my computer only when in a guest / icognito window.

those duplication are not present on the SSR source, so its a hydration problem

Expected Behavior

no duplicate tags

Link to reproduction

https://nextjs.org/

To Reproduce

open https://nextjs.org/

use inspector, look at the head

ijjk commented 2 years ago

Hi, it looks like this is related to a change in google tag manager where it's injecting a new script to the head breaking the next-head-count order. Can you confirm this is similar to the case you are seeing in your project as well?

snelsi commented 2 years ago

@ijjk Can confirm. For some reason, GTM is inserting it's scripts above next-head-count, causing meta tags duplication when navigating between pages image

macrozone commented 2 years ago

Hi, it looks like this is related to a change in google tag manager where it's injecting a new script to the head breaking the next-head-count order. Can you confirm this is similar to the case you are seeing in your project as well?

Hi, yes, that could be indeed the case, it uses GTM and it injects various stuff in the header, in our case i see a clarity.ms script and analytics:

Bildschirmfoto 2022-07-29 um 09 48 08
velialiev commented 2 years ago

Same issue here using Next.js v10.2.3. Any updates?

Z2Y commented 2 years ago

duplicate meta tags when use with preact. https://github.com/garmeeh/next-seo/issues/864

mikeldoka1 commented 1 year ago

Any fix for this yet?

KingMatrix1989 commented 1 year ago

Same issue with Next.js v12

zargold commented 1 year ago

definitely not a silver bullet: but could we address by keeping a different count for scripts, meta tags, etc. rather than just one next-head-count we could keep one for each? Better yet would be some sort of hash of each specific tag so we know that this one already exists and don't need to create another m:d ().

guzz commented 1 year ago

Also seeing this issue in nextjs v12

JaysonHewe-KSO commented 1 year ago

Have you guys tried placing the GTM scripts at the top, immediately after the web page's opening <head> tag?

lindseybradford commented 1 year ago

πŸ‘‹πŸ» Also encountering this and curious if there are any good work arounds.

mikeldoka1 commented 1 year ago

πŸ‘‹πŸ» Also encountering this and curious if there are any good work arounds.

Yes, switched back to wordpress !

victoriaSh commented 1 year ago

Facing the same issue: The is duplicated on every page. The <meta name="viewport" .../> is duplicated after navigating, even if the viewport meta is not set.

next@13.2.4

finevans commented 1 year ago

Also having this problem - any plans to fix?

JaysonHewe-KSO commented 1 year ago

Hi everyone, please try moving any scripts that appends additional scripts, e.g., GTM, to _document, and at the top of the <Head> stack, so it doesn't mess up the next-head-count order.

ghost commented 1 year ago

Any update on this? Facing the same issue after integrating google tag manager.

ing-ivan-31 commented 1 year ago

Any update on this? Facing the same issue

pm0u commented 1 year ago

I'm actually not seeing this on the current NextJS site, so maybe someone from the team could chime in for how this was officially fixed and update the docs?

image

in our case, moving GTM to document resolved.

EDIT: it actually did not. Moving <Scripts /> to Document just meant they didn't load at all which removed the duplicates but obviously we need these scripts to load.

Edit 2: Okay, I have no idea what is going on here but the resulting solution

  1. Do not abstract these scripts to their own components, they need to use the Script component imported in _document
  2. Use strategy beforeInteractive on these scripts
  3. Include these scripts as children of the <Head /> component in _document
  4. Also include the affected meta tags that were previously in _app in _document

1 - they did not show up otherwise no matter what else changed (strategy, child of Head which yes broke NextJS rules but I tried it) 2 - they did not show up otherwise 3 - again, did not show up otherwise 4 - when we had a sitewide meta tag in _app it still got moved around until it was included in document

Our use case included the usual GTM inline script that appends to the document head as well as an external script.

pm0u commented 1 year ago

Still had issues, ended up doing a custom implementation for GTM so that it at least didn't append itself to the head of the document - we do have other scripts bundled so that may still happen somewhere down the line and will require some further testing. For now:


import { gtmId } from "../../../constants"
import Script from "next/script"
import { useEffect } from "react"

export const GTMScript = () => {
  useEffect(() => {
    window.dataLayer = window.dataLayer ?? []
    window.dataLayer.push({
      "gtm.start": new Date().getTime(),
      event: "gtm.js",
    })
  }, [])
  return <Script src={`https://www.googletagmanager.comgtm.js?id=${gtmId}`} />
}
ghost commented 1 year ago

Thank you @pm0u . If possible please keep us updated if you find anything else.

pm0u commented 1 year ago

Following up -

We ended up moving these scripts to afterInteractive so they end up in the body rather than the head and this seems to work although I haven't stress tested bundling scripts with GTM

image

https://nextjs.org/docs/pages/api-reference/components/script#afterinteractive

This was primarily spurred after getting this linter error: https://nextjs.org/docs/messages/next-script-for-ga as well as the note in the docs there re: intended uses.

hitarthdesai commented 1 year ago

Following up -

We ended up moving these scripts to afterInteractive so they end up in the body rather than the head and this seems to work although I haven't stress tested bundling scripts with GTM

image

https://nextjs.org/docs/pages/api-reference/components/script#afterinteractive

This was primarily spurred after getting this linter error: https://nextjs.org/docs/messages/next-script-for-ga as well as the note in the docs there re: intended uses.

So I am assuming the <Script /> tag is not in _document.js. So did you move it to an _app.js component or someplace else?

pm0u commented 1 year ago

So I am assuming the <Script /> tag is not in _document.js. So did you move it to an _app.js component or someplace else?

Correct, these scripts are now in _app.tsx. Also just for the record we are using the pages router currently on Next 13.4

hitarthdesai commented 1 year ago

@pm0u so I shifted the <Script /> tag in the _app.tsx file, but, duplication in my case still persists. Do you have any idea on why this may not have worked in my case OR any other possible solutions on your mind?

SamuelePiazzesi commented 1 year ago

Any update on this? Facing the same issue. I think the problem it's the GTM script

hitarthdesai commented 1 year ago

I ended up slightly modifying the default gtm loading script to essentially not allow next-head-count to mess things up because of time constraints. However, the issue still persists in next 12.

The default gtm script finds the first <script /> element and loads all gtm scripts before it. Now you can change the first step to be something else like find the first css link tag or anything else that you see fit, and then load the gtm scripts below it. Just make sure it is below the <meta name="next-head-count" /> tag.

Also another thing to note is that you could upgrade to next13 and try the experimental.nextStrictHead flag which throws next-head-count out the window, but I was unable to try it due to constraints on the next version we use at out company.

SamuelePiazzesi commented 1 year ago

@hitarthdesai thank you so much for the update. Actually i have the same problem: my company still use the 12 version of Next. Do you have any implementation example of how did you changed the script?

hitarthdesai commented 1 year ago

I did the following:

var p=d.head.getElementsByTagName("meta").namedItem("next-head-count")
p.parentNode.insertBefore(i, p.nextElementSibling);
p.parentNode.insertBefore(j, i.nextElementSibling);

where j is the script element created in the default gtm script. All I changed was how they created a var f = ... and used the above replacement instead.