# @se-studio/hubspot — LLM reference

## Exports

| Import | Contents |
|--------|----------|
| `@se-studio/hubspot` | `HubSpotAnalyticsAdapter`, `createHubSpotBootstrapScript`, `HubspotDynamicForm`, `buildDefaultValues`, `captureMarketingParams`, `getMarketingParams`, `applyMarketingParamsToHiddenFields`, `useHubspotSubmit`, `navigateAfterSubmit`, types |
| `@se-studio/hubspot/server` | `getHubspotFormDefinition`, `submitHubspotForm`, `hubspotFormTag` |
| `@se-studio/hubspot/external` | `createHubspotFormExternalRenderer` |

## CMS external component

- `externalComponentType`: `"Hubspot form"`
- `data.formId` (required): HubSpot form GUID
- `data.portalId` (optional): defaults to `HUBSPOT_PORTAL_ID`
- Hidden UTM fields: `HubspotDynamicForm` auto-fills empty hidden fields from URL query + first-touch `sessionStorage` (`utm_source`, etc.). CMS `hiddenFields` override. Forks should import `buildDefaultValues` / `applyMarketingParamsToHiddenFields` rather than reimplementing.

## Post-submit

Not native HubSpot embed — client must handle redirect/thank-you.

Priority: `redirectUrlOverride` → submit `redirectUri` → form `postSubmitAction.redirect_url` → thank-you / inline message.

- External URLs → `window.location.assign` (via `navigateAfterSubmit`)
- Same-origin → `router.push`
- `onSuccess` is a **side-effect only** — does not suppress redirect/thank-you
- Preserve full `redirectUri` from HubSpot (do not strip host)

```tsx
useHubspotSubmit({ portalId, formDefinition, onSuccess, redirectUrlOverride })
// or
<HubspotDynamicForm redirectUrlOverride={url} onSuccess={fn} ... />
```

After HubSpot form editor changes, revalidate: `revalidateTag(hubspotFormTag(formId), { expire: 0 })` (definitions cached ~1h). Do not use `'max'` — that is stale-while-revalidate.

## Analytics

Use with `CompositeAnalyticsAdapter` + `AnalyticsPageTracker` from `@se-studio/core-ui`. HubSpot SPA Mode B: bootstrap `setPath` before script load; `AnalyticsPageTracker` skips first mount.

**SSG layouts:** call `createHubSpotBootstrapScript()` with **no args** in root layout. Do **not** use `headers()` or middleware to pass pathname — that breaks on-demand SSG routes in `next start`.

## Env

- `HUBSPOT_PORTAL_ID` — tracking + submit URL
- `HUBSPOT_PAT` — Marketing Forms API (server only)