如何让Usercentrics Cookiebot在Next.js v14(App Router)中正常工作
问题分析
- React错误#418:Cookiebot的
data-blockingmode="auto"会自动修改DOM元素,和Next.js的hydration(水合)过程冲突,导致React检测到DOM不匹配触发报错,同时横幅因DOM被干扰短暂显示后消失。 - next/script方案失败:大概率是属性传递错误、策略选择不当,或是CBID(Cookiebot ID)未正确替换导致脚本找不到。
解决方案
方案1:使用next/script正确集成(推荐)
Next.js的next/script组件专门优化外部脚本加载,需注意以下细节:
uc.js必须设置id="Cookiebot",且用beforeInteractive策略确保页面初始化时加载。- 所有
data-*属性直接作为props传递给Script组件。 - 替换所有
<id here>为你的真实Cookiebot CBID。
import { Script } from 'next/script'; import { isProduction } from '@/utils/env'; // 替换为你的环境判断函数 export default function RootLayout({ children }: { children: React.ReactNode }) { const CBID = '你的真实Cookiebot ID'; // 替换成实际ID return ( <html lang="en"> <head> <link rel="icon" href="/favicon.svg" /> {isProduction() && ( <Script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" data-cbid={CBID} data-blockingmode="auto" strategy="beforeInteractive" /> )} </head> <body className={`${urbanist.className} flex flex-col`}> <Providers> {children} <Analytics /> </Providers> {isProduction() && ( <Script id="CookieDeclaration" src={`https://consent.cookiebot.com/${CBID}/cd.js`} strategy="afterInteractive" async /> )} </body> </html> ); }
方案2:修复原生script的hydration冲突
如果坚持使用原生script,需避免在hydration过程中让Cookiebot修改DOM:
- 将
data-blockingmode="auto"改为data-blockingmode="manual",避免自动操作DOM。 - 在客户端hydration完成后再加载脚本,用
useEffect实现(仅在客户端执行)。
'use client'; // 必须添加,useEffect为客户端钩子 import { useEffect } from 'react'; import { isProduction } from '@/utils/env'; export default function RootLayout({ children }: { children: React.ReactNode }) { const CBID = '你的真实Cookiebot ID'; useEffect(() => { if (!isProduction()) return; // 加载uc.js const ucScript = document.createElement('script'); ucScript.id = 'Cookiebot'; ucScript.src = 'https://consent.cookiebot.com/uc.js'; ucScript.setAttribute('data-cbid', CBID); ucScript.setAttribute('data-blockingmode', 'auto'); document.head.appendChild(ucScript); // 加载CookieDeclaration脚本 const cdScript = document.createElement('script'); cdScript.id = 'CookieDeclaration'; cdScript.src = `https://consent.cookiebot.com/${CBID}/cd.js`; cdScript.async = true; document.body.appendChild(cdScript); // 清理函数 return () => { ucScript.remove(); cdScript.remove(); }; }, []); return ( <html lang="en"> <head> <link rel="icon" href="/favicon.svg" /> </head> <body className={`${urbanist.className} flex flex-col`}> <Providers> {children} <Analytics /> </Providers> </body> </html> ); }
额外注意事项
- 确保
isProduction()函数正确判断环境,避免在开发环境加载生产脚本。 - 检查CBID是否正确,登录Cookiebot后台可获取专属ID。
- 不要同时使用原生script和next/script加载Cookiebot脚本,会导致冲突。
内容的提问来源于stack exchange,提问作者octavemirbeau
相关产品推荐
相关产品推荐

