Skip to content

Commit

Permalink
feat: add support for facebook pixel (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
lotyp authored Feb 3, 2023
1 parent 755c05e commit c169c73
Show file tree
Hide file tree
Showing 20 changed files with 389 additions and 208 deletions.
7 changes: 7 additions & 0 deletions .changeset/small-pigs-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@wayofdev/eslint-config-custom': patch
'@wayofdev/google-tag-manager': patch
'web': patch
---

feat: add support for facebook pixel
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@ NEXT_IGNORE_TYPE_CHECK=false

NEXT_DEBUG_I18N=true

### Analytics
# Google Tag Manager
NEXT_PUBLIC_GTM_ID=GTM-XXXXXXX
# Facebook Pixel
NEXT_PUBLIC_FACEBOOK_PIXEL_ID=0000000000000000
NEXT_PUBLIC_FACEBOOK_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Authentification
NEXTAUTH_URL=${APP_URL}
14 changes: 8 additions & 6 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,31 @@
},
"dependencies": {
"@fontsource/inter": "^4.5.15",
"@wayofdev/google-tag-manager": "workspace:*",
"@headlessui/react": "^1.7.8",
"@heroicons/react": "^2.0.14",
"@hookform/resolvers": "^2.9.10",
"@httpx/exception": "^1.7.1",
"@vercel/analytics": "latest",
"@wayofdev/facebook-pixel": "workspace:*",
"@wayofdev/google-tag-manager": "workspace:*",
"@wayofdev/ui": "workspace:*",
"clsx": "^1.2.1",
"i18next": "^22.4.9",
"next": "^13.1.6",
"next-auth": "^4.19.1",
"next-i18next": "^13.0.3",
"next-auth": "^4.19.2",
"next-i18next": "^13.1.4",
"next-seo": "^5.15.0",
"next-sitemap": "^3.1.48",
"next-sitemap": "^3.1.49",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.43.0",
"react-i18next": "^12.1.4",
"react-i18next": "^12.1.5",
"type-fest": "^3.5.4",
"zod": "^3.20.2"
},
"devDependencies": {
"@next/bundle-analyzer": "13.1.6",
"@sentry/nextjs": "^7.34.0",
"@sentry/nextjs": "^7.36.0",
"@size-limit/file": "^8.1.2",
"@storybook/addon-essentials": "^7.0.0-beta.38",
"@storybook/addon-interactions": "^7.0.0-beta.38",
Expand All @@ -58,6 +59,7 @@
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/facebook-pixel": "^0.0.24",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/jest": "29.4.0",
"@types/node": "^18.11.18",
Expand Down
6 changes: 6 additions & 0 deletions apps/web/src/features/home/pages/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { event } from '@wayofdev/facebook-pixel/src/lib/fpixel'
import { Button } from '@wayofdev/ui'
import { useTranslation } from 'next-i18next'
import { NextSeo } from 'next-seo'
import type { FC } from 'react'
Expand All @@ -8,6 +10,9 @@ import { homeConfig } from '../home.config'

export const HomePage: FC = () => {
const { t } = useTranslation(homeConfig.i18nNamespaces)
const handleClick = () => {
event('Purchase', { value: 10, currency: 'USD', test_event_code: 'TEST24819' })
}

return (
<>
Expand All @@ -18,6 +23,7 @@ export const HomePage: FC = () => {
<MainLayout>
<Banner />
<MainNav />
<Button onClick={handleClick}>Buy 10$</Button>
</MainLayout>
</>
)
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FacebookPixelScript } from '@wayofdev/facebook-pixel/src'
import { GoogleTagManagerScript } from '@wayofdev/google-tag-manager/src'
import type { AppProps } from 'next/app'
import Head from 'next/head'
Expand Down Expand Up @@ -43,6 +44,7 @@ const MyApp = (appProps: MyAppProps) => {
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</Head>
<GoogleTagManagerScript />
<FacebookPixelScript />
{/* Workaround for https://github.com/vercel/next.js/issues/8592 */}
<Component {...pageProps} err={err} />
</AppProviders>
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Analytics } from '@vercel/analytics/react'
import { FacebookPixelNoScript } from '@wayofdev/facebook-pixel/src'
import { GoogleTagManagerNoScript } from '@wayofdev/google-tag-manager/src'
import type { DocumentContext, DocumentInitialProps } from 'next/document'
import Document, { Html, Head, Main, NextScript } from 'next/document'
Expand Down Expand Up @@ -47,6 +48,7 @@ class MyDocument extends Document {
</body>
<Analytics />
<GoogleTagManagerNoScript />
<FacebookPixelNoScript />
</Html>
)
}
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@
"postcss": "^8.4.21",
"prettier": "^2.8.3",
"rimraf": "^4.1.2",
"secretlint": "^6.0.2",
"secretlint": "^6.1.0",
"shell-quote": "^1.8.0",
"sort-package-json": "^2.3.0",
"sort-package-json": "^2.4.0",
"stylelint": "^14.16.1",
"stylelint-a11y": "^1.2.3",
"turbo": "^1.7.0",
"turbo": "^1.7.2",
"typescript": "^4.9.5"
},
"packageManager": "[email protected]",
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-config-custom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-regexp": "^1.12.0",
"eslint-plugin-security": "^1.7.0",
"eslint-plugin-security": "^1.7.1",
"eslint-plugin-sonarjs": "^0.18.0",
"eslint-plugin-storybook": "^0.6.10",
"eslint-plugin-tailwindcss": "^3.8.2",
"eslint-plugin-tailwindcss": "^3.8.3",
"eslint-plugin-testing-library": "^5.10.0",
"eslint-plugin-unicorn": "^45.0.2",
"prettier": "^2.8.3"
Expand Down
35 changes: 35 additions & 0 deletions packages/facebook-pixel/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Specific eslint rules for this app/package, extends the base rules
* @see https://github.com/belgattitude/nextjs-monorepo-example/blob/main/docs/about-linters.md
* @see https://github.com/wayofdev/next-starter-tpl/blob/master/docs/about-linters.md
*/

// Workaround for https://github.com/eslint/eslint/issues/3458 (re-export of @rushstack/eslint-patch)
require('@wayofdev/eslint-config-custom/patch/modern-module-resolution')

const { getDefaultIgnorePatterns } = require('@wayofdev/eslint-config-custom/helpers')

module.exports = {
root: true,
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.json',
},
ignorePatterns: [...getDefaultIgnorePatterns()],
extends: [
'@wayofdev/eslint-config-custom/typescript',
'@wayofdev/eslint-config-custom/regexp',
'@wayofdev/eslint-config-custom/sonar',
'@wayofdev/eslint-config-custom/jest',
'@wayofdev/eslint-config-custom/rtl',
'@wayofdev/eslint-config-custom/react',
// Apply prettier and disable incompatible rules
'@wayofdev/eslint-config-custom/prettier',
],
rules: {
// optional overrides per project
},
overrides: [
// optional overrides per project file match
],
}
11 changes: 11 additions & 0 deletions packages/facebook-pixel/.ncurc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
# Will override root .ncurc.yml
# @link https://github.com/raineorshine/npm-check-updates

reject: []
# Exclude package dependencies (not peer) if you want to keep a lower
# range when publishing. For example:
# '@emotion/react',
# '@emotion/styled',
# 'react',
# 'react-dom',
29 changes: 29 additions & 0 deletions packages/facebook-pixel/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@wayofdev/facebook-pixel",
"version": "1.0.0",
"private": true,
"homepage": "https://github.com/wayofdev/next-starter-tpl",
"license": "MIT",
"author": {
"name": "Andrij Orlenko",
"email": "[email protected]",
"url": "https://github.com/lotyp"
},
"sideEffects": false,
"scripts": {
"clean": "rimraf dist .turbo",
"lint": "eslint . --ext .ts,.tsx,.js,.jsx,.cjs,.mjs --cache --cache-location ../../.cache/eslint/facebook-pixel.eslintcache",
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx,.cjs,.mjs --fix",
"lint:types": "tsc --project tsconfig.json --noEmit"
},
"devDependencies": {
"@types/facebook-pixel": "^0.0.24",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10"
},
"peerDependencies": {
"next": "^13.1.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
17 changes: 17 additions & 0 deletions packages/facebook-pixel/src/components/FacebookPixelNoScript.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { facebookPixelId } from '../lib/fpixel'

export function FacebookPixelNoScript() {
return (
<>
<noscript>
<img
height="1"
width="1"
style={{ display: 'none' }}
src={`https://www.facebook.com/tr?id=${facebookPixelId}&ev=PageView&noscript=1`}
alt=""
/>
</noscript>
</>
)
}
43 changes: 43 additions & 0 deletions packages/facebook-pixel/src/components/FacebookPixelScript.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useRouter } from 'next/router'
import Script from 'next/script'
import { useEffect } from 'react'
import { onRouteChangeComplete, facebookPixelId } from '../lib/fpixel'

export function FacebookPixelScript() {
const router = useRouter()

useEffect(() => {
// This pageview only triggers the first time (it's important for Pixel to have real information)
onRouteChangeComplete()

router.events.on('routeChangeComplete', onRouteChangeComplete)
return () => {
router.events.off('routeChangeComplete', onRouteChangeComplete)
}
}, [router.events])

if (!facebookPixelId) return null

return (
<>
{/* Global Site Code Pixel - Facebook Pixel */}
<Script
id="fb-pixel"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
!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', ${facebookPixelId});
`,
}}
/>
</>
)
}
2 changes: 2 additions & 0 deletions packages/facebook-pixel/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './FacebookPixelScript'
export * from './FacebookPixelNoScript'
1 change: 1 addition & 0 deletions packages/facebook-pixel/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components'
16 changes: 16 additions & 0 deletions packages/facebook-pixel/src/lib/fpixel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const facebookPixelId = process.env.NEXT_PUBLIC_FACEBOOK_PIXEL_ID

declare global {
interface Window {
fbq: facebook.Pixel.Event
}
}

// https://developers.facebook.com/docs/facebook-pixel/advanced/
export const event = (name: string, options = {}) => {
window.fbq('track', name, options)
}

export const onRouteChangeComplete = () => {
window.fbq('track', 'PageView')
}
14 changes: 14 additions & 0 deletions packages/facebook-pixel/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../../tsconfig.base.json",
"exclude": ["**/node_modules", "**/.*/", "dist", "build"],
"include": ["./src/**/*"],
"compilerOptions": {
"baseUrl": "./src",
"target": "esnext",
"outDir": "dist",
"allowJs": true,
"jsx": "react-jsx",
"noEmit": false
}
}
10 changes: 5 additions & 5 deletions packages/google-tag-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx,.cjs,.mjs --fix",
"lint:types": "tsc --project tsconfig.json --noEmit"
},
"peerDependencies": {
"next": "^13.1.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/gapi.client.tagmanager": "^2.0.3",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10"
},
"peerDependencies": {
"next": "^13.1.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ export function GoogleTagManagerScript() {

return (
<>
<Script id="gtag-base" strategy="afterInteractive">{`
(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', '${gtmId}');
`}</Script>
<Script
id="gtag-base"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
(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', '${gtmId}');
`,
}}
/>
</>
)
}
Loading

2 comments on commit c169c73

@vercel
Copy link

@vercel vercel bot commented on c169c73 Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on c169c73 Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.