我正在使用 nextjs,并且还必须处理 facebook 广告。我建议做的第一件事是他们登陆的任何登陆页面,使用路由器提取搜索查询参数参数。
const nonce = crypto.createHash('sha256').update(v4()).digest('base64');
const router = useRouter();
const {
query: { utm_medium, utm_campaign, utm_source, utm_term, fbclid }
} = router;
const parsing: typeof router.query = {
fbclid: fbclid ? (fbclid as string) : `${nonce}`,
utm_medium: utm_medium ? (utm_medium as string) : 'organic',
utm_term: utm_term ? (utm_term as string) : 'organic',
utm_source: utm_source ? (utm_source as string) : 'organic',
utm_campaign: utm_campaign ? (utm_campaign as string) : 'organic'
};
另外,这可能与没有安装 facebook 像素有关?
{
"dependencies": {
"@apollo/client": "^3.4.10",
"@artsy/fresnel": "^1.9.0",
"@datadog/browser-rum": "^3.3.1",
"@google-analytics/data": "^2.7.0",
"@headlessui/react": "^1.4.1",
"@react-spring/web": "^9.2.4",
"@stripe/react-stripe-js": "^1.4.1",
"@stripe/stripe-js": "^1.17.1",
"apollo-upload-client": "^16.0.0",
"autoprefixer": "^10.3.4",
"body-scroll-lock": "4.0.0-beta.0",
"classnames": "^2.3.1",
"cookie": "^0.4.1",
"date-fns": "^2.23.0",
"debounce": "^1.2.1",
"graphql": "^15.5.3",
"graphql-upload": "^12.0.0",
"html-react-parser": "^1.3.0",
"js-cookie": "^3.0.1",
"keen-slider": "^5.5.1",
"micro": "^9.3.4",
"micro-cors": "^0.1.1",
"next": "^11.1.3-canary.14",
"next-seo": "^4.26.0",
"next-themes": "^0.0.15",
"postcss": "^8.3.6",
"postcss-import": "^14.0.2",
"postcss-nesting": "^8.0.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-facebook-pixel": "^1.0.4",
"react-fast-marquee": "^1.2.1",
"react-gtm-module": "^2.0.11",
"react-intersection-observer": "^8.32.1",
"react-merge-refs": "^1.1.0",
"react-tsparticles": "^1.34.0",
"react-use-cart": "^1.11.2",
"react-use-measure": "^2.0.4",
"remark-gfm": "^2.0.0",
"stripe": "^8.174.0",
"swr": "^1.0.0",
"tabbable": "^5.2.1",
"tailwindcss": "^2.2.12",
"uuid": "^8.3.2",
"vercel": "^23.1.2"
},
"devDependencies": {
"@babel/core": "^7.15.5",
"@babel/eslint-parser": "^7.15.4",
"@babel/preset-env": "^7.15.4",
"@babel/preset-typescript": "^7.15.0",
"@graphql-codegen/add": "^3.1.0",
"@graphql-codegen/cli": "2.2.0",
"@graphql-codegen/fragment-matcher": "3.1.0",
"@graphql-codegen/jsdoc": "^2.1.3",
"@graphql-codegen/named-operations-object": "^2.1.0",
"@graphql-codegen/schema-ast": "^2.2.0",
"@graphql-codegen/typed-document-node": "^2.1.3",
"@graphql-codegen/typescript": "2.2.1",
"@graphql-codegen/typescript-apollo-client-helpers": "^2.1.3",
"@graphql-codegen/typescript-document-nodes": "^2.1.3",
"@graphql-codegen/typescript-operations": "2.1.3",
"@graphql-codegen/typescript-react-apollo": "3.1.3",
"@graphql-typed-document-node/core": "^3.1.0",
"@next/bundle-analyzer": "^11.1.2",
"@next/eslint-plugin-next": "^11.1.2",
"@tailwindcss/aspect-ratio": "^0.2.1",
"@tailwindcss/forms": "^0.3.3",
"@tailwindcss/jit": "^0.1.18",
"@tailwindcss/line-clamp": "^0.2.1",
"@tailwindcss/typography": "^0.4.1",
"@testing-library/dom": "^8.3.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/apollo-upload-client": "^14.1.0",
"@types/body-scroll-lock": "^3.1.0",
"@types/cookie": "^0.4.1",
"@types/debounce": "^1.2.0",
"@types/duplicate-package-checker-webpack-plugin": "^2.1.2",
"@types/facebook-pixel": "^0.0.24",
"@types/google.analytics": "^0.0.42",
"@types/graphql-upload": "^8.0.7",
"@types/gtag.js": "^0.0.7",
"@types/jest": "^27.0.1",
"@types/js-cookie": "^2.2.7",
"@types/lodash.debounce": "^4.0.6",
"@types/lodash.isequal": "^4.5.5",
"@types/lodash.merge": "^4.6.6",
"@types/lodash.random": "^3.2.6",
"@types/lodash.throttle": "^4.1.6",
"@types/lodash.tonumber": "^4.0.6",
"@types/lodash.update": "^4.10.6",
"@types/micro": "^7.3.6",
"@types/micro-cors": "^0.1.2",
"@types/node": "^16.7.13",
"@types/react": "^17.0.20",
"@types/react-dom": "^17.0.9",
"@types/react-gtm-module": "^2.0.1",
"@types/react-test-renderer": "^17.0.1",
"@types/tabbable": "^3.1.1",
"@types/tailwindcss": "^2.2.1",
"@types/uuid": "^8.3.1",
"@typescript-eslint/eslint-plugin": "^4.31.0",
"@typescript-eslint/parser": "^4.31.0",
"babel-jest": "^27.1.1",
"babel-plugin-module-resolver": "^4.1.0",
"cross-env": "^7.0.3",
"deepmerge": "^4.2.2",
"dotenv": "^10.0.0",
"dotenv-cli": "^4.0.0",
"eslint": "^7.32.0",
"eslint-config-next": "^11.1.2",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-yml": "^0.10.0",
"graphql-config": "^4.0.1",
"husky": "^7.0.2",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.1.1",
"jest-diff": "^27.1.1",
"jest-matcher-css": "^1.1.0",
"jest-mock-extended": "2.0.2-beta2",
"jest-watch-typeahead": "^0.6.4",
"lint-staged": "^11.1.2",
"next-sitemap": "^1.6.168",
"next-unused": "^0.0.6",
"patch-package": "^6.4.7",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^6.7.0",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.3.2",
"pretty-quick": "^3.1.1",
"react-test-renderer": "^17.0.2",
"stylelint": "^13.13.1",
"stylelint-config-recommended": "^5.0.0",
"ts-jest": "^27.0.5",
"typescript": "^4.4.2",
"webpack": "^5.52.0",
"webpack-bundle-size-analyzer": "^3.1.0",
"yaml-loader": "^0.6.0"
}
}
FB PIXEL 实例化(类似于谷歌标签管理器)
我还建议获取类似于 api 路由的东西,用于记录并向控制台发出事件。这样,您可以在 Vercel 上检查您的无服务器函数日志以尝试查明错误
export const FB_PIXEL_ID = process.env.NEXT_PUBLIC_FACEBOOK_PIXEL_ID ?? '';
export const pageview = async () => {
typeof window !== 'undefined'
? window.fbq('track', 'PageView')
: console.log('window undefined');
};
// https://developers.facebook.com/docs/facebook-pixel/advanced/
export const event = (
{ name }: facebook.Pixel.Event,
options = { debug: process.env.NODE_ENV !== 'production' ? true : false }
) => {
window.fbq('track', name, options);
};
- components/Application/google-facebook-provider.tsx
import { useEffect, FC, Fragment } from 'react';
import { useRouter } from 'next/router';
import * as gtm from '@/utils/gtm';
import { FB_PIXEL_ID } from '@/utils/fbpixel';
const GoogleFacebookProvider: FC = ({ children }) => {
const router = useRouter();
useEffect(() => {
const shouldReport = process.env.NODE_ENV === 'production';
const handleRouteChangeGtag = (url: URL) => {
gtm.pageview(url);
};
if (shouldReport) {
router.events.on('routeChangeComplete', handleRouteChangeGtag);
return () => {
router.events.off('routeChangeComplete', handleRouteChangeGtag);
};
}
return console.log(
JSON.stringify(
router.events.on
? router.events.on('routeChangeComplete', handleRouteChangeGtag)
: router.events.off
? router.events.off('routeChangeComplete', handleRouteChangeGtag)
: router.events.emit('routeChangeError'),
null,
2
)
);
}, [router.events]);
useEffect(() => {
const shouldReport = process.env.NODE_ENV === 'production';
if (shouldReport) {
import('react-facebook-pixel')
.then(x => x.default)
.then(ReactPixel => {
ReactPixel.init(FB_PIXEL_ID);
ReactPixel.pageView();
router.events.on('routeChangeComplete', () => {
ReactPixel.pageView();
});
});
}
}, [router.events]);
return <Fragment>{children}</Fragment>;
};
export default GoogleFacebookProvider;
在 _app.tsx 文件中,只需将根 <Component {...pageProps} /> 包裹在您的 GoogleFacebookProvider 组件中
import '../styles/index.css';
import React, { useEffect, ReactElement, ReactNode, FC } from 'react';
import * as gtag from '@/utils/analytics';
import { useRouter } from 'next/router';
import { NextWebVitalsMetric, AppContext, AppInitialProps } from 'next/app';
import { ApolloProvider } from '@apollo/client';
import { Head } from '@/components/Head';
import { useApollo } from '@/apollo/apollo';
import { AuthProvider } from '@/lib/use-auth';
import { NextSEO } from '../next-seo';
import { GoogleFacebookProvider } from '@/components/App';
import Script from 'next/script';
import { GA_TRACKING_ID } from '@/utils/analytics';
import { FB_PIXEL_ID } from '@/utils/fbpixel';
import { GTM_ID } from '@/utils/gtm';
import { datadogRum } from '@datadog/browser-rum';
const Noop: FC = ({ children }) => <>{children}</>;
const applicationId = process.env.NEXT_PUBLIC_DATADOG_CLIENT_ID ?? '';
const clientToken = process.env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN ?? '';
datadogRum.init({
applicationId: `${applicationId}`,
clientToken: `${clientToken}`,
site: 'datadoghq.com',
service: 'www-getcortina',
env: 'production',
version: '1.0.0',
sampleRate: 100,
trackInteractions: true,
trackSessionAcrossSubdomains: true
// internalMonitoringApiKey: process.env.DATADOG
});
export default function NextApp({
Component,
pageProps
}: AppContext & AppInitialProps) {
const LayoutNoop = (Component as any).LayoutNoop || Noop;
const apolloClient = useApollo(pageProps);
useEffect(() => {
document.body.classList?.remove('loading');
}, []);
const router = useRouter();
useEffect(() => {
const isProd = process.env.NODE_ENV === 'production';
const handleRouteChange = (url: URL) => {
if (isProd) gtag.pageview(url);
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router.events]);
return (
<>
<Script
async
strategy='lazyOnload'
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
defer
/>
<Script strategy='afterInteractive' id={`${GA_TRACKING_ID}`}>
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}', {
page_path: window.location.pathname,
});
`}
</Script>
<Script strategy='afterInteractive' id={`${GTM_ID}`}>
{`
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer', '${GTM_ID}');
`}
</Script>
<Script strategy='afterInteractive' id={`${FB_PIXEL_ID}`}>
{`
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '${FB_PIXEL_ID}');
fbq('track', 'PageView');
`}
</Script>
<Head nextSeoProps={NextSEO} />
<ApolloProvider client={apolloClient}>
<AuthProvider>
<GoogleFacebookProvider>
<LayoutNoop pageProps={pageProps}>
<Component {...pageProps} />
</LayoutNoop>
</GoogleFacebookProvider>
</AuthProvider>
</ApolloProvider>
</>
);
}
最后,在 _document.tsx 中,您必须 (a) 提供您的 facebook verification code 以进行域验证,并且 (b) 提供 noscript 图像...至少对于基本配置。我目前正在研究替代方法。
import Document, {
Head,
Html,
Main,
NextScript,
DocumentContext,
DocumentInitialProps
} from 'next/document';
import { GTM_ID } from '@/utils/gtm';
import { FB_PIXEL_ID } from '@/utils/fbpixel';
import Image from 'next/image';
class Cortina extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: <>{initialProps.styles}</>
};
}
render() {
return (
<Html lang='en'>
<Head>
<link
href='/fonts/GothamLatin/GothamPro.woff2'
rel='preload'
as='font'
type='font/woff2'
crossOrigin='anonymous'
/>
<link
rel='prefetch'
type='video/mp4'
href='/videos/Cortina_Selphie.mp4'
crossOrigin='anonymous'
media='(autoplay)'
/>
<link href='/meta/favicon.ico' rel='shortcut icon' />
<link href='/meta/site.webmanifest' rel='manifest' />
<link
rel='apple-touch-icon'
sizes='180x180'
href='/meta/apple-touch-icon.png'
/>
<link
rel='icon'
type='image/png'
sizes='16x16'
href='/meta/favicon-16x16.png'
/>
<link
rel='icon'
type='image/png'
sizes='32x32'
href='/meta/favicon-32x32.png'
/>
<link
rel='mask-icon'
href='/meta/safari-pinned-tab.svg'
color='#5bbad5'
/>
<meta name='msapplication-TileColor' content='#da532c' />
<meta name='theme-color' content='#ffffff' />
<meta name='msapplication-config' content='/meta/browserconfig.xml' />
<meta
name='facebook-domain-verification'
content='7c23wx4wuh3cnsatzfmekou1yallec'
/>
<meta
name='google-site-verification'
content='zIWPD8byBUQ5GCoLDvkkwes7U1mhFIp18mnf5RxSz58'
/>
</Head>
<body className='loading'>
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${GTM_ID}`}
height='0'
width='0'
style={{ display: 'none', visibility: 'hidden' }}
/>
</noscript>
<noscript>
<Image
height='1'
width='1'
className='invisible'
alt='fb pixel no script'
src={`https://www.facebook.com/tr?id=${FB_PIXEL_ID}&ev=PageView&noscript=1`}
/>
</noscript>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default Cortina;