refineddigital/cms-form-builder-hubspot

HubSpot integration for Form Builder

Maintainers

Package info

github.com/refined-digital/cms-form-builder-hubspot

pkg:composer/refineddigital/cms-form-builder-hubspot

Transparency log

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.3 2026-07-23 04:31 UTC

This package is auto-updated.

Last update: 2026-07-23 04:31:57 UTC


README

A HubSpot integration for RefinedCMS Form Builder. On submit, the form's mapped field values create or update a contact via the HubSpot CRM v3 API. Mapping is done per field using the field's Merge Field value; the normal submission email still sends unless you turn it off in the Integrations panel.

Requires refineddigital/cms-form-builder. No SDK — it uses Laravel's HTTP client.

Install

composer require refineddigital/cms-form-builder-hubspot
php artisan refinedCMS:install-form-builder-hubspot

The install command publishes the config (config/hubspot.php) and appends HUBSPOT_TOKEN= to your .env (only if missing — it won't overwrite an existing value).

HubSpot setup

  1. In HubSpot go to Settings → Integrations → Private Apps and create a private app.
  2. Give it the crm.objects.contacts.write scope.
  3. Copy the access token into HUBSPOT_TOKEN in your .env.

The token is the only credential, and it is global to the site — there is nothing to configure per form.

Connecting a form

Once the package is installed it appears automatically in every form's Integrations panel.

  1. Edit the form and open the Integrations tab.
  2. Toggle HubSpot on.
  3. Open each field you want sent (Fields tab → the field → Merge Field) and enter the HubSpot internal property nameemail, firstname, lastname, phone, company, or any custom property's internal name.
  4. Back on Integrations, click Configure and toggle off any field you don't want sent. Each row shows its merge field next to the name, so a row with no tag isn't mapped and won't be sent whatever you do with its toggle.

Fields with an empty Merge Field are not sent. Blank submitted values are dropped rather than written as empty strings. A form whose Configure modal has never been saved sends every mapped field.

The Merge Field box only appears in the field editor once at least one integration is enabled on the form.

Emails are not this integration's concern — use the form's own Email Notifications section. There is no Send Email toggle here, and no ordering: HubSpot properties are keyed by name, so the row order is irrelevant.

Finding a property's internal name

In HubSpot: Settings → Properties, open the property, and use the name shown under Internal name (not the label). It is usually lowercase with underscores.

Behaviour

  • Upsert by email. If a field is mapped to email, the contact is upserted on that address (POST /crm/v3/objects/contacts/batch/upsert with idProperty: email), so a repeat submitter updates their existing contact instead of failing with a 409. Without an email mapped there is no identity to match on, so a plain contact create is used.
  • Checkbox / multi-select values are joined with ;, which is HubSpot's delimiter for multi-select properties.
  • Failures never block a submission. HTTP errors are caught and reported via report(), never surfaced to the visitor — HubSpot being down will not cost you a lead or stop the notification email. Returning a failure result (or throwing) would abort the whole submission; we deliberately don't.
  • No token, no call. If HUBSPOT_TOKEN is unset the integration is a no-op.

Config

config/hubspot.php:

return [
    'token' => env('HUBSPOT_TOKEN'),
];

How it works

The service provider registers the integration with the core FormBuilderIntegrationAggregate, which is what makes it show up in the panel. It registers 'sortable' => false (order is meaningless for named properties) and 'config_tab' => false (no Send Email toggle, no settings), so the Configure modal is just the field on/off list.

Process implements FormBuilderIntegrationInterface; when an enabled form is submitted, the core form-builder calls Process::process($request, $form, $settings), which walks the form's fields, keeps the ones that have a merge field and are enabled in $settings['config']['fields'], drops blanks, and POSTs the result to the contacts endpoint.

The integration does not send email — notifications are the form's own responsibility.