From 2e2625a6cdbf9a22e17953886ae92d9a4a340a1b Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 04:09:04 +0000 Subject: [PATCH 1/5] Update conversions/leads/supabase.mdx --- conversions/leads/supabase.mdx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/conversions/leads/supabase.mdx b/conversions/leads/supabase.mdx index 93333106..419d4d24 100644 --- a/conversions/leads/supabase.mdx +++ b/conversions/leads/supabase.mdx @@ -18,9 +18,11 @@ In this guide, we will be focusing on tracking new user sign-ups for a SaaS appl ## Configure Supabase -Next, configure Supabase to track lead conversion events in the auth callback function. +Next, configure Supabase to track lead conversion events. The implementation depends on your authentication flow: -Here's how it works in a nutshell: +### For OAuth and email verification flows + +For OAuth providers (Google, GitHub, etc.) and email signup with verification enabled, use the `/api/auth/callback` route: 1. In the `/api/auth/callback` route, check if: - the `dub_id` cookie is present. @@ -28,6 +30,12 @@ Here's how it works in a nutshell: 2. If the `dub_id` cookie is present and the user is a new sign up, send a lead event to Dub using `dub.track.lead` 3. Delete the `dub_id` cookie. +### For email signup without verification + + +The `/auth/callback` route handles most authentication conditions **except** normal user signup with email when email verification is disabled. For this flow, you need to add tracking code directly to your signup page. + + ```typescript Next.js App Router From d29c91f93e023dae1b92acef95af105e36e23069 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 04:09:31 +0000 Subject: [PATCH 2/5] Update conversions/leads/supabase.mdx --- conversions/leads/supabase.mdx | 191 +++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/conversions/leads/supabase.mdx b/conversions/leads/supabase.mdx index 419d4d24..7f2da5e9 100644 --- a/conversions/leads/supabase.mdx +++ b/conversions/leads/supabase.mdx @@ -36,6 +36,197 @@ For OAuth providers (Google, GitHub, etc.) and email signup with verification en The `/auth/callback` route handles most authentication conditions **except** normal user signup with email when email verification is disabled. For this flow, you need to add tracking code directly to your signup page. +When email verification is disabled, users are immediately signed in after signup without going through the `/auth/callback` route. Add the tracking code directly to your signup form handler: + + + +```typescript Client-side signup form +// components/signup-form.tsx +import { useState } from 'react'; +import { createClient } from '@/lib/supabase/client'; +import { dub } from '@/lib/dub'; + +export function SignupForm() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [loading, setLoading] = useState(false); + + const supabase = createClient(); + + const handleSignup = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + + try { + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) throw error; + + // Track the lead conversion if signup was successful + if (data.user) { + const dubId = document.cookie + .split('; ') + .find(row => row.startsWith('dub_id=')) + ?.split('=')[1]; + + if (dubId) { + await dub.track.lead({ + clickId: dubId, + eventName: 'Sign Up', + customerExternalId: data.user.id, + customerEmail: data.user.email, + customerName: data.user.user_metadata?.name, + customerAvatar: data.user.user_metadata?.avatar_url, + }); + + // Delete the dub_id cookie + document.cookie = 'dub_id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'; + } + } + } catch (error) { + console.error('Signup error:', error); + } finally { + setLoading(false); + } + }; + + return ( +
+ setEmail(e.target.value)} + placeholder="Email" + required + /> + setPassword(e.target.value)} + placeholder="Password" + required + /> + +
+ ); +} +``` + +```typescript Server action (App Router) +// app/actions/auth.ts +'use server'; + +import { cookies } from 'next/headers'; +import { createClient } from '@/lib/supabase/server'; +import { dub } from '@/lib/dub'; +import { redirect } from 'next/navigation'; + +export async function signUp(formData: FormData) { + const email = formData.get('email') as string; + const password = formData.get('password') as string; + + const supabase = createClient(cookies()); + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) { + throw new Error(error.message); + } + + // Track the lead conversion if signup was successful + if (data.user) { + const dubId = cookies().get('dub_id')?.value; + + if (dubId) { + await dub.track.lead({ + clickId: dubId, + eventName: 'Sign Up', + customerExternalId: data.user.id, + customerEmail: data.user.email, + customerName: data.user.user_metadata?.name, + customerAvatar: data.user.user_metadata?.avatar_url, + }); + + // Delete the dub_id cookie + cookies().delete('dub_id'); + } + } + + redirect('/dashboard'); +} +``` + +```typescript API route (Pages Router) +// pages/api/auth/signup.ts +import { NextApiRequest, NextApiResponse } from 'next'; +import { createClient } from '@supabase/supabase-js'; +import { dub } from '@/lib/dub'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== 'POST') { + return res.status(405).json({ error: 'Method not allowed' }); + } + + const { email, password } = req.body; + + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.SUPABASE_SERVICE_ROLE_KEY! + ); + + try { + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) throw error; + + // Track the lead conversion if signup was successful + if (data.user) { + const { dub_id } = req.cookies; + + if (dub_id) { + await dub.track.lead({ + clickId: dub_id, + eventName: 'Sign Up', + customerExternalId: data.user.id, + customerEmail: data.user.email, + customerName: data.user.user_metadata?.name, + customerAvatar: data.user.user_metadata?.avatar_url, + }); + + // Delete the dub_id cookie + res.setHeader( + 'Set-Cookie', + 'dub_id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT' + ); + } + } + + res.status(200).json({ user: data.user }); + } catch (error) { + res.status(400).json({ error: error.message }); + } +} +``` + +
+ +## Auth callback implementation + +For OAuth and email verification flows, implement the `/auth/callback` route: + ```typescript Next.js App Router From adce6e8690caf714ddc0377a19ebae5d54d388d0 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 04:25:58 +0000 Subject: [PATCH 3/5] Update conversions/leads/supabase.mdx --- conversions/leads/supabase.mdx | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/conversions/leads/supabase.mdx b/conversions/leads/supabase.mdx index 7f2da5e9..5ff87f7d 100644 --- a/conversions/leads/supabase.mdx +++ b/conversions/leads/supabase.mdx @@ -44,7 +44,6 @@ When email verification is disabled, users are immediately signed in after signu // components/signup-form.tsx import { useState } from 'react'; import { createClient } from '@/lib/supabase/client'; -import { dub } from '@/lib/dub'; export function SignupForm() { const [email, setEmail] = useState(''); @@ -65,27 +64,9 @@ export function SignupForm() { if (error) throw error; - // Track the lead conversion if signup was successful - if (data.user) { - const dubId = document.cookie - .split('; ') - .find(row => row.startsWith('dub_id=')) - ?.split('=')[1]; - - if (dubId) { - await dub.track.lead({ - clickId: dubId, - eventName: 'Sign Up', - customerExternalId: data.user.id, - customerEmail: data.user.email, - customerName: data.user.user_metadata?.name, - customerAvatar: data.user.user_metadata?.avatar_url, - }); - - // Delete the dub_id cookie - document.cookie = 'dub_id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'; - } - } + // For lead tracking, use one of the server-side approaches below + // The dub.track.lead SDK only works on the server side + } catch (error) { console.error('Signup error:', error); } finally { From f70104794ee0fb8212651b1c66747edd073c9f9d Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 04:29:52 +0000 Subject: [PATCH 4/5] Update conversions/leads/supabase.mdx --- conversions/leads/supabase.mdx | 182 +-------------------------------- 1 file changed, 2 insertions(+), 180 deletions(-) diff --git a/conversions/leads/supabase.mdx b/conversions/leads/supabase.mdx index 5ff87f7d..e4cd7d07 100644 --- a/conversions/leads/supabase.mdx +++ b/conversions/leads/supabase.mdx @@ -20,9 +20,9 @@ In this guide, we will be focusing on tracking new user sign-ups for a SaaS appl Next, configure Supabase to track lead conversion events. The implementation depends on your authentication flow: -### For OAuth and email verification flows +## Auth callback implementation -For OAuth providers (Google, GitHub, etc.) and email signup with verification enabled, use the `/api/auth/callback` route: +For OAuth providers (Google, GitHub, etc.) and email signup with verification enabled, implement the `/auth/callback` route: 1. In the `/api/auth/callback` route, check if: - the `dub_id` cookie is present. @@ -30,184 +30,6 @@ For OAuth providers (Google, GitHub, etc.) and email signup with verification en 2. If the `dub_id` cookie is present and the user is a new sign up, send a lead event to Dub using `dub.track.lead` 3. Delete the `dub_id` cookie. -### For email signup without verification - - -The `/auth/callback` route handles most authentication conditions **except** normal user signup with email when email verification is disabled. For this flow, you need to add tracking code directly to your signup page. - - -When email verification is disabled, users are immediately signed in after signup without going through the `/auth/callback` route. Add the tracking code directly to your signup form handler: - - - -```typescript Client-side signup form -// components/signup-form.tsx -import { useState } from 'react'; -import { createClient } from '@/lib/supabase/client'; - -export function SignupForm() { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [loading, setLoading] = useState(false); - - const supabase = createClient(); - - const handleSignup = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - - try { - const { data, error } = await supabase.auth.signUp({ - email, - password, - }); - - if (error) throw error; - - // For lead tracking, use one of the server-side approaches below - // The dub.track.lead SDK only works on the server side - - } catch (error) { - console.error('Signup error:', error); - } finally { - setLoading(false); - } - }; - - return ( -
- setEmail(e.target.value)} - placeholder="Email" - required - /> - setPassword(e.target.value)} - placeholder="Password" - required - /> - -
- ); -} -``` - -```typescript Server action (App Router) -// app/actions/auth.ts -'use server'; - -import { cookies } from 'next/headers'; -import { createClient } from '@/lib/supabase/server'; -import { dub } from '@/lib/dub'; -import { redirect } from 'next/navigation'; - -export async function signUp(formData: FormData) { - const email = formData.get('email') as string; - const password = formData.get('password') as string; - - const supabase = createClient(cookies()); - const { data, error } = await supabase.auth.signUp({ - email, - password, - }); - - if (error) { - throw new Error(error.message); - } - - // Track the lead conversion if signup was successful - if (data.user) { - const dubId = cookies().get('dub_id')?.value; - - if (dubId) { - await dub.track.lead({ - clickId: dubId, - eventName: 'Sign Up', - customerExternalId: data.user.id, - customerEmail: data.user.email, - customerName: data.user.user_metadata?.name, - customerAvatar: data.user.user_metadata?.avatar_url, - }); - - // Delete the dub_id cookie - cookies().delete('dub_id'); - } - } - - redirect('/dashboard'); -} -``` - -```typescript API route (Pages Router) -// pages/api/auth/signup.ts -import { NextApiRequest, NextApiResponse } from 'next'; -import { createClient } from '@supabase/supabase-js'; -import { dub } from '@/lib/dub'; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method !== 'POST') { - return res.status(405).json({ error: 'Method not allowed' }); - } - - const { email, password } = req.body; - - const supabase = createClient( - process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.SUPABASE_SERVICE_ROLE_KEY! - ); - - try { - const { data, error } = await supabase.auth.signUp({ - email, - password, - }); - - if (error) throw error; - - // Track the lead conversion if signup was successful - if (data.user) { - const { dub_id } = req.cookies; - - if (dub_id) { - await dub.track.lead({ - clickId: dub_id, - eventName: 'Sign Up', - customerExternalId: data.user.id, - customerEmail: data.user.email, - customerName: data.user.user_metadata?.name, - customerAvatar: data.user.user_metadata?.avatar_url, - }); - - // Delete the dub_id cookie - res.setHeader( - 'Set-Cookie', - 'dub_id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT' - ); - } - } - - res.status(200).json({ user: data.user }); - } catch (error) { - res.status(400).json({ error: error.message }); - } -} -``` - -
- -## Auth callback implementation - -For OAuth and email verification flows, implement the `/auth/callback` route: - ```typescript Next.js App Router From 0d5a46559589fa6aa8dbacf74ed3203722ea2e13 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 04:30:11 +0000 Subject: [PATCH 5/5] Update conversions/leads/supabase.mdx --- conversions/leads/supabase.mdx | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/conversions/leads/supabase.mdx b/conversions/leads/supabase.mdx index e4cd7d07..cc2c4d1f 100644 --- a/conversions/leads/supabase.mdx +++ b/conversions/leads/supabase.mdx @@ -139,6 +139,122 @@ export default async function handler( +## Email signup without verification + + +The `/auth/callback` route handles most authentication conditions **except** normal user signup with email when email verification is disabled. For this flow, you need to add tracking code directly to your signup page. + + +When email verification is disabled, users are immediately signed in after signup without going through the `/auth/callback` route. Add the tracking code directly to your signup form handler: + + + +```typescript Server action (App Router) +// app/actions/auth.ts +'use server'; + +import { cookies } from 'next/headers'; +import { createClient } from '@/lib/supabase/server'; +import { dub } from '@/lib/dub'; +import { redirect } from 'next/navigation'; + +export async function signUp(formData: FormData) { + const email = formData.get('email') as string; + const password = formData.get('password') as string; + + const supabase = createClient(cookies()); + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) { + throw new Error(error.message); + } + + // Track the lead conversion if signup was successful + if (data.user) { + const dubId = cookies().get('dub_id')?.value; + + if (dubId) { + await dub.track.lead({ + clickId: dubId, + eventName: 'Sign Up', + customerExternalId: data.user.id, + customerEmail: data.user.email, + customerName: data.user.user_metadata?.name, + customerAvatar: data.user.user_metadata?.avatar_url, + }); + + // Delete the dub_id cookie + cookies().delete('dub_id'); + } + } + + redirect('/dashboard'); +} +``` + +```typescript API route (Pages Router) +// pages/api/auth/signup.ts +import { NextApiRequest, NextApiResponse } from 'next'; +import { createClient } from '@supabase/supabase-js'; +import { dub } from '@/lib/dub'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + if (req.method !== 'POST') { + return res.status(405).json({ error: 'Method not allowed' }); + } + + const { email, password } = req.body; + + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.SUPABASE_SERVICE_ROLE_KEY! + ); + + try { + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) throw error; + + // Track the lead conversion if signup was successful + if (data.user) { + const { dub_id } = req.cookies; + + if (dub_id) { + await dub.track.lead({ + clickId: dub_id, + eventName: 'Sign Up', + customerExternalId: data.user.id, + customerEmail: data.user.email, + customerName: data.user.user_metadata?.name, + customerAvatar: data.user.user_metadata?.avatar_url, + }); + + // Delete the dub_id cookie + res.setHeader( + 'Set-Cookie', + 'dub_id=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT' + ); + } + } + + res.status(200).json({ user: data.user }); + } catch (error) { + res.status(400).json({ error: error.message }); + } +} +``` + + + ## Example App