diff --git a/docs/content/scripts/tracking/reddit-pixel.md b/docs/content/scripts/tracking/reddit-pixel.md new file mode 100644 index 00000000..979d832f --- /dev/null +++ b/docs/content/scripts/tracking/reddit-pixel.md @@ -0,0 +1,145 @@ +--- +title: Reddit Pixel +description: Use Reddit Pixel in your Nuxt app. +links: +- label: Source + icon: i-simple-icons-github + to: https://github.com/nuxt/scripts/blob/main/src/runtime/registry/reddit-pixel.ts + size: xs +--- + +[Reddit Pixel](https://advertising.reddithelp.com/en/categories/custom-audiences-and-conversion-tracking/reddit-pixel) helps you track conversions and build audiences for your Reddit advertising campaigns. + +Nuxt Scripts provides a registry script composable `useScriptRedditPixel` to easily integrate Reddit Pixel in your Nuxt app. + +### Nuxt Config Setup + +The simplest way to load Reddit Pixel globally in your Nuxt App is to use Nuxt config. Alternatively you can directly +use the [useScriptRedditPixel](#useScriptRedditPixel) composable. + +If you don't plan to send custom events you can use the [Environment overrides](https://nuxt.com/docs/getting-started/configuration#environment-overrides) to +disable the script in development. + +::code-group + +```ts [Always enabled] +export default defineNuxtConfig({ + scripts: { + registry: { + redditPixel: { + id: 'YOUR_ID' + } + } + } +}) +``` + +```ts [Production only] +export default defineNuxtConfig({ + $production: { + scripts: { + registry: { + redditPixel: { + id: 'YOUR_ID', + } + } + } + } +}) +``` + +:: + +#### With Environment Variables + +If you prefer to configure your id using environment variables. + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + scripts: { + registry: { + redditPixel: true, + } + }, + // you need to provide a runtime config to access the environment variables + runtimeConfig: { + public: { + scripts: { + redditPixel: { + id: '', // NUXT_PUBLIC_SCRIPTS_REDDIT_PIXEL_ID + }, + }, + }, + }, +}) +``` + +```text [.env] +NUXT_PUBLIC_SCRIPTS_REDDIT_PIXEL_ID= +``` + +## useScriptRedditPixel + +The `useScriptRedditPixel` composable lets you have fine-grain control over when and how Reddit Pixel is loaded on your site. + +```ts +const { proxy } = useScriptRedditPixel({ + id: 'YOUR_ID' +}) +// example +proxy.rdt('track', 'Lead') +``` + +Please follow the [Registry Scripts](/docs/guides/registry-scripts) guide to learn more about advanced usage. + +### RedditPixelApi + +```ts +export interface RedditPixelApi { + rdt: RdtFns & { + sendEvent: (rdt: RedditPixelApi['rdt'], args: unknown[]) => void + callQueue: unknown[] + } +} +type RdtFns + = & ((event: 'init', id: string) => void) + & ((event: 'track', eventName: string) => void) +``` + +### Config Schema + +You must provide the options when setting up the script for the first time. + +```ts +export const RedditPixelOptions = object({ + id: string(), +}) +``` + +## Example + +Using Reddit Pixel only in production while using `rdt` to send a tracking event. + +::code-group + +```vue [TrackingButton.vue] + + + +``` + +:: \ No newline at end of file diff --git a/playground/pages/index.vue b/playground/pages/index.vue index fe059d1d..fa247a4d 100644 --- a/playground/pages/index.vue +++ b/playground/pages/index.vue @@ -26,6 +26,10 @@ const thirdParties = [ name: 'X Pixel', path: '/third-parties/x-pixel/nuxt-scripts', }, + { + name: 'Reddit Pixel', + path: '/third-parties/reddit-pixel/nuxt-scripts', + }, { name: 'Google Adsense', path: '/third-parties/google-adsense/nuxt-scripts', diff --git a/playground/pages/third-parties/reddit-pixel/default.vue b/playground/pages/third-parties/reddit-pixel/default.vue new file mode 100644 index 00000000..37e3822e --- /dev/null +++ b/playground/pages/third-parties/reddit-pixel/default.vue @@ -0,0 +1,22 @@ + + + diff --git a/playground/pages/third-parties/reddit-pixel/nuxt-scripts.vue b/playground/pages/third-parties/reddit-pixel/nuxt-scripts.vue new file mode 100644 index 00000000..65cd8133 --- /dev/null +++ b/playground/pages/third-parties/reddit-pixel/nuxt-scripts.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/registry.ts b/src/registry.ts index 58546d73..7fbcebda 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -121,6 +121,16 @@ export async function registry(resolve?: (path: string, opts?: ResolvePathOption from: await resolve('./runtime/registry/snapchat-pixel'), }, }, + { + label: 'Reddit Pixel', + src: 'https://www.redditstatic.com/ads/pixel.js', + category: 'tracking', + logo: ` `, + import: { + name: 'useScriptRedditPixel', + from: await resolve('./runtime/registry/reddit-pixel'), + }, + }, // ads { label: 'Google Adsense', diff --git a/src/runtime/registry/reddit-pixel.ts b/src/runtime/registry/reddit-pixel.ts new file mode 100644 index 00000000..3be1bf38 --- /dev/null +++ b/src/runtime/registry/reddit-pixel.ts @@ -0,0 +1,59 @@ +import type { UseScriptInput } from '@unhead/vue' +import { useRegistryScript } from '../utils' +import { object, string } from '#nuxt-scripts-validator' +import type { RegistryScriptInput } from '#nuxt-scripts/types' + +type RdtFns + = & ((event: 'init', id: string) => void) + & ((event: 'track', eventName: string) => void) + +export interface RedditPixelApi { + rdt: RdtFns & { + sendEvent: (rdt: RedditPixelApi['rdt'], args: unknown[]) => void + callQueue: unknown[] + } +} + +declare global { + interface Window extends RedditPixelApi {} +} + +export const RedditPixelOptions = object({ + id: string(), +}) +export type RedditPixelInput = RegistryScriptInput + +export function useScriptRedditPixel(_options?: RedditPixelInput) { + return useRegistryScript('redditPixel', (options) => { + return ({ + scriptInput: { + src: 'https://www.redditstatic.com/ads/pixel.js', + async: true, + } as UseScriptInput, + clientInit: import.meta.server + ? undefined + : () => { + const rdt = function (...args: unknown[]) { + if ((rdt as any).sendEvent) { + (rdt as any).sendEvent(rdt, args) + } + else { + (rdt as any).callQueue.push(args) + } + } as RedditPixelApi['rdt'] + ;(rdt as any).callQueue = [] + window.rdt = rdt + if (options?.id) { + rdt('init', options.id) + rdt('track', 'PageVisit') + } + }, + schema: import.meta.dev ? RedditPixelOptions : undefined, + scriptOptions: { + use() { + return { rdt: window.rdt } + }, + }, + }) + }, _options) +} diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 0c1bf40a..fec16d00 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -28,6 +28,7 @@ import type { GoogleAnalyticsInput } from './registry/google-analytics' import type { GoogleTagManagerInput } from './registry/google-tag-manager' import type { UmamiAnalyticsInput } from './registry/umami-analytics' import type { RybbitAnalyticsInput } from './registry/rybbit-analytics' +import type { RedditPixelInput } from './registry/reddit-pixel' import type { PayPalInput } from './registry/paypal' import { object } from '#nuxt-scripts-validator' @@ -143,6 +144,7 @@ export interface ScriptRegistry { paypal?: PayPalInput matomoAnalytics?: MatomoAnalyticsInput rybbitAnalytics?: RybbitAnalyticsInput + redditPixel?: RedditPixelInput segment?: SegmentInput stripe?: StripeInput xPixel?: XPixelInput