Adovo

Data & Analytics

Who gets to publish an SEO change in HubSpot?

How we built a HubSpot CMS connector for an enterprise SEO platform, then moved the publish decision into the customer's app settings.

November 5, 2026

An enterprise SEO platform serving large brands can tell us what needs to change on a page. It cannot assume the page owner wants that change live immediately. That distinction shaped a HubSpot CMS connector we built. The platform needed to send precise content updates; the customer needed to keep control of publication in HubSpot.

The first brief was to bring an existing CMS integration's editing capabilities to HubSpot. A request might replace a title or description, change an H1, update a link or image value in a page module, or manage a JSON-LD block. We had to find the right page in the right customer account and leave unrelated content alone. A successful API response also had to say whether the change was saved as a draft or published.

One installation path for many customer accounts

Our early design included a HubSpot-hosted function deployed into each customer's account. Keeping the integration inside the account had an appeal, but it made installation depend on account-specific setup and HubSpot's Enterprise deployment capabilities. The client chose a service hosted by the SEO platform. Its customers needed a shared installation link, not a CLI procedure or a token to copy into another system.

We moved to a Node.js service with HubSpot OAuth. The customer follows the link, selects an account, and grants access. After the OAuth exchange, the service verifies the HubSpot account ID and uses that ID as the tenant identity. It stores encrypted access and refresh tokens in PostgreSQL, so the SEO platform does not pass HubSpot credentials with every content request. The platform's own backend calls the connector with a separate account-scoped token.

We made that boundary explicit. A page URL in a request must never be enough to select another customer's connection. The connector resolves the page inside the account identified by the authenticated caller, then rejects missing or ambiguous matches.

A page update is more than a field assignment

HubSpot metadata fields are direct enough to update. An H1 or a link in rendered HTML is different: the connector has to map what the visitor sees back to an editable field in a page-local module. We required the caller to supply the original value, checked that the target was unambiguous, and rejected unsupported mappings. For structured data, we edited only a marked block that the connector owned, leaving an author's other JSON-LD in place.

We also checked the page's draft against its published version before writing. If an editor already had unpublished changes, an integration update could later publish those changes along with its own. In that case we stopped instead of treating the existing draft as ours. Before publication we checked the page again; if the state had changed, we kept the saved draft for review and reported the conflict. HubSpot does not give this flow an atomic compare-and-publish operation, so the checks reduce risk without locking editors out of the page.

Moving the publish decision to the customer

The first API contract let the SEO platform send a publish choice with a content update. During the project, the requirement became clearer: the installing customer should make that choice inside the HubSpot app. If the platform could still send publish: true, a customer-facing switch would be easy to bypass.

We added an Auto-publish control to the app's HubSpot settings page. The settings request is authenticated as a HubSpot user, and the service saves the choice against that user's verified account ID in PostgreSQL. On each content write, the connector reads the saved setting. When it is off, the change remains a draft and the response says draft_saved. When it is on, the connector runs the publication checks and returns published only after publication succeeds. Content requests no longer accept a publish field.

That changed what the SEO platform had to understand. It sends the requested edit and reads the result; it does not decide whether the customer's live page changes. A draft can be published later through a separate operation, but only while Auto-publish is on and only when the saved draft still matches the recorded account, page, and baseline.

What the tests showed

We exercised the connector against dedicated pages in one HubSpot developer account. The tests covered OAuth connection and token refresh, metadata, H1 and XPath updates, structured data, draft saving, publication, and conflict handling. In live page checks, Auto-publish off saved updates without changing the rendered public page; on published supported updates. We checked text, link, and image values and restored the original content after testing. A local Settings proxy also showed the saved switch value changing in PostgreSQL.

The Settings view still needed a browser check after a loading issue. We also kept the module mapping conservative: one matching value in a customer theme does not always prove that the field owns the visible output.

The project established a clearer division of responsibility. The customer authorizes its HubSpot account and chooses publication in the app. The SEO platform supplies the intended change. The connector checks the account, page, editable field, and draft state, then reports whether it saved a draft or published the page. That separation kept a useful content edit from becoming an unapproved publishing decision.

Continue exploring

Data & Analytics

dbtData Contracts

A dbt model contract can miss a breaking change inside STRUCT

A nested field type change may pass a model-version breaking-change check. Compare normalized schemas and downstream behavior before release.

Read more

Data & Analytics

dbtDeveloper Experience

dbt lineage browsing stalls when every focus change recompiles

Diagnose repeated background compilation in the dbt VS Code Lineage panel and protect the development workflow while a fix is pending.

Read more

Data & Analytics

Marketing AnalyticsData PlatformPower BI

Connecting Marketing Activity to Leads and Opportunities

What changedA shared reporting view connected engagement, leads and opportunities.

Read more
Explore data and analytics services →