-
Notifications
You must be signed in to change notification settings - Fork 38
Hubspot #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hubspot #233
Conversation
Warning Rate limit exceeded@steven-tey has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 10 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughAdds a new HubSpot integration guide at Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User (Browser)
participant HS as HubSpot Form
participant D as Dub Analytics
rect rgba(200,230,255,0.20)
note over U,HS: HubSpot Forms — autofill hidden `dub_id` and submit
U->>U: Read `dub_id` cookie
HS->>U: Form embed loads
U->>HS: Populate hidden `dub_id` field when form ready
U->>HS: Submit form
HS-->>D: Lead submission includes `dub_id`
end
sequenceDiagram
autonumber
participant U as User (Browser)
participant HM as HubSpot Meetings Widget
participant D as Dub Analytics
rect rgba(220,255,220,0.20)
note over U,HM: Meetings Scheduler — deferred lead tracking via postMessage
HM->>U: postMessage on booking success
U->>U: Read `dub_id` cookie
U->>D: dubAnalytics.trackLead(clickId=dub_id, mode="deferred", event="Meeting scheduled", customerInfo)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
conversions/leads/hubspot.mdx (4)
22-22
: Grammar nits: pluralize “Form”.“HubSpot Form help…” → “HubSpot Forms help…”.
-HubSpot Form help you capture lead information and track conversions. +HubSpot Forms help you capture lead information and track conversions.
39-45
: Alt text doesn’t match image content.Use accurate, descriptive alt for accessibility.
- alt="Segment Dub (Actions) Mapping" + alt="HubSpot Dub Id contact property configuration"
55-62
: Alt text mismatch (second image).Same issue as above.
- alt="Segment Dub (Actions) Mapping" + alt="HubSpot form builder with hidden Dub Id field"
152-192
: Meetings postMessage: broaden origin check and harden tracking call.
- Events may originate from meetings.hubspot.com (new) and historically app.hubspot.com; allowlist both. (community.hubspot.com)
- Guard if dubAnalytics isn’t loaded to avoid runtime errors.
- Data shape shown (meetingsPayload.bookingResponse…) matches current community examples, but can change; keep defensive checks. (community.hubspot.com)
- window.addEventListener("message", function (event) { - // Check if the message is from the scheduling widget - if (event.origin === "https://meetings.hubspot.com") { + window.addEventListener("message", function (event) { + const allowedOrigins = ["https://meetings.hubspot.com", "https://app.hubspot.com"]; + if (!allowedOrigins.includes(event.origin)) { + return; + } const clickId = getCookie("dub_id"); @@ - if (data.meetingBookSucceeded) { + if (data && data.meetingBookSucceeded) { @@ - dubAnalytics.trackLead({ + if (typeof dubAnalytics?.trackLead !== "function") { + console.warn("dubAnalytics.trackLead unavailable. Skipping lead tracking."); + return; + } + dubAnalytics.trackLead({ clickId, mode: "deferred", eventName: "Meeting scheduled", customerExternalId: contact.email, customerName: customerName, customerEmail: contact.email, }); } - } - }); + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
images/conversions/hubspot/hubspot-dub-id-property.png
is excluded by!**/*.png
images/conversions/hubspot/hubspot-forms-setup.png
is excluded by!**/*.png
📒 Files selected for processing (2)
conversions/leads/hubspot.mdx
(1 hunks)docs.json
(2 hunks)
🔇 Additional comments (3)
docs.json (2)
76-78
: Approve — nav addition conversions/leads/hubspothubspot.mdx found at conversions/leads/hubspot.mdx; entry matches the new page path and will render correctly.
87-89
: Broken nav link: conversions/sales/hubspot is missing.File: docs.json — I could not confirm conversions/sales/hubspot.mdx exists (search produced no output); this nav entry will 404 and can break builds. Either remove the entry or add a stub/redirect.
- "conversions/sales/segment", - "conversions/sales/hubspot" + "conversions/sales/segment"conversions/leads/hubspot.mdx (1)
66-106
: Form embed snippet: wrong script URL, brittle form selection, and listener ordering.
- Use HubSpot’s supported v2 embed + hbspt.forms.create; register the hs-form-event:on-ready listener before creating the form and scope it to the specific form via HubSpotFormsV4.getFormFromEvent(event); call setFieldValue on the returned form instance instead of HubSpotFormsV4.getForms()[0].
- Confirmed code-fence label usage: ```html HTML appears at conversions/leads/hubspot.mdx:70 and conversions/sales/stripe.mdx:146 — CodeGroup uses this pattern elsewhere in the repo.
- <script src="https://js.hsforms.net/forms/embed/47839131.js" defer></script> - - <div - class="hs-form-frame" - data-region="na1" - data-form-id="YOUR_FORM_ID" - data-portal-id="YOUR_PORTAL_ID" - ></div> - - <script> + <div class="hs-form-frame"></div> + + <script> // A helper function to get the value of a cookie function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) { return parts.pop().split(";").shift(); } return null; } - // Listen for the form ready event - window.addEventListener("hs-form-event:on-ready", (event) => { - const clickId = getCookie("dub_id"); - - if (!clickId) { - console.debug("clickId not found. Skipping lead tracking."); - return; - } - - // Populate the hidden field with the dub_id - HubSpotFormsV4.getForms()[0].setFieldValue("0-1/dub_id", clickId); - }); + // Register the listener BEFORE creating the form + window.addEventListener("hs-form-event:on-ready", (event) => { + const clickId = getCookie("dub_id"); + if (!clickId) { + console.debug("clickId not found. Skipping lead tracking."); + return; + } + const form = HubSpotFormsV4.getFormFromEvent(event); + if (form) form.setFieldValue("0-1/dub_id", clickId); + }); </script> + <script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/embed/v2.js"></script> + <script> + hbspt.forms.create({ + region: "na1", // or "eu1" + portalId: "YOUR_PORTAL_ID", + formId: "YOUR_FORM_ID", + target: ".hs-form-frame", + }); + </script>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (6)
conversions/leads/hubspot.mdx (6)
22-23
: Grammar fix: pluralize “Form”.“HubSpot Form help…” → “HubSpot Forms help…”.
-HubSpot Form help you capture lead information and track conversions. By integrating with Dub, you can attribute each form submission back to the specific Dub link that drove the conversion. +HubSpot Forms help you capture lead information and track conversions. By integrating with Dub, you can attribute each form submission back to the specific Dub link that drove the conversion.
41-45
: Alt text mismatch (references Segment).Update alt text to describe the HubSpot property screenshot.
- alt="Segment Dub (Actions) Mapping" + alt="HubSpot Dub Id contact property settings"
56-62
: Alt text mismatch (references Segment).Update to reflect HubSpot form setup.
- alt="Segment Dub (Actions) Mapping" + alt="HubSpot form with hidden Dub Id field"
147-150
: Alt text tweak for accuracy.Clarify what the image shows.
- alt="Enabling conversion tracking for a workspace" + alt="Allowed Hostnames settings in Dub Analytics"
152-156
: Consistent terminology: “allowlist.”Use “allowlist” consistently.
- You can group your hostnames when adding them to the allow list: + You can group your hostnames when adding them to the allowlist:
235-243
: PII note (email/name) — add a brief consent reminder.Since email/name are sent client-side, add a one-line note about obtaining consent where required (GDPR/CCPA).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
conversions/leads/hubspot.mdx (5)
23-23
: Grammar: pluralize “Form”.Use “HubSpot Forms help you capture…” for subject-verb agreement and consistency with product naming.
-HubSpot Form help you capture lead information and track conversions. +HubSpot Forms help you capture lead information and track conversions.
41-45
: Alt text mismatch (accessibility).Alt references “Segment” but the image is for HubSpot. Update for accurate, descriptive alt text.
- alt="Segment Dub (Actions) Mapping" + alt="HubSpot contact property for Dub Id (single-line text)"
58-62
: Alt text mismatch (accessibility).Same issue here; adjust to describe the HubSpot form configuration.
- alt="Segment Dub (Actions) Mapping" + alt="HubSpot form builder with hidden Dub Id field mapped to contact property"
174-189
: Minor: code fence label.“
html HTML” may render oddly in some MDX renderers. Prefer just “
html” and use CodeGroup titles if supported.- ```html HTML + ```html
176-188
: Optional: add defensive init for analytics.If the script is blocked, the queue stub prevents errors, but add a simple ready check before calling methods outside this snippet.
- })(window, "dubAnalytics"); + })(window, "dubAnalytics"); + // Optional: verify queue exists + if (!window.dubAnalytics) window.dubAnalytics = function(){(window.dubAnalytics.q=window.dubAnalytics.q||[]).push(arguments)};
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
conversions/leads/hubspot.mdx
(1 hunks)docs.json
(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- docs.json
🔇 Additional comments (3)
conversions/leads/hubspot.mdx (3)
70-107
: Use official HubSpot Forms v2 embed and set hidden field in onFormReady.The snippet loads a nonstandard embed and uses a private API/path (
HubSpotFormsV4
,"0-1/dub_id"
), which is brittle and likely to break. Switch to//js.hsforms.net/forms/embed/v2.js
andhbspt.forms.create(...)
and set the input by name ononFormReady
.- <script src="https://js.hsforms.net/forms/embed/47839131.js" defer></script> - - <div - class="hs-form-frame" - data-region="na1" - data-form-id="YOUR_FORM_ID" - data-portal-id="YOUR_PORTAL_ID" - ></div> - - <script> - // A helper function to get the value of a cookie - function getCookie(name) { - const value = `; ${document.cookie}`; - const parts = value.split(`; ${name}=`); - - if (parts.length === 2) { - return parts.pop().split(";").shift(); - } - - return null; - } - - // Listen for the form ready event - window.addEventListener("hs-form-event:on-ready", (event) => { - const clickId = getCookie("dub_id"); - - if (!clickId) { - console.debug("clickId not found. Skipping lead tracking."); - return; - } - - // Populate the hidden field with the dub_id - HubSpotFormsV4.getForms()[0].setFieldValue("0-1/dub_id", clickId); - }); - </script> + <script charset="utf-8" type="text/javascript" src="//js.hsforms.net/forms/embed/v2.js" defer></script> + <div id="hubspotForm"></div> + <script> + function getCookie(name) { + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); + if (parts.length === 2) return parts.pop().split(";").shift(); + return null; + } + window.addEventListener("load", function () { + if (!window.hbspt || !hbspt.forms?.create) return; + hbspt.forms.create({ + region: "na1", + portalId: "YOUR_PORTAL_ID", + formId: "YOUR_FORM_ID", + target: "#hubspotForm", + onFormReady: function (formEl) { + const clickId = getCookie("dub_id"); + if (!clickId) return; + const fld = formEl.querySelector('input[name="dub_id"]'); + if (fld) fld.value = clickId; + }, + }); + }); + </script>
212-247
: Harden HubSpot Meetings postMessage handling; don’t rely onmeetingBookSucceeded
.Whitelist HubSpot origins (meetings/app), guard payload shape, and read contact from
meetingsPayload
. This avoids false positives and runtime errors.- // Listen for the message event - window.addEventListener("message", function (event) { - // Check if the message is from the scheduling widget - if (event.origin === "https://meetings.hubspot.com") { - const clickId = getCookie("dub_id"); - - // Get the data from the event - const data = event.data; - - if (data.meetingBookSucceeded) { - // Get the scheduled contact - const contact = - data.meetingsPayload.bookingResponse.postResponse.contact; - - if (!contact) { - console.debug("contact not found. Skipping lead tracking."); - return; - } - - // Track the lead with the scheduled contact - const customerName = [contact.firstName, contact.lastName] - .filter(Boolean) - .join(" "); - - dubAnalytics.trackLead({ - clickId, - mode: "deferred", - eventName: "Meeting scheduled", - customerExternalId: contact.email, - customerName: customerName, - customerEmail: contact.email, - }); - } - } - }); + // Listen for booking messages from HubSpot Meetings + window.addEventListener("message", function (event) { + const allowed = ["https://meetings.hubspot.com", "https://app.hubspot.com"]; + if (!allowed.includes(event.origin)) return; + const data = event.data && typeof event.data === "object" ? event.data : {}; + const contact = data?.meetingsPayload?.bookingResponse?.postResponse?.contact; + if (!contact?.email) return; + const clickId = getCookie("dub_id"); + const customerName = [contact.firstName, contact.lastName].filter(Boolean).join(" "); + dubAnalytics.trackLead({ + clickId, + mode: "deferred", + eventName: "Meeting scheduled", + customerExternalId: contact.email, + customerName, + customerEmail: contact.email, + }); + });
176-186
: Confirm Dub script attribute contract (“data-domains”) and script URL
- data-domains must be a JSON string. Supported keys: refer (used/required for partner / client-side click-tracking), site, outbound (string or array). The example data-domains='{"refer":"YOUR_SHORT_DOMAIN"}' is valid; you may prefer the full example: data-domains='{"refer":"refer.dub.co","site":"site.dub.co","outbound":["example.com","example.sh"]}'.
- Also supported: data-cookie-options (JSON) and data-query-param (optional, default "via"). JSON must be stringified inside the attribute.
- Verify script src — docs reference https://www.dubcdn.com/analytics/script.js (or variants like script.outbound-domains.js); the snippet’s https://dubcdn.com/analytics/script.conversion-tracking.js may be an older/different variant and should be confirmed/updated.
File: conversions/leads/hubspot.mdx Lines: 176-186
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
conversions/leads/client-side.mdx (1)
32-32
: Fix broken link — remove/docs
prefixReplace the site-rooted path in conversions/leads/client-side.mdx:32 (and conversions/sales/client-side.mdx:34) — change /docs/conversions/... to /conversions/.... If you intended the sales guide, use /conversions/sales/introduction.
-For more accurate conversion tracking, consider using [server-side conversion tracking](/docs/conversions/leads/introduction) +For more accurate conversion tracking, consider using [server-side conversion tracking](/conversions/leads/introduction)conversions/leads/next-auth.mdx (2)
34-67
: Fix undefined variables and cookie API usage in App Router example.
- user.* is referenced but undefined; should use message.user.*.
- cookies() is synchronous; remove await.
Apply this diff:
events: { async signIn(message) { // if it's a new sign up if (message.isNewUser) { - const cookieStore = await cookies(); + const cookieStore = cookies(); // check if dub_id cookie is present const dub_id = cookieStore.get("dub_id")?.value; if (dub_id) { // send lead event to Dub await dub.track.lead({ clickId: dub_id, eventName: "Sign Up", - customerExternalId: user.id, - customerName: user.name, - customerEmail: user.email, - customerAvatar: user.image, + customerExternalId: message.user.id, + customerName: message.user.name, + customerEmail: message.user.email, + customerAvatar: message.user.image, }); // delete the cookies - cookieStore.delete("dub_id"); - cookieStore.delete("dub_partner_data"); + cookieStore.delete("dub_id"); + cookieStore.delete("dub_partner_data"); } } }, },
75-98
: Fix undefined variables in Pages Router example.Replace user.* with message.user.* to match NextAuth event signature.
await dub.track.lead({ clickId: dub_id, eventName: "Sign Up", - customerExternalId: user.id, - customerName: user.name, - customerEmail: user.email, - customerAvatar: user.image, + customerExternalId: message.user.id, + customerName: message.user.name, + customerEmail: message.user.email, + customerAvatar: message.user.image, });conversions/leads/introduction.mdx (1)
99-107
: Fix Go example: add missing imports and use exported CustomerExternalId
- Add the missing "os" and "time" imports (os.Getenv is used by dub.WithSecurity; time.Unix is used when clearing the cookie).
- Replace unexported customerExternalId with exported CustomerExternalId (Go struct fields must be exported).
File: conversions/leads/introduction.mdx — imports block (lines 99–103), TrackLeadRequest block (lines 111–117), cookie deletion/time.Unix (~lines 118–121).-import ( - "context" - dub "github.com/dubinc/dub-go" - "net/http" -) +import ( + "context" + "net/http" + "os" + "time" + dub "github.com/dubinc/dub-go" +) - _, err = d.Track.Lead(context.Background(), &operations.TrackLeadRequest{ + _, err = d.Track.Lead(context.Background(), &operations.TrackLeadRequest{ ClickId: dubId.Value, EventName: "Sign Up", - customerExternalId: customer.ID, + CustomerExternalId: customer.ID, // matches exported field used elsewhere in Go examples CustomerName: customer.Name, CustomerEmail: customer.Email, CustomerAvatar: customer.Avatar, })
🧹 Nitpick comments (12)
snippets/conversion-tracking-prerequisites.mdx (2)
5-12
: Avoid duplicated “Prerequisites” headings across pages.Since the snippet includes “## Prerequisites”, any host page that also prints a “## Prerequisites” header will render duplicates. Either remove the header from the snippet or document that pages should not add their own header.
Apply one of these:
-## Prerequisites +<!-- Heading intentionally omitted; host pages provide context -->or standardize usage across pages to not add an extra “## Prerequisites” around this snippet.
9-9
: Tighten copy.“Then, you'd want to install …” → more direct: “Then install …”.
-Then, you'd want to install the `@dub/analytics` script to your website to track conversion events. +Then install the `@dub/analytics` script on your website to track conversion events.conversions/leads/segment.mdx (1)
110-112
: cookies() is synchronous in App Router.Remove await to avoid misleading example.
-const cookieStore = await cookies(); +const cookieStore = cookies();conversions/leads/auth0.mdx (1)
30-64
: TS types in a .js example; align filename or import.Either make the example TypeScript (route.ts) or drop the type-only import in JS.
-```typescript app/api/auth/[auth0]/route.js -import { handleAuth, handleCallback, type Session } from "@auth0/nextjs-auth0"; +```typescript app/api/auth/[auth0]/route.ts +import { handleAuth, handleCallback, type Session } from "@auth0/nextjs-auth0";Or, if keeping JS:
-```typescript app/api/auth/[auth0]/route.js +```js app/api/auth/[auth0]/route.js -import { handleAuth, handleCallback, type Session } from "@auth0/nextjs-auth0"; +import { handleAuth, handleCallback } from "@auth0/nextjs-auth0";conversions/sales/google-tag-manager.mdx (2)
12-15
: Grammar: singular agreement.“Conversion tracking require” → “Conversion tracking requires”.
- Conversion tracking require a [Business plan](https://dub.co/pricing) + Conversion tracking requires a [Business plan](https://dub.co/pricing)
77-77
: Use raw file URLs for direct template downloads.Leads GTM page uses raw.githubusercontent.com; align here for a one-click download.
-Download the [gtm-server-client-template/template.tpl](https://github.com/dubinc/gtm-server-client-template/blob/main/template.tpl) file and upload it to the Template Editor. You'll see a preview of the template: +Download the [gtm-server-client-template/template.tpl](https://raw.githubusercontent.com/dubinc/gtm-server-client-template/main/template.tpl) file and upload it to the Template Editor. You'll see a preview of the template:-Download the [gtm-server-tag-template/template.tpl](https://github.com/dubinc/gtm-server-tag-template/blob/main/template.tpl) file and upload it to the Template Editor. You'll see a preview of the template: +Download the [gtm-server-tag-template/template.tpl](https://raw.githubusercontent.com/dubinc/gtm-server-tag-template/main/template.tpl) file and upload it to the Template Editor. You'll see a preview of the template:Also applies to: 174-174
conversions/leads/clerk.mdx (4)
23-33
: Use React-friendly iframe attribute casing.CamelCase avoids JSX/TSX prop warnings.
- frameborder="0" + frameBorder="0" - referrerpolicy="strict-origin-when-cross-origin" + referrerPolicy="strict-origin-when-cross-origin" - allowfullscreen + allowFullScreen
48-50
: Fix token URL.Use the canonical Dub dashboard tokens URL.
- # get it here: https://d.to/tokens + # get it here: https://app.dub.co/settings/tokens
95-110
: Commented fetch example: make callback async or drop await.Minor consistency nit to prevent copy-paste errors.
- }).then(res => { + }).then(async (res) => { if (res.ok) await user.reload(); else console.error(res.statusText); });
161-163
: cookies() is synchronous in Server Actions.Remove await to match Next.js API.
- const cookieStore = await cookies(); + const cookieStore = cookies();snippets/enable-conversion-tracking.mdx (2)
12-13
: Duplicate sentence in Option 1.Remove the repeated line.
Apply this diff:
- To enable conversion tracking for all future links in a workspace, you can do the following: -To enable conversion tracking for all future links in a workspace, you can do the following: + To enable conversion tracking for all future links in a workspace, you can do the following:
1-1
: Microcopy tighten (optional).Slightly crisper intro.
Apply this diff:
-First, you'll need to enable conversion tracking for your Dub links to be able to start tracking conversions. +First, enable conversion tracking on your Dub links to start recording conversions.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
images/conversions/hubspot/installed-hubspot-integration.png
is excluded by!**/*.png
📒 Files selected for processing (28)
conversions/leads/appwrite.mdx
(1 hunks)conversions/leads/auth0.mdx
(1 hunks)conversions/leads/better-auth.mdx
(1 hunks)conversions/leads/clerk.mdx
(1 hunks)conversions/leads/client-side.mdx
(1 hunks)conversions/leads/google-tag-manager.mdx
(3 hunks)conversions/leads/hubspot.mdx
(1 hunks)conversions/leads/introduction.mdx
(2 hunks)conversions/leads/next-auth.mdx
(1 hunks)conversions/leads/segment.mdx
(1 hunks)conversions/leads/supabase.mdx
(1 hunks)conversions/quickstart.mdx
(1 hunks)conversions/sales/client-side.mdx
(1 hunks)conversions/sales/google-tag-manager.mdx
(2 hunks)conversions/sales/introduction.mdx
(1 hunks)conversions/sales/segment.mdx
(2 hunks)conversions/sales/shopify.mdx
(1 hunks)conversions/sales/stripe.mdx
(1 hunks)partners/quickstart.mdx
(1 hunks)sdks/client-side/features/conversion-tracking.mdx
(2 hunks)sdks/client-side/installation-guides/shopify.mdx
(2 hunks)snippets/client-side-tracking-install.mdx
(2 hunks)snippets/conversion-tracking-prerequisites.mdx
(1 hunks)snippets/dub-client-install.mdx
(2 hunks)snippets/enable-conversion-tracking.mdx
(1 hunks)snippets/leads-intro.mdx
(1 hunks)snippets/leads-prerequisites.mdx
(0 hunks)snippets/sales-prerequisites.mdx
(0 hunks)
💤 Files with no reviewable changes (2)
- snippets/sales-prerequisites.mdx
- snippets/leads-prerequisites.mdx
✅ Files skipped from review due to trivial changes (5)
- conversions/sales/stripe.mdx
- snippets/client-side-tracking-install.mdx
- conversions/sales/client-side.mdx
- sdks/client-side/installation-guides/shopify.mdx
- conversions/sales/shopify.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
- conversions/leads/hubspot.mdx
🔇 Additional comments (24)
snippets/leads-intro.mdx (1)
9-9
: Bullet update looks good.“Booking a demo meeting” is a clearer lead example.
partners/quickstart.mdx (1)
81-81
: Verify new docs path.Confirm that /partners/embedded-referrals exists and is the intended destination for the “whitelabeled referral dashboard” link. If not, update to the correct route.
conversions/leads/client-side.mdx (2)
21-24
: Quickstart section addition reads well.Good placement after install steps; keeps the flow clear.
25-34
: Helpful limitations warning.Nice callout on client-side tracking caveats.
conversions/quickstart.mdx (1)
2-2
: Title change: check nav and inbound links.After renaming to “Conversion tracking”, verify docs.json/nav entries and any inbound links/redirects to the former “Quickstart” title still resolve correctly.
conversions/leads/appwrite.mdx (2)
9-9
: Switched to shared prerequisites snippet.Import path looks correct.
Ensure no extra “Prerequisites” header is present on this page to avoid duplication with the snippet’s own header.
17-17
: Snippet usage LGTM.Placement before provider‑specific steps is consistent with other guides.
conversions/sales/introduction.mdx (2)
9-9
: Consolidated to ConversionTrackingPrerequisites.Good move to centralize content.
Confirm there’s no local “Prerequisites” header around this snippet to prevent duplicate headings.
17-17
: Usage placement is correct.Reads naturally before “Configure sale tracking.”
conversions/leads/supabase.mdx (2)
9-9
: Updated import to shared prerequisites.Looks correct and aligns with the broader migration.
Check for any remaining references to LeadsPrerequisites in this repo to avoid drift.
17-17
: Snippet placement LGTM.Right before provider configuration; consistent across leads guides.
conversions/leads/google-tag-manager.mdx (2)
9-11
: Switch to shared prerequisites snippet looks good.Import + usage of ConversionTrackingPrerequisites is consistent with the new snippet approach.
Please confirm the snippet exports a default component and that the docs build resolves “/snippets/conversion-tracking-prerequisites.mdx”.
Also applies to: 17-17
55-55
: No-op content change.Whitespace-only change; nothing to review.
Also applies to: 142-142
conversions/leads/better-auth.mdx (1)
10-10
: Prerequisites snippet migration LGTM.Import path and component usage match the new shared snippet.
Ensure the page order still renders as intended after inserting the shared prerequisites section.
Also applies to: 18-18
conversions/leads/next-auth.mdx (2)
9-9
: Prerequisites snippet migration LGTM.Consistent with other guides adopting the shared prerequisites.
Also applies to: 17-17
34-67
: Cookie deletion semantics caution.Deleting cookies via cookies() works in Route Handlers/Server Actions, but within NextAuth event context it may not persist. Consider deleting in the response (e.g., via a follow-up Route Handler/API route) after successful lead tracking.
Also applies to: 69-98
conversions/leads/segment.mdx (1)
9-9
: Prerequisites snippet migration LGTM.Matches the standardized pattern.
Also applies to: 17-17
conversions/leads/auth0.mdx (1)
9-9
: Prerequisites snippet migration LGTM.Import and usage look correct.
Also applies to: 17-17
conversions/sales/google-tag-manager.mdx (1)
8-8
: Prerequisites snippet migration LGTM.Consistent with the leads guides.
Also applies to: 24-24
sdks/client-side/features/conversion-tracking.mdx (1)
7-7
: Quickstart insertion LGTM.EnableConversionTracking import and placement before install section reads well.
Confirm the horizontal rule (“---”) renders as intended in your MDX theme.
Also applies to: 44-49
conversions/leads/clerk.mdx (1)
9-9
: Prerequisites snippet migration LGTM.Import and usage are consistent with other guides.
Also applies to: 17-17
conversions/sales/segment.mdx (1)
8-8
: Good consolidation to shared prerequisites; confirm build and heading nesting.
- Path and export look right; verify the snippet exists and doesn’t duplicate an H2 already on this page.
- After switching to the shared snippet, double-check any references like “first two steps” still make sense.
Also applies to: 17-17
conversions/leads/introduction.mdx (1)
9-9
: Consistent prerequisites across leads pages—nice.Looks correct; please confirm the shared snippet’s copy is lead‑appropriate (no sales‑only phrasing) and that TOC anchors remain stable.
Also applies to: 18-18
snippets/dub-client-install.mdx (1)
8-9
: Card props change to self‑closing horizontal variants—verify component API and a11y.
- Ensure Card supports the horizontal prop without children.
- Confirm accessible names remain (title as aria-label) and no SEO content was lost with removal of descriptions.
Also applies to: 14-15, 33-34, 39-40, 45-46, 51-52, 53-58
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (9)
snippets/leads-attributes.mdx (5)
6-6
: Verify cross-reference and tighten phrasing
- Confirm the parameter name and path: “
leadEventName
prop in/track/sale
”. If there’s a canonical doc for sale tracking, link it.- Slightly clearer wording.
-| `eventName` | **Yes** | The name of the lead event to track. Can also be used as a unique identifier to associate a given lead event for a customer for a subsequent sale event (via the `leadEventName` prop in `/track/sale`). | +| `eventName` | **Yes** | The name of the lead event to track. Can also serve as a unique identifier to tie this lead to a subsequent sale event (via the `leadEventName` parameter on `/track/sale`). |
7-7
: Call out uniqueness scope forcustomerExternalId
Readers need to know if this must be unique per workspace/account and if it’s immutable.
-| `customerExternalId` | **Yes** | The unique ID of the customer in your system. Will be used to identify and attribute all future events to this customer. | +| `customerExternalId` | **Yes** | The unique ID of the customer in your system (must be unique per workspace). Used to identify and attribute all future events to this customer. |
8-10
: Small wording nits and optional guardrails for PII/URLs
- Prefer “If omitted” to “If not passed.”
- Consider noting expected formats/normalization (e.g., lowercasing emails, HTTPS-only avatar URLs), if enforced.
-| `customerName` | No | The name of the customer. If not passed, a random name will be generated (e.g. "Big Red Caribou"). | +| `customerName` | No | The name of the customer. If omitted, a random name will be generated (e.g., "Big Red Caribou"). |For
customerEmail
andcustomerAvatar
, add format expectations only if they’re validated at the API boundary.
12-12
: Clarifymetadata
type and limitsSpecify the accepted shape (e.g., JSON object), size enforcement (stringified length vs. total of values), and truncation/error behavior.
Example edit (adjust if inaccurate):
-| `metadata` | No | Additional metadata to be stored with the lead event. Max 10,000 characters. | +| `metadata` | No | Additional JSON metadata to store with the lead event (object). Limit: 10,000 characters when stringified. Payloads exceeding the limit are rejected or truncated (confirm behavior). |
5-5
: Clarify “Required” vs deferred behavior; tighten grammarFile: snippets/leads-attributes.mdx Lines: 5-5
Make explicit that clickId is required except when tracking deferred lead events; fix two small grammar issues.
-| `clickId` | **Yes** | The unique ID of the click that the lead conversion event is attributed to. You can read this value from `dub_id` cookie. If an empty string is provided (i.e. if you're using [tracking a deferred lead event](/conversions/leads/deferred)), Dub will try to find an existing customer with the provided `customerExternalId` and use the `clickId` from the customer if found. | +| `clickId` | **Yes*** | The unique ID of the click that the lead conversion event is attributed to. You can read this value from the `dub_id` cookie. When [tracking a deferred lead event](/conversions/leads/deferred), you may pass an empty string; Dub will try to find an existing customer with the provided `customerExternalId` and reuse that customer’s `clickId` if found. |If you leave “Yes” unchanged, add a short footnote below the table explaining the deferred-case exception.
conversions/leads/deferred.mdx (4)
14-14
: Grammar nit: “times when”, not “times where”.Replace “there are times where” with “there are times when” for correctness.
-However, there are times where signups alone might not be the clearest indicator of a lead conversion event. +However, there are times when signups alone might not be the clearest indicator of a lead conversion event.
40-41
: Call out SDK-specific casing differences.Parameter casing differs across SDKs (e.g., customerExternalId vs external_id). Add a one‑line note before the examples to reduce copy/paste errors.
To do this, you'll need to set the `mode` property to `deferred` when tracking the lead event. With this, Dub will still track the customer and the click ID they came from, but defer the actual lead event creation to a subsequent request. +Note: SDKs use language‑idiomatic casing (e.g., JavaScript: `customerExternalId`; Python/Ruby: `external_id`). Use the field names shown in the snippet for your language.
49-65
: Framework-specific cookie API; clarify context or show two variants.
req.cookies[...]
/res.cookies.set(...)
is not Express‑standard (Express usesreq.cookies
/res.cookie
). Either clarify this is Next.js App Router or show both variants.-const dubId = req.cookies["dub_id"]; -// ... -res.cookies.set("dub_id", "", { +// Next.js App Router: +const dubId = req.cookies?.get?.("dub_id")?.value; +// ... +res.cookies.set("dub_id", "", { expires: new Date(0), }); +// Express: +// const dubId = req.cookies?.dub_id; +// res.cookie("dub_id", "", { expires: new Date(0) });
121-129
: Ruby: namespace/gem mismatch.
require 'dub'
but instantiates::OpenApiSDK::Dub
. Confirm the correct gem and namespace. If the gem exposesDub
, avoid theOpenApiSDK
namespace; otherwise, require the appropriate gem.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
conversions/leads/deferred.mdx
(1 hunks)conversions/leads/hubspot.mdx
(1 hunks)conversions/leads/introduction.mdx
(3 hunks)docs.json
(1 hunks)snippets/enable-conversion-tracking.mdx
(1 hunks)snippets/leads-attributes.mdx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- conversions/leads/hubspot.mdx
- docs.json
- conversions/leads/introduction.mdx
- snippets/enable-conversion-tracking.mdx
🔇 Additional comments (2)
snippets/leads-attributes.mdx (2)
3-4
: Table structure LGTMHeader and alignment look consistent with the rest of the docs.
11-11
: Document defaultmode
and clarifyclickId
relationshipFile: snippets/leads-attributes.mdx Lines: 11-11
-| `mode` | No | The mode to use for tracking the lead event. `async` will not block the request; `wait` will block the request until the lead event is fully recorded in Dub; `deferred` will defer the lead event creation to a subsequent request. | +| `mode` | No | The mode to use for tracking the lead event. Default: `async`. `async` does not block the request; `wait` blocks until the lead is fully recorded in Dub; `deferred` defers lead creation to a subsequent request (often used with `clickId=""`). |Consider documenting timeout/latency expectations for
wait
.
dub_id = request.cookies.get('dub_id') | ||
if dub_id: | ||
dub.track.lead({ | ||
'click_id': dub_id, | ||
'mode': 'deferred', | ||
'event_name': 'Sign Up', | ||
'external_id': customer.id, | ||
'customer_name': customer.name, | ||
'customer_email': customer.email, | ||
'customer_avatar': customer.avatar | ||
}) | ||
# delete the dub_id cookie | ||
response.delete_cookie('dub_id') | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python: undefined response
and framework ambiguity.
response.delete_cookie('dub_id')
references an undefined variable. Provide a concrete example (e.g., Flask) or remove the line and add a comment to delete the cookie using the framework’s response object.
-dub.track.lead({
+res = dub.track.lead({
'click_id': dub_id,
'mode': 'deferred',
'event_name': 'Sign Up',
'external_id': customer.id,
'customer_name': customer.name,
'customer_email': customer.email,
'customer_avatar': customer.avatar
})
-# delete the dub_id cookie
-response.delete_cookie('dub_id')
+# delete the dub_id cookie using your framework's response:
+# Flask example:
+# from flask import make_response
+# resp = make_response(...)
+# resp.delete_cookie('dub_id')
🤖 Prompt for AI Agents
In conversions/leads/deferred.mdx around lines 73 to 86, the code calls
response.delete_cookie('dub_id') but response is undefined and the framework is
ambiguous; fix by using a concrete framework pattern (for example, in Flask
create/use the response object returned by make_response or the view return and
call response.delete_cookie('dub_id') before returning) or remove that line and
replace it with a short comment telling the caller to delete the 'dub_id' cookie
using the framework's response object.
import ( | ||
"context" | ||
dub "github.com/dubinc/dub-go" | ||
"net/http" | ||
) | ||
|
||
d := dub.New( | ||
dub.WithSecurity(os.Getenv("DUB_API_KEY")), | ||
) | ||
|
||
dubId, err := r.Cookie("dub_id") | ||
if err == nil { | ||
_, err = d.Track.Lead(context.Background(), &operations.TrackLeadRequest{ | ||
ClickId: dubId.Value, | ||
Mode: "deferred", | ||
EventName: "Sign Up", | ||
customerExternalId: customer.ID, | ||
CustomerName: customer.Name, | ||
CustomerEmail: customer.Email, | ||
CustomerAvatar: customer.Avatar, | ||
}) | ||
// delete the dub_id cookie | ||
http.SetCookie(w, &http.Cookie{ | ||
Name: "dub_id", | ||
Value: "", | ||
Expires: time.Unix(0, 0), | ||
}) | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Verification inconclusive
Go: missing imports, undefined operations
, and likely wrong struct field casing.
- Missing imports: os, time, and models/operations.
operations
package is used but not imported.- Field
customerExternalId
is unexported; Go structs typically export asCustomerExternalID
(verify actual SDK). - Uses
r
/w
without showing handler context; add a brief comment.
-import (
- "context"
- dub "github.com/dubinc/dub-go"
- "net/http"
-)
+import (
+ "context"
+ "net/http"
+ "os"
+ "time"
+ dub "github.com/dubinc/dub-go"
+ "github.com/dubinc/dub-go/models/operations"
+)
@@
- _, err = d.Track.Lead(context.Background(), &operations.TrackLeadRequest{
+ _, err = d.Track.Lead(context.Background(), &operations.TrackLeadRequest{
ClickId: dubId.Value,
Mode: "deferred",
EventName: "Sign Up",
- customerExternalId: customer.ID,
- CustomerName: customer.Name,
- CustomerEmail: customer.Email,
- CustomerAvatar: customer.Avatar,
+ // Verify exact field name in the SDK:
+ // CustomerExternalID: customer.ID,
+ CustomerName: customer.Name,
+ CustomerEmail: customer.Email,
+ CustomerAvatar: customer.Avatar,
})
@@
- http.SetCookie(w, &http.Cookie{
+ // In an http.HandlerFunc(w http.ResponseWriter, r *http.Request):
+ http.SetCookie(w, &http.Cookie{
Name: "dub_id",
Value: "",
Expires: time.Unix(0, 0),
})
To confirm field names and package paths, please verify against the current dub-go SDK docs.
Go: missing imports, wrong SDK type, and unexported field usage
- Add imports: os, time, and the operations package (github.com/dubinc/dub-go/models/operations). (github.com)
- Use the SDK request body type: replace operations.TrackLeadRequest with operations.TrackLeadRequestBody (Track.Lead expects *operations.TrackLeadRequestBody). (pkg.go.dev)
- Replace the unexported JSON-style field (customerExternalId) with the SDK's exported field(s) — e.g., ClickID and the SDK's exported external-ID field (CustomerExternalID / ExternalID). Verify the exact field name in the SDK before committing. (dub.co)
- Ensure the snippet is inside an http.Handler (w http.ResponseWriter, r *http.Request) since r/w are used but not shown.
🤖 Prompt for AI Agents
In conversions/leads/deferred.mdx around lines 91-119, the snippet is missing
imports, using the wrong SDK request type, and referencing an unexported field;
add imports for os and time and the operations package
(github.com/dubinc/dub-go/models/operations), change operations.TrackLeadRequest
to the SDK request body type operations.TrackLeadRequestBody (Track.Lead expects
*operations.TrackLeadRequestBody), replace the unexported customerExternalId
field with the SDK's exported external ID field (confirm and use the exact
exported name such as CustomerExternalID or ExternalID), and ensure this code is
placed inside an http.Handler function signature (w http.ResponseWriter, r
*http.Request) so r and w are defined before committing.
$request->customerExternalId = $customer->id; | ||
$request->customerNasme = $customer->name; | ||
$request->customerEmail = $customer->email; | ||
$request->customerAvatar = $customer->avatar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP: typo customerNasme
→ customerName
.
This will silently drop the name in most SDKs. Fix the property.
- $request->customerNasme = $customer->name;
+ $request->customerName = $customer->name;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
$request->customerExternalId = $customer->id; | |
$request->customerNasme = $customer->name; | |
$request->customerEmail = $customer->email; | |
$request->customerAvatar = $customer->avatar; | |
$request->customerExternalId = $customer->id; | |
$request->customerName = $customer->name; | |
$request->customerEmail = $customer->email; | |
$request->customerAvatar = $customer->avatar; |
🤖 Prompt for AI Agents
In conversions/leads/deferred.mdx around lines 164 to 167, there's a typo
setting $request->customerNasme which will drop the name; change that property
to $request->customerName to match the intended field and the surrounding
properties so the customer's name is correctly passed.
d := dub.New( | ||
dub.WithSecurity(os.Getenv("DUB_API_KEY")), | ||
) | ||
|
||
d.Track.Lead(context.Background(), &operations.TrackLeadRequest{ | ||
ClickId: "", | ||
EventName: "Sign Up", | ||
customerExternalId: customer.ID, | ||
CustomerName: customer.Name, | ||
CustomerEmail: customer.Email, | ||
CustomerAvatar: customer.Avatar, | ||
}) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Verification inconclusive
Go (Step 2): same issues as Step 1.
Add missing imports for os
(used above if applicable) and operations
, and verify struct field casing for customer external ID.
-import (
- "context"
- dub "github.com/dubinc/dub-go"
- "net/http"
-)
+import (
+ "context"
+ dub "github.com/dubinc/dub-go"
+ "github.com/dubinc/dub-go/models/operations"
+)
@@
-d.Track.Lead(context.Background(), &operations.TrackLeadRequest{
+d.Track.Lead(context.Background(), &operations.TrackLeadRequest{
ClickId: "",
EventName: "Sign Up",
- customerExternalId: customer.ID,
+ // CustomerExternalID: customer.ID, // verify exact name in SDK
CustomerName: customer.Name,
CustomerEmail: customer.Email,
CustomerAvatar: customer.Avatar,
})
Go (Step 2): add imports and fix Track.Lead example
- File: conversions/leads/deferred.mdx (lines 223–235) — add missing imports and correct the Go SDK types/fields.
- Imports: add "os" and "github.com/dubinc/dub-go/models/operations".
- Replace the example payload with the SDK request type and exported fields (use TrackLeadRequestBody and PascalCase fields):
- Use &operations.TrackLeadRequestBody{ ClickID: "", EventName: "Sign Up", CustomerExternalID: customer.ID, CustomerName: customer.Name, CustomerEmail: customer.Email, CustomerAvatar: customer.Avatar }.
🤖 Prompt for AI Agents
In conversions/leads/deferred.mdx around lines 223 to 235, the Go example is
missing imports and uses incorrect SDK types/field names; add imports "os" and
"github.com/dubinc/dub-go/models/operations" at the top of the snippet, replace
the payload with the correct SDK request type and exported PascalCase fields by
using &operations.TrackLeadRequestBody{ ClickID: "", EventName: "Sign Up",
CustomerExternalID: customer.ID, CustomerName: customer.Name, CustomerEmail:
customer.Email, CustomerAvatar: customer.Avatar }, and ensure the dub.New call
uses dub.WithSecurity(os.Getenv("DUB_API_KEY")) as shown.
$request->customerExternalId = $customer->id; | ||
$request->customerNasme = $customer->name; | ||
$request->customerEmail = $customer->email; | ||
$request->customerAvatar = $customer->avatar; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP: repeated typo customerNasme
→ customerName
.
Fix in Step 2 as well.
-$request->customerNasme = $customer->name;
+$request->customerName = $customer->name;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
$request->customerExternalId = $customer->id; | |
$request->customerNasme = $customer->name; | |
$request->customerEmail = $customer->email; | |
$request->customerAvatar = $customer->avatar; | |
$request->customerExternalId = $customer->id; | |
$request->customerName = $customer->name; | |
$request->customerEmail = $customer->email; | |
$request->customerAvatar = $customer->avatar; |
🤖 Prompt for AI Agents
In conversions/leads/deferred.mdx around lines 271 to 274, there's a typo
assigning $request->customerNasme; change it to $request->customerName, and
similarly update the same typo occurrence in Step 2 of the document; ensure both
assignments use customerName exactly and leave the other properties
(customerExternalId, customerEmail, customerAvatar) unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
conversions/quickstart.mdx (3)
15-16
: Grammar: subject–verb agreement.“Conversion tracking require” → “Conversion tracking requires”.
Apply this diff:
- Conversion tracking require a [Business plan](https://dub.co/pricing) + Conversion tracking requires a [Business plan](https://dub.co/pricing)
38-38
: Grammar: tense consistency.“detects … and storing” → “detects … and stores”.
Apply this diff:
-This script detects the `dub_id` query parameter and storing it as a first-party cookie, which will be used to attribute subsequent conversion events to the original link. +This script detects the `dub_id` query parameter and stores it as a first-party cookie, which will be used to attribute subsequent conversion events to the original link.
22-26
: Optional: improve image alt text for accessibility/SEO.Consider a more descriptive alt, e.g., “Screenshot of Dub conversion analytics dashboard” rather than “Conversion analytics”.
Apply this diff:
- alt="Conversion analytics" + alt="Screenshot of the Dub conversion analytics dashboard"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
conversions/quickstart.mdx
(1 hunks)
🔇 Additional comments (2)
conversions/quickstart.mdx (2)
28-28
: LGTM on intro sentence.Clear and sets context well.
7-12
: Snippet imports resolve — no action required.All referenced /snippets/*.mdx files exist under ./snippets and contain MDX/JSX content; the imports in conversions/quickstart.mdx match those files.
Summary by CodeRabbit