@se-studio/hubspot 17.4.1 → 17.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +12 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tracking/HubSpotAnalyticsAdapter.d.ts +30 -1
- package/dist/tracking/HubSpotAnalyticsAdapter.d.ts.map +1 -1
- package/dist/tracking/HubSpotAnalyticsAdapter.js +60 -9
- package/dist/tracking/HubSpotAnalyticsAdapter.js.map +1 -1
- package/dist/tracking/createHubSpotBootstrapScript.d.ts +3 -2
- package/dist/tracking/createHubSpotBootstrapScript.d.ts.map +1 -1
- package/dist/tracking/createHubSpotBootstrapScript.js +8 -4
- package/dist/tracking/createHubSpotBootstrapScript.js.map +1 -1
- package/docs/llms.md +10 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @se-studio/hubspot
|
|
2
2
|
|
|
3
|
+
## 17.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @se-studio/core-ui@1.35.2
|
|
8
|
+
|
|
9
|
+
## 17.5.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- f1656f5: Assert HubSpot official third-party banner consent (`disableHubSpotCookieBanner` + `_hsp.setHubSpotConsent`) from `HubSpotAnalyticsAdapter` on every initialize and consent change. Mirror analytics to all three categories by default; keep `_hsq.doNotTrack` as opt-in via `hardDoNotTrack`.
|
|
14
|
+
|
|
3
15
|
## 17.4.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -25,6 +25,15 @@ pnpm add @se-studio/hubspot
|
|
|
25
25
|
|
|
26
26
|
## Analytics (with GTM)
|
|
27
27
|
|
|
28
|
+
`HubSpotAnalyticsAdapter` implements HubSpot’s [third-party consent banner API](https://developers.hubspot.com/docs/api-reference/latest/account/settings/consent-banner/consent-banner-api):
|
|
29
|
+
|
|
30
|
+
1. Sets `window.disableHubSpotCookieBanner = true` **before** injecting `js.hs-scripts.com`
|
|
31
|
+
2. Pushes `_hsp.setHubSpotConsent({ analytics, advertisement, functionality })` on every `initialize` / `updateConsent` (HubSpot does **not** persist this — re-assert every page / change)
|
|
32
|
+
3. By default mirrors analytics consent to all three categories; pass `resolveHubSpotConsent` or `updateConsent({ advertising })` for explicit flags
|
|
33
|
+
4. `_hsq.doNotTrack` is **opt-in** via `hardDoNotTrack: true` (stricter than official decline — blocks anonymized page views)
|
|
34
|
+
|
|
35
|
+
`ConsentAwareAdapter({ syncConsent: true })` already forwards analytics into `updateConsent`, so HubSpot category sync runs inside the HubSpot adapter when `getConsent` / `updateConsent` is used.
|
|
36
|
+
|
|
28
37
|
```tsx
|
|
29
38
|
import { AnalyticsPageTracker, AnalyticsProvider, CompositeAnalyticsAdapter, ConsentAwareAdapter, GoogleTagManagerAdapter, createConsentGetter } from '@se-studio/core-ui';
|
|
30
39
|
import { AbTestReporter } from '@se-studio/ab-testing/components';
|
|
@@ -48,6 +57,7 @@ const adapter = new ConsentAwareAdapter(
|
|
|
48
57
|
new HubSpotAnalyticsAdapter({
|
|
49
58
|
portalId: process.env.HUBSPOT_PORTAL_ID!,
|
|
50
59
|
getConsent: hasConsent,
|
|
60
|
+
// Optional: hardDoNotTrack: true — also pushes `_hsq.doNotTrack` (zero anonymized hits)
|
|
51
61
|
}),
|
|
52
62
|
]),
|
|
53
63
|
'analytics',
|
|
@@ -56,7 +66,8 @@ const adapter = new ConsentAwareAdapter(
|
|
|
56
66
|
);
|
|
57
67
|
adapter.initialize();
|
|
58
68
|
|
|
59
|
-
// layout.tsx — before HubSpot script loads (no args = SSG-safe; uses window.location.pathname)
|
|
69
|
+
// layout.tsx — before HubSpot script loads (no args = SSG-safe; uses window.location.pathname).
|
|
70
|
+
// Bootstrap also sets `disableHubSpotCookieBanner` and initialises `_hsp` / `_hsq`.
|
|
60
71
|
<Script id="hubspot-bootstrap" strategy="beforeInteractive"
|
|
61
72
|
dangerouslySetInnerHTML={{ __html: createHubSpotBootstrapScript() }} />
|
|
62
73
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,6 @@ export { classifyHubspotFormAnalyticsError, hubspotFormAnalyticsIdentity, useHub
|
|
|
7
7
|
export { HUBSPOT_MIN_SUBMIT_MS, HUBSPOT_SUBMIT_TOO_FAST_MESSAGE, isHubspotSubmitTooFast, } from './forms/submitGuard';
|
|
8
8
|
export type { HubspotFieldResponse, HubspotFormClassNames, HubspotFormContext, HubspotFormDefinition, HubspotFormExternalData, HubspotFormSubmissionResponse, } from './forms/types';
|
|
9
9
|
export { createHubSpotBootstrapScript } from './tracking/createHubSpotBootstrapScript';
|
|
10
|
-
export type { HubSpotAnalyticsAdapterConfig } from './tracking/HubSpotAnalyticsAdapter';
|
|
10
|
+
export type { HubSpotAnalyticsAdapterConfig, HubSpotConsentCategories, } from './tracking/HubSpotAnalyticsAdapter';
|
|
11
11
|
export { HubSpotAnalyticsAdapter } from './tracking/HubSpotAnalyticsAdapter';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,sBAAsB,EACtB,kBAAkB,EAClB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EACL,iCAAiC,EACjC,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,sBAAsB,EACtB,kBAAkB,EAClB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EACL,iCAAiC,EACjC,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,YAAY,EACV,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,sBAAsB,EACtB,kBAAkB,EAClB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EACL,iCAAiC,EACjC,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EACL,kCAAkC,EAClC,sBAAsB,EACtB,kBAAkB,EAClB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EACL,iCAAiC,EACjC,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AAKvF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
|
|
@@ -2,8 +2,16 @@ import type { AnalyticsAdapter, AnalyticsConsentState, ClickTrackingProperties,
|
|
|
2
2
|
declare global {
|
|
3
3
|
interface Window {
|
|
4
4
|
_hsq?: unknown[][];
|
|
5
|
+
_hsp?: unknown[][];
|
|
6
|
+
disableHubSpotCookieBanner?: boolean;
|
|
5
7
|
}
|
|
6
8
|
}
|
|
9
|
+
/** HubSpot third-party banner categories (`setHubSpotConsent`). */
|
|
10
|
+
export interface HubSpotConsentCategories {
|
|
11
|
+
analytics: boolean;
|
|
12
|
+
advertisement: boolean;
|
|
13
|
+
functionality: boolean;
|
|
14
|
+
}
|
|
7
15
|
export interface HubSpotAnalyticsAdapterConfig {
|
|
8
16
|
portalId: string;
|
|
9
17
|
/** Map analytics event names to HubSpot behavioural event names. */
|
|
@@ -14,21 +22,42 @@ export interface HubSpotAnalyticsAdapterConfig {
|
|
|
14
22
|
* When provided, `initialize()` does not inject the HubSpot script and
|
|
15
23
|
* `track*` does not push `_hsq` events while this returns false.
|
|
16
24
|
* Omit it for unchanged behaviour (script loads, events fire).
|
|
25
|
+
* Consent categories are still asserted via `_hsp.setHubSpotConsent`.
|
|
17
26
|
*/
|
|
18
27
|
getConsent?: () => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* When true, a deny also pushes `_hsq.doNotTrack` (blocks anonymized page
|
|
30
|
+
* views). Default `false`: official third-party banner path uses only
|
|
31
|
+
* `setHubSpotConsent`.
|
|
32
|
+
*/
|
|
33
|
+
hardDoNotTrack?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Explicit HubSpot category mapping. When omitted, analytics consent is
|
|
36
|
+
* mirrored to `analytics`, `advertisement`, and `functionality`.
|
|
37
|
+
* `advertising` from `updateConsent` is passed through when present.
|
|
38
|
+
*/
|
|
39
|
+
resolveHubSpotConsent?: (input: {
|
|
40
|
+
analytics: boolean;
|
|
41
|
+
advertising?: boolean;
|
|
42
|
+
}) => HubSpotConsentCategories;
|
|
19
43
|
}
|
|
20
44
|
export declare class HubSpotAnalyticsAdapter implements AnalyticsAdapter {
|
|
21
45
|
private initialized;
|
|
22
46
|
private readonly config;
|
|
23
47
|
/** Last explicit `updateConsent` analytics flag. Default allow when unset. */
|
|
24
48
|
private allowedFromUpdate;
|
|
49
|
+
private lastAdvertising;
|
|
25
50
|
private doNotTrackSent;
|
|
26
51
|
constructor(config: HubSpotAnalyticsAdapterConfig);
|
|
27
52
|
private isAllowed;
|
|
53
|
+
private resolveCategories;
|
|
54
|
+
private assertHubSpotConsent;
|
|
28
55
|
private sendDoNotTrack;
|
|
56
|
+
private injectTrackingScript;
|
|
29
57
|
initialize(): void;
|
|
30
58
|
/**
|
|
31
|
-
*
|
|
59
|
+
* Asserts HubSpot category consent via `_hsp.setHubSpotConsent`.
|
|
60
|
+
* `analytics: false` optionally pushes `_hsq.doNotTrack` when `hardDoNotTrack`.
|
|
32
61
|
* `analytics: true` allows `initialize()` to load the script on a later grant.
|
|
33
62
|
*/
|
|
34
63
|
updateConsent(consent: AnalyticsConsentState): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HubSpotAnalyticsAdapter.d.ts","sourceRoot":"","sources":["../../src/tracking/HubSpotAnalyticsAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"HubSpotAnalyticsAdapter.d.ts","sourceRoot":"","sources":["../../src/tracking/HubSpotAnalyticsAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QACnB,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QACnB,0BAA0B,CAAC,EAAE,OAAO,CAAC;KACtC;CACF;AAED,mEAAmE;AACnE,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,oFAAoF;IACpF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE;QAC9B,SAAS,EAAE,OAAO,CAAC;QACnB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,KAAK,wBAAwB,CAAC;CAChC;AAyDD,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,8EAA8E;IAC9E,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,cAAc,CAAS;IAE/B,YAAY,MAAM,EAAE,6BAA6B,EAEhD;IAED,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,oBAAoB;IAoB5B,UAAU,IAAI,IAAI,CAoBjB;IAED;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAqBlD;IAED,OAAO,CAAC,UAAU;IAQlB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,sBAAsB,GAAG,IAAI,CAMhE;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAgBnE;IAED,UAAU,CAAC,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAwBpD;CACF"}
|
|
@@ -6,6 +6,27 @@ function pushHsq(args) {
|
|
|
6
6
|
window._hsq = window._hsq || [];
|
|
7
7
|
window._hsq.push(args);
|
|
8
8
|
}
|
|
9
|
+
function pushHsp(args) {
|
|
10
|
+
if (typeof window === 'undefined') {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
window._hsp = window._hsp || [];
|
|
14
|
+
window._hsp.push(args);
|
|
15
|
+
}
|
|
16
|
+
function disableHubSpotBanner() {
|
|
17
|
+
if (typeof window === 'undefined') {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
window.disableHubSpotCookieBanner = true;
|
|
21
|
+
}
|
|
22
|
+
function defaultHubSpotConsent(input) {
|
|
23
|
+
const advertisement = input.advertising ?? input.analytics;
|
|
24
|
+
return {
|
|
25
|
+
analytics: input.analytics,
|
|
26
|
+
advertisement,
|
|
27
|
+
functionality: input.analytics,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
9
30
|
function getHubspotEventName(event, properties, eventNameMap) {
|
|
10
31
|
const fromProps = properties.hubspotEvent ||
|
|
11
32
|
properties.hubspot_event;
|
|
@@ -23,6 +44,7 @@ export class HubSpotAnalyticsAdapter {
|
|
|
23
44
|
config;
|
|
24
45
|
/** Last explicit `updateConsent` analytics flag. Default allow when unset. */
|
|
25
46
|
allowedFromUpdate = true;
|
|
47
|
+
lastAdvertising;
|
|
26
48
|
doNotTrackSent = false;
|
|
27
49
|
constructor(config) {
|
|
28
50
|
this.config = config;
|
|
@@ -33,24 +55,33 @@ export class HubSpotAnalyticsAdapter {
|
|
|
33
55
|
}
|
|
34
56
|
return this.allowedFromUpdate;
|
|
35
57
|
}
|
|
58
|
+
resolveCategories(analytics) {
|
|
59
|
+
const input = {
|
|
60
|
+
analytics,
|
|
61
|
+
advertising: this.lastAdvertising,
|
|
62
|
+
};
|
|
63
|
+
if (this.config.resolveHubSpotConsent) {
|
|
64
|
+
return this.config.resolveHubSpotConsent(input);
|
|
65
|
+
}
|
|
66
|
+
return defaultHubSpotConsent(input);
|
|
67
|
+
}
|
|
68
|
+
assertHubSpotConsent(analytics) {
|
|
69
|
+
disableHubSpotBanner();
|
|
70
|
+
pushHsp(['setHubSpotConsent', this.resolveCategories(analytics)]);
|
|
71
|
+
}
|
|
36
72
|
sendDoNotTrack() {
|
|
37
|
-
if (this.doNotTrackSent || !this.initialized) {
|
|
73
|
+
if (!this.config.hardDoNotTrack || this.doNotTrackSent || !this.initialized) {
|
|
38
74
|
return;
|
|
39
75
|
}
|
|
40
76
|
pushHsq(['doNotTrack']);
|
|
41
77
|
this.doNotTrackSent = true;
|
|
42
78
|
}
|
|
43
|
-
|
|
44
|
-
if (typeof window === 'undefined' || this.initialized) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (!this.isAllowed()) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
79
|
+
injectTrackingScript() {
|
|
50
80
|
const { portalId } = this.config;
|
|
51
81
|
if (!portalId) {
|
|
52
82
|
return;
|
|
53
83
|
}
|
|
84
|
+
disableHubSpotBanner();
|
|
54
85
|
const scriptId = 'hs-script-loader';
|
|
55
86
|
if (!document.getElementById(scriptId)) {
|
|
56
87
|
const script = document.createElement('script');
|
|
@@ -61,11 +92,27 @@ export class HubSpotAnalyticsAdapter {
|
|
|
61
92
|
script.src = `https://js.hs-scripts.com/${portalId}.js`;
|
|
62
93
|
document.head.appendChild(script);
|
|
63
94
|
}
|
|
95
|
+
}
|
|
96
|
+
initialize() {
|
|
97
|
+
if (typeof window === 'undefined' || this.initialized) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const allowed = this.isAllowed();
|
|
101
|
+
// HubSpot does not persist third-party consent — re-assert every load.
|
|
102
|
+
this.assertHubSpotConsent(allowed);
|
|
103
|
+
if (!allowed) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!this.config.portalId) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.injectTrackingScript();
|
|
64
110
|
this.initialized = true;
|
|
65
111
|
this.doNotTrackSent = false;
|
|
66
112
|
}
|
|
67
113
|
/**
|
|
68
|
-
*
|
|
114
|
+
* Asserts HubSpot category consent via `_hsp.setHubSpotConsent`.
|
|
115
|
+
* `analytics: false` optionally pushes `_hsq.doNotTrack` when `hardDoNotTrack`.
|
|
69
116
|
* `analytics: true` allows `initialize()` to load the script on a later grant.
|
|
70
117
|
*/
|
|
71
118
|
updateConsent(consent) {
|
|
@@ -73,6 +120,10 @@ export class HubSpotAnalyticsAdapter {
|
|
|
73
120
|
return;
|
|
74
121
|
}
|
|
75
122
|
this.allowedFromUpdate = consent.analytics;
|
|
123
|
+
if (consent.advertising !== undefined) {
|
|
124
|
+
this.lastAdvertising = consent.advertising;
|
|
125
|
+
}
|
|
126
|
+
this.assertHubSpotConsent(consent.analytics);
|
|
76
127
|
if (!consent.analytics) {
|
|
77
128
|
this.sendDoNotTrack();
|
|
78
129
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HubSpotAnalyticsAdapter.js","sourceRoot":"","sources":["../../src/tracking/HubSpotAnalyticsAdapter.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"HubSpotAnalyticsAdapter.js","sourceRoot":"","sources":["../../src/tracking/HubSpotAnalyticsAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Inline script for beforeInteractive: initialises _hsq
|
|
3
|
-
*
|
|
2
|
+
* Inline script for beforeInteractive: initialises `_hsq` / `_hsp`, disables
|
|
3
|
+
* HubSpot's own cookie banner, and sets the path before the HubSpot tracking
|
|
4
|
+
* script loads (SPA Mode B + third-party CMP).
|
|
4
5
|
*
|
|
5
6
|
* Call with no args in root layouts (SSG-safe): uses `window.location.pathname`
|
|
6
7
|
* at script execution time. Pass an explicit pathname only for tests or rare cases.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createHubSpotBootstrapScript.d.ts","sourceRoot":"","sources":["../../src/tracking/createHubSpotBootstrapScript.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"createHubSpotBootstrapScript.d.ts","sourceRoot":"","sources":["../../src/tracking/createHubSpotBootstrapScript.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAatE"}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Inline script for beforeInteractive: initialises _hsq
|
|
3
|
-
*
|
|
2
|
+
* Inline script for beforeInteractive: initialises `_hsq` / `_hsp`, disables
|
|
3
|
+
* HubSpot's own cookie banner, and sets the path before the HubSpot tracking
|
|
4
|
+
* script loads (SPA Mode B + third-party CMP).
|
|
4
5
|
*
|
|
5
6
|
* Call with no args in root layouts (SSG-safe): uses `window.location.pathname`
|
|
6
7
|
* at script execution time. Pass an explicit pathname only for tests or rare cases.
|
|
7
8
|
*/
|
|
8
9
|
export function createHubSpotBootstrapScript(pathname) {
|
|
10
|
+
const bannerAndQueues = `window.disableHubSpotCookieBanner = true;
|
|
11
|
+
var _hsp = window._hsp = window._hsp || [];
|
|
12
|
+
var _hsq = window._hsq = window._hsq || [];`;
|
|
9
13
|
if (pathname === undefined) {
|
|
10
|
-
return
|
|
14
|
+
return `${bannerAndQueues}
|
|
11
15
|
_hsq.push(['setPath', window.location.pathname]);`;
|
|
12
16
|
}
|
|
13
17
|
const safePath = pathname.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
14
|
-
return
|
|
18
|
+
return `${bannerAndQueues}
|
|
15
19
|
_hsq.push(['setPath', '${safePath}']);`;
|
|
16
20
|
}
|
|
17
21
|
//# sourceMappingURL=createHubSpotBootstrapScript.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createHubSpotBootstrapScript.js","sourceRoot":"","sources":["../../src/tracking/createHubSpotBootstrapScript.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"createHubSpotBootstrapScript.js","sourceRoot":"","sources":["../../src/tracking/createHubSpotBootstrapScript.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAAC,QAAiB;IAC5D,MAAM,eAAe,GAAG;;4CAEkB,CAAC;IAE3C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,GAAG,eAAe;kDACqB,CAAC;IACjD,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACtE,OAAO,GAAG,eAAe;yBACF,QAAQ,MAAM,CAAC;AACxC,CAAC"}
|
package/docs/llms.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| Import | Contents |
|
|
6
6
|
|--------|----------|
|
|
7
|
-
| `@se-studio/hubspot` | `HubSpotAnalyticsAdapter`, `createHubSpotBootstrapScript`, `HubspotDynamicForm`, `buildDefaultValues`, `captureMarketingParams`, `getMarketingParams`, `applyMarketingParamsToHiddenFields`, `useHubspotSubmit`, `hubspotFormAnalyticsIdentity`, `classifyHubspotFormAnalyticsError`, `navigateAfterSubmit`, `HUBSPOT_MIN_SUBMIT_MS`, `HUBSPOT_SUBMIT_TOO_FAST_MESSAGE`, `isHubspotSubmitTooFast`, types |
|
|
7
|
+
| `@se-studio/hubspot` | `HubSpotAnalyticsAdapter`, `HubSpotConsentCategories`, `createHubSpotBootstrapScript`, `HubspotDynamicForm`, `buildDefaultValues`, `captureMarketingParams`, `getMarketingParams`, `applyMarketingParamsToHiddenFields`, `useHubspotSubmit`, `hubspotFormAnalyticsIdentity`, `classifyHubspotFormAnalyticsError`, `navigateAfterSubmit`, `HUBSPOT_MIN_SUBMIT_MS`, `HUBSPOT_SUBMIT_TOO_FAST_MESSAGE`, `isHubspotSubmitTooFast`, types |
|
|
8
8
|
| `@se-studio/hubspot/server` | `getHubspotFormDefinition`, `submitHubspotForm`, `hubspotFormTag`, `HUBSPOT_MIN_SUBMIT_MS`, `HUBSPOT_SUBMIT_TOO_FAST_MESSAGE`, `isHubspotSubmitTooFast` |
|
|
9
9
|
| `@se-studio/hubspot/external` | `createHubspotFormExternalRenderer` |
|
|
10
10
|
|
|
@@ -58,9 +58,16 @@ After HubSpot form editor changes, revalidate: `revalidateTag(hubspotFormTag(for
|
|
|
58
58
|
|
|
59
59
|
Use with `CompositeAnalyticsAdapter` + `AnalyticsPageTracker` from `@se-studio/core-ui`. HubSpot SPA Mode B: bootstrap `setPath` before script load; `AnalyticsPageTracker` skips first mount.
|
|
60
60
|
|
|
61
|
-
Consent
|
|
61
|
+
Consent (official third-party banner API):
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
- `initialize` / `updateConsent` set `disableHubSpotCookieBanner = true` before `js.hs-scripts.com` and push `_hsp.setHubSpotConsent({ analytics, advertisement, functionality })`. HubSpot does **not** persist category consent — re-assert every page load and every CMP change.
|
|
64
|
+
- Default mapping: analytics consent → all three categories. Override with `resolveHubSpotConsent`, or pass `advertising` on `updateConsent` to set `advertisement` independently.
|
|
65
|
+
- Pass `getConsent` to skip script inject + `_hsq` track events while false (script gating from #204). Category consent is still asserted.
|
|
66
|
+
- `_hsq.doNotTrack` is **opt-in** (`hardDoNotTrack: true`). Default deny uses only `setHubSpotConsent` (anonymized aggregated views may still be allowed by HubSpot).
|
|
67
|
+
- `ConsentAwareAdapter({ syncConsent: true })` forwards analytics into `updateConsent`; HubSpot category sync happens inside this adapter — do not fork `_hsp` in site code.
|
|
68
|
+
- Helpers: `createConsentGetter` / `resolveAnalyticsConsent` in `@se-studio/core-ui`.
|
|
69
|
+
|
|
70
|
+
**SSG layouts:** call `createHubSpotBootstrapScript()` with **no args** in root layout. Bootstrap also sets `disableHubSpotCookieBanner` and initialises `_hsp` / `_hsq`. Do **not** use `headers()` or middleware to pass pathname — that breaks on-demand SSG routes in `next start`.
|
|
64
71
|
|
|
65
72
|
## Env
|
|
66
73
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@se-studio/hubspot",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.5.1",
|
|
4
4
|
"description": "HubSpot tracking and API-driven form rendering for Next.js marketing sites",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@se-studio/core-data-types": "1.13.7",
|
|
44
|
-
"@se-studio/core-ui": "1.35.
|
|
44
|
+
"@se-studio/core-ui": "1.35.2",
|
|
45
45
|
"next": ">=15.5.0 <17",
|
|
46
46
|
"react": "^19.0.0",
|
|
47
47
|
"react-dom": "^19.0.0"
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@biomejs/biome": "^2.5.12",
|
|
56
56
|
"@se-studio/core-data-types": "1.13.7",
|
|
57
|
-
"@se-studio/core-ui": "1.35.
|
|
57
|
+
"@se-studio/core-ui": "1.35.2",
|
|
58
58
|
"@types/node": "^24.13.3",
|
|
59
59
|
"@types/react": "^19.2.18",
|
|
60
60
|
"@types/react-dom": "^19.2.5",
|