Skip to content

Commit dadef00

Browse files
authored
Merge pull request #2902 from Dokploy/feat/add-cloud-tracking
feat(tracking): integrate HubSpot tracking functionality and reintrod…
2 parents a0868ad + 2cda982 commit dadef00

File tree

3 files changed

+150
-3
lines changed

3 files changed

+150
-3
lines changed

packages/server/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ export * from "./utils/backups/postgres";
6868
export * from "./utils/backups/utils";
6969
export * from "./utils/backups/web-server";
7070
export * from "./utils/builders/compose";
71-
export * from "./utils/startup/cancell-deployments";
7271
export * from "./utils/builders/docker-file";
7372
export * from "./utils/builders/drop";
7473
export * from "./utils/builders/heroku";
@@ -77,7 +76,6 @@ export * from "./utils/builders/nixpacks";
7776
export * from "./utils/builders/paketo";
7877
export * from "./utils/builders/static";
7978
export * from "./utils/builders/utils";
80-
8179
export * from "./utils/cluster/upload";
8280
export * from "./utils/databases/rebuild";
8381
export * from "./utils/docker/collision";
@@ -113,6 +111,8 @@ export * from "./utils/providers/raw";
113111
export * from "./utils/schedules/index";
114112
export * from "./utils/schedules/utils";
115113
export * from "./utils/servers/remote-docker";
114+
export * from "./utils/startup/cancell-deployments";
115+
export * from "./utils/tracking/hubspot";
116116
export * from "./utils/traefik/application";
117117
export * from "./utils/traefik/domain";
118118
export * from "./utils/traefik/file-types";

packages/server/src/lib/auth.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { db } from "../db";
1010
import * as schema from "../db/schema";
1111
import { getUserByToken } from "../services/admin";
1212
import { updateUser } from "../services/user";
13+
import { getHubSpotUTK, submitToHubSpot } from "../utils/tracking/hubspot";
1314
import { sendEmail } from "../verification/send-verification-email";
1415
import { getPublicIpWithFallback } from "../wss/utils";
1516

@@ -115,7 +116,7 @@ const { handler, api } = betterAuth({
115116
}
116117
}
117118
},
118-
after: async (user) => {
119+
after: async (user, context) => {
119120
const isAdminPresent = await db.query.member.findFirst({
120121
where: eq(schema.member.role, "owner"),
121122
});
@@ -126,6 +127,27 @@ const { handler, api } = betterAuth({
126127
});
127128
}
128129

130+
if (IS_CLOUD) {
131+
try {
132+
const hutk = getHubSpotUTK(
133+
context?.request?.headers?.get("cookie") || undefined,
134+
);
135+
const hubspotSuccess = await submitToHubSpot(
136+
{
137+
email: user.email,
138+
firstName: user.name,
139+
lastName: user.name,
140+
},
141+
hutk,
142+
);
143+
if (!hubspotSuccess) {
144+
console.error("Failed to submit to HubSpot");
145+
}
146+
} catch (error) {
147+
console.error("Error submitting to HubSpot", error);
148+
}
149+
}
150+
129151
if (IS_CLOUD || !isAdminPresent) {
130152
await db.transaction(async (tx) => {
131153
const organization = await tx
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
interface HubSpotFormField {
2+
objectTypeId: string;
3+
name: string;
4+
value: string;
5+
}
6+
7+
interface HubSpotFormData {
8+
fields: HubSpotFormField[];
9+
context: {
10+
pageUri: string;
11+
pageName: string;
12+
hutk?: string; // HubSpot UTK from cookies
13+
};
14+
}
15+
16+
interface SignUpFormData {
17+
firstName?: string;
18+
lastName?: string;
19+
email?: string;
20+
}
21+
22+
/**
23+
* Extract HubSpot UTK (User Token) from cookies
24+
* This is used for tracking and attribution in HubSpot
25+
*/
26+
export function getHubSpotUTK(cookieHeader?: string): string | null {
27+
if (!cookieHeader) return null;
28+
29+
const name = "hubspotutk=";
30+
const decodedCookie = decodeURIComponent(cookieHeader);
31+
const cookieArray = decodedCookie.split(";");
32+
33+
for (let i = 0; i < cookieArray.length; i++) {
34+
const cookie = cookieArray[i]?.trim();
35+
if (!cookie) continue;
36+
if (cookie.indexOf(name) === 0) {
37+
return cookie.substring(name.length, cookie.length);
38+
}
39+
}
40+
return null;
41+
}
42+
43+
/**
44+
* Convert contact form data to HubSpot form format
45+
*/
46+
export function formatContactDataForHubSpot(
47+
contactData: SignUpFormData,
48+
hutk?: string | null,
49+
): HubSpotFormData {
50+
const formData: HubSpotFormData = {
51+
fields: [
52+
{
53+
objectTypeId: "0-1", // Contact object type
54+
name: "firstname",
55+
value: contactData.firstName || "",
56+
},
57+
{
58+
objectTypeId: "0-1",
59+
name: "lastname",
60+
value: contactData.lastName || "",
61+
},
62+
{
63+
objectTypeId: "0-1",
64+
name: "email",
65+
value: contactData.email || "",
66+
},
67+
],
68+
context: {
69+
pageUri: "https://app.dokploy.com/register",
70+
pageName: "Sign Up",
71+
},
72+
};
73+
74+
// Add HubSpot UTK if available
75+
if (hutk) {
76+
formData.context.hutk = hutk;
77+
}
78+
79+
return formData;
80+
}
81+
82+
/**
83+
* Submit form data to HubSpot Forms API
84+
*/
85+
export async function submitToHubSpot(
86+
contactData: SignUpFormData,
87+
hutk?: string | null,
88+
): Promise<boolean> {
89+
try {
90+
const portalId = process.env.HUBSPOT_PORTAL_ID;
91+
const formGuid = process.env.HUBSPOT_FORM_GUID;
92+
93+
if (!portalId || !formGuid) {
94+
console.error(
95+
"HubSpot configuration missing: HUBSPOT_PORTAL_ID or HUBSPOT_FORM_GUID not set",
96+
);
97+
return false;
98+
}
99+
100+
const formData = formatContactDataForHubSpot(contactData, hutk);
101+
const response = await fetch(
102+
`https://api.hsforms.com/submissions/v3/integration/submit/${portalId}/${formGuid}`,
103+
{
104+
method: "POST",
105+
headers: {
106+
"Content-Type": "application/json",
107+
},
108+
body: JSON.stringify(formData),
109+
},
110+
);
111+
112+
if (!response.ok) {
113+
const errorText = await response.text();
114+
console.error("HubSpot API error:", response.status, errorText);
115+
return false;
116+
}
117+
118+
const result = await response.json();
119+
console.log("HubSpot submission successful:", result);
120+
return true;
121+
} catch (error) {
122+
console.error("Error submitting to HubSpot:", error);
123+
return false;
124+
}
125+
}

0 commit comments

Comments
 (0)