Files
ComfyUI_frontend/apps/website/README.md
Benjamin Lu 17c18b0707 fix: embed HubSpot contact form (#11723)
## Summary

Embed the HubSpot-hosted contact sales form on `/contact` and
`/zh-CN/contact` so HubSpot owns submission handling, validation,
anti-spam/security updates, tracking context, and form configuration.

## Changes

- **What**: Replaces the custom local contact form stub with a HubSpot
embed component using the HubSpot-hosted developer/raw HTML script and
`hs-form-html` container.
- **Localization**: Uses the existing English form ID by default and
switches to the zh-CN form ID for `/zh-CN/contact`.
- **Styling**: Applies HubSpot form CSS custom properties to match the
Comfy contact page colors and `PP Formula` font more closely.
- **Docs**: Updates the website README with the developer embed snippet
and the zh-CN form ID.
- **Dependencies**: None.

## Why Embedded Form

- HubSpot docs say forms should be loaded with the HubSpot-hosted
JavaScript file, and that security, anti-spam, accessibility, and
performance improvements will not propagate if the embed runtime is
copied or self-hosted:
https://developers.hubspot.com/docs/cms/start-building/building-blocks/modules/forms
- The direct form submission endpoint is documented under `v3 legacy`:
https://developers.hubspot.com/docs/api-reference/legacy/marketing/forms/v3-legacy/submit-data-unauthenticated
- HubSpot’s legacy API overview says numeric-versioned APIs are legacy
and will be deprecated in a future release:
https://developers.hubspot.com/docs/api-reference/legacy/overview

## Review Focus

- Confirm the portal ID and form IDs are correct:
  - `en`: `94e05eab-1373-47f7-ab5e-d84f9e6aa262`
  - `zh-CN`: `6885750c-02ef-4aa2-ba0d-213be9cccf93`
- Check visual fit on `/contact` and `/zh-CN/contact`, especially font,
background, inputs, radio controls, and submit button.
- Confirm the developer/raw HTML embed remains the preferred integration
over a custom Forms API POST.

## Local Checks

- `pnpm exec oxfmt --check
apps/website/src/components/contact/HubspotFormEmbed.vue
apps/website/README.md`
- `pnpm exec eslint
apps/website/src/components/contact/HubspotFormEmbed.vue`
- `pnpm --filter @comfyorg/website typecheck`
- `pnpm --filter @comfyorg/website test:unit`
- `pnpm --filter @comfyorg/website build`
- Commit hooks: stylelint, oxfmt, oxlint, eslint, `pnpm typecheck`,
`pnpm typecheck:website`
- Push hook: `pnpm knip --cache`

Build completed with existing non-fatal environment warnings: Node
`v25.8.1` vs requested `24.x`, unresolved website font paths deferred to
runtime, `transformWithEsbuild` deprecation, and missing Ashby env
falling back to the committed snapshot.

Incredibly, during the taking of these screenshots, I discovered a bug
in macos, where despite the snapshot/record bar not existing, from me
esc'ing out, some of the tooltips persist. Closing and reopening the lid
did not fix this. I didn't see the process in activity monitor.

<img width="1512" height="862" alt="Screenshot 2026-04-29 at 7 09 55 PM"
src="https://github.com/user-attachments/assets/92518795-6845-4b34-8da3-54048b440eb1"
/>

<img width="1512" height="862" alt="Screenshot 2026-04-29 at 7 13 18 PM"
src="https://github.com/user-attachments/assets/f7609e58-898d-413c-975c-b02b70b84e73"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11723-fix-embed-HubSpot-contact-form-3506d73d365081528bfbe4b024c2a21f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-04-29 22:40:55 -07:00

5.3 KiB

@comfyorg/website

Marketing/brand website built with Astro + Vue.

Ashby careers integration

/careers and /zh-CN/careers are rendered from Ashby's public job board API at build time. Data flow:

  1. src/pages/careers.astro awaits fetchRolesForBuild() during the Astro build.
  2. src/utils/ashby.ts calls GET https://api.ashbyhq.com/posting-api/job-board/{board}?includeCompensation=false, validates the envelope and each posting with Zod (src/utils/ashby.schema.ts), and maps to the domain type in src/data/roles.ts.
  3. On any failure (network, HTTP 4xx/5xx, envelope schema drift), the fetcher falls back to the committed JSON snapshot at src/data/ashby-roles.snapshot.json.
  4. src/utils/ashby.ci.ts emits GitHub Actions annotations and a $GITHUB_STEP_SUMMARY block so stale fetches are visible on green builds.

Required environment variables

Both are build-time only. Never prefix with PUBLIC_ (Astro would inline that into the client bundle).

Name Purpose Default (when unset)
WEBSITE_ASHBY_API_KEY Ashby API key (Basic auth) Build uses the committed snapshot
WEBSITE_ASHBY_JOB_BOARD_NAME Ashby public job board slug Build uses the committed snapshot

CI wiring (manual step — required)

This repo's .github/workflows/*.yaml changes cannot be pushed by a GitHub App. A maintainer must apply the following edits once:

.github/workflows/ci-website-build.yaml — pass the env into the build step and run the unit tests before it:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Setup frontend
        uses: ./.github/actions/setup-frontend

      - name: Run website unit tests
        run: pnpm --filter @comfyorg/website test:unit

      - name: Build website
        env:
          WEBSITE_ASHBY_API_KEY: ${{ secrets.WEBSITE_ASHBY_API_KEY }}
          WEBSITE_ASHBY_JOB_BOARD_NAME: ${{ vars.WEBSITE_ASHBY_JOB_BOARD_NAME || 'comfy-org' }}
        run: pnpm --filter @comfyorg/website build

      - name: Verify API key is not leaked into build output
        env:
          WEBSITE_ASHBY_API_KEY: ${{ secrets.WEBSITE_ASHBY_API_KEY }}
        run: |
          set +x
          if [ -z "${WEBSITE_ASHBY_API_KEY:-}" ]; then
            echo "Secret not available in this run; skipping leak check."
            exit 0
          fi
          # grep -rlF prints only file paths (never match content).
          MATCHES=$(grep -rlF --exclude-dir=node_modules --null \
            -e "$WEBSITE_ASHBY_API_KEY" apps/website/dist/ 2>/dev/null \
            | tr '\0' '\n' || true)
          if [ -n "$MATCHES" ]; then
            echo "::error title=Ashby API key leaked into build output::$MATCHES"
            exit 1
          fi

.github/workflows/ci-vercel-website-preview.yaml — add the two env vars to the top-level env: block so vercel build (both deploy-preview and deploy-production jobs) sees them:

env:
  VERCEL_ORG_ID: ${{ secrets.VERCEL_WEBSITE_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEBSITE_PROJECT_ID }}
  VERCEL_TOKEN: ${{ secrets.VERCEL_WEBSITE_TOKEN }}
  VERCEL_SCOPE: comfyui
  WEBSITE_ASHBY_API_KEY: ${{ secrets.WEBSITE_ASHBY_API_KEY }}
  WEBSITE_ASHBY_JOB_BOARD_NAME: ${{ vars.WEBSITE_ASHBY_JOB_BOARD_NAME || 'comfy-org' }}

The secret must also be added to the Vercel project environment (vercel env add WEBSITE_ASHBY_API_KEY … or via the Vercel UI) so that vercel build in the preview job has access to it.

Fork PRs do not exercise this path: ci-vercel-website-preview.yaml receives an empty VERCEL_TOKEN for forks and fails at vercel pull before the build runs. Fork-safe PR interactions (the preview-URL comment) are handled by pr-vercel-website-preview.yaml.

Refreshing the snapshot

When a maintainer wants to update the committed snapshot (e.g. after onboarding/offboarding roles):

WEBSITE_ASHBY_API_KEY=WEBSITE_ASHBY_JOB_BOARD_NAME=comfy-org \
  pnpm --filter @comfyorg/website ashby:refresh-snapshot
git commit apps/website/src/data/ashby-roles.snapshot.json

The script exits non-zero on any non-fresh outcome so stale/empty snapshots can't be accidentally committed.

HubSpot contact form

The contact page uses HubSpot's hosted form embed for the interest form:

<script
  src="https://js-na2.hsforms.net/forms/embed/developer/244637579.js"
  defer
></script>
<div
  class="hs-form-html"
  data-region="na2"
  data-form-id="94e05eab-1373-47f7-ab5e-d84f9e6aa262"
  data-portal-id="244637579"
></div>

The localized /zh-CN/contact page uses the same portal and script with form ID 6885750c-02ef-4aa2-ba0d-213be9cccf93.

This keeps submission handling, validation, anti-spam updates, and field configuration in HubSpot. The local implementation in src/components/contact/HubspotFormEmbed.vue only loads the hosted script and renders the documented embed container.

Scripts

  • pnpm dev — Astro dev server
  • pnpm build — production build to dist/
  • pnpm typecheckastro check
  • pnpm test:unit — Vitest unit tests
  • pnpm test:e2e — Playwright E2E tests (requires pnpm build first)
  • pnpm ashby:refresh-snapshot — refresh the committed careers snapshot