Skip to main content

Overview

The HubSpot integration allows you to:
  • Connect your HubSpot portal via OAuth
  • Sync website pages and blog posts
  • Get SEO recommendations based on LatentGEO audits
  • Apply fixes directly to HubSpot content
  • Rollback changes if needed
All HubSpot connections are user-owned. In production, legacy ownerless connections are automatically blocked. OAuth requires authentication for both the authorization URL and callback.

OAuth Setup Workflow

1

Request Authorization URL

Call the /api/hubspot/auth-url endpoint with your JWT bearer token:
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.latentgeo.com/api/hubspot/auth-url
Response:
{
  "url": "https://app.hubspot.com/oauth/authorize?...",
  "state": "eyJhbGciOiJIUzI1NiIs..."
}
The state parameter is a signed, time-limited token (valid for 10 minutes) that prevents CSRF attacks.
2

Redirect User to HubSpot

Redirect your user to the returned url. They’ll authorize your app to access their HubSpot portal.
3

Handle OAuth Callback

HubSpot redirects back with a code and state. Post these to /api/hubspot/callback:
curl -X POST \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code":"oauth_code","state":"signed_state"}' \
  https://api.latentgeo.com/api/hubspot/callback
Response:
{
  "status": "success",
  "connection_id": "conn_hs_abc123",
  "portal_id": "12345678"
}
4

Sync Pages

After connection, manually sync pages to pull in your HubSpot content:
curl -X POST \
  -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.latentgeo.com/api/hubspot/sync/CONNECTION_ID

OAuth Security Contract

Signed State Tokens: The OAuth state parameter is cryptographically signed and includes:
  • User ID and email
  • Service identifier (hubspot)
  • Expiration timestamp (10 minutes)
Callbacks with invalid or expired state tokens are rejected with 400 or 401 errors.

Security Features

  • User binding: State tokens are tied to the authenticated user
  • Time-limited: Tokens expire after 10 minutes
  • Signature verification: HMAC-SHA256 prevents tampering
  • Cross-user protection: Callbacks validate the user matches the original requester

Connecting HubSpot Accounts

List Connections

Retrieve all active HubSpot connections for the authenticated user:
GET /api/hubspot/connections
Response:
[
  {
    "id": "conn_hs_abc123",
    "portal_id": "12345678",
    "created_at": "2024-01-15T10:30:00Z",
    "is_active": true
  }
]

Sync Pages

Pull the latest pages and blog posts from your HubSpot portal:
POST /api/hubspot/sync/{connection_id}
Response:
{
  "status": "success",
  "synced_count": 42
}
This syncs:
  • Website pages
  • Blog posts
  • Landing pages
  • Meta information (title, description)

Get Pages

List all synced pages:
GET /api/hubspot/pages/{connection_id}
Response:
[
  {
    "id": "page_xyz789",
    "hubspot_id": "87654321",
    "connection_id": "conn_hs_abc123",
    "url": "https://www.example.com/blog/seo-tips",
    "title": "10 Essential SEO Tips",
    "html_title": "10 Essential SEO Tips | Example Blog",
    "meta_description": "Learn the top 10 SEO tips to improve your website rankings.",
    "page_type": "blog_post",
    "created_at": "2024-01-10T09:00:00Z",
    "updated_at": "2024-01-15T14:30:00Z"
  }
]

Getting SEO Recommendations

LatentGEO generates actionable recommendations based on your audit results.

Generate Recommendations

Get recommendations for all pages that match an audit:
GET /api/hubspot/recommendations/{audit_id}
Response:
{
  "recommendations": [
    {
      "id": "rec_abc123",
      "hubspot_page_id": "87654321",
      "page_url": "https://www.example.com/blog/seo-tips",
      "page_title": "10 Essential SEO Tips",
      "field": "meta_description",
      "current_value": "",
      "recommended_value": "Learn the top 10 SEO tips to improve your website rankings and drive more organic traffic.",
      "priority": "high",
      "auto_fixable": true,
      "issue_type": "Missing Meta Description"
    },
    {
      "id": "rec_def456",
      "hubspot_page_id": "87654322",
      "page_url": "https://www.example.com/services",
      "page_title": "Our Services",
      "field": "html_title",
      "current_value": "Services",
      "recommended_value": "Our SEO Services - Boost Your Rankings | Example",
      "priority": "medium",
      "auto_fixable": true,
      "issue_type": "Poor Title"
    }
  ]
}

Recommendation Fields

  • field: The HubSpot field to update (e.g., meta_description, html_title)
  • current_value: The existing value in HubSpot
  • recommended_value: The AI-suggested improvement
  • priority: Importance level (high, medium, low)
  • auto_fixable: Whether the fix can be applied automatically
  • issue_type: The SEO issue being addressed

Applying SEO Recommendations

Batch Apply

Apply multiple recommendations at once:
POST /api/hubspot/apply-recommendations
Body:
{
  "audit_id": 123,
  "recommendations": [
    {
      "hubspot_page_id": "87654321",
      "field": "meta_description",
      "recommended_value": "Learn the top 10 SEO tips to improve your website rankings and drive more organic traffic."
    },
    {
      "hubspot_page_id": "87654322",
      "field": "html_title",
      "recommended_value": "Our SEO Services - Boost Your Rankings | Example"
    }
  ]
}
Response:
{
  "status": "completed",
  "applied": 2,
  "failed": 0,
  "details": {
    "applied": [
      {
        "page_id": "87654321",
        "success": true,
        "field": "meta_description"
      },
      {
        "page_id": "87654322",
        "success": true,
        "field": "html_title"
      }
    ],
    "failed": []
  }
}

Single Change

Apply a single change to a page:
{
  "connection_id": "conn_hs_abc123",
  "page_id": "87654321",
  "field": "meta_description",
  "new_value": "Learn the top 10 SEO tips to improve your rankings.",
  "audit_id": 123
}
All changes are tracked in the database, allowing you to see the history of modifications and rollback if needed.

Rollback Capabilities

If a change doesn’t work as expected, you can easily revert it.

Rollback a Change

POST /api/hubspot/rollback/{change_id}
Response:
{
  "status": "success",
  "new_change_id": "change_789"
}
How it works:
  1. LatentGEO retrieves the original value before the change
  2. Applies the old value back to HubSpot
  3. Creates a new change record marking the rollback
  4. Updates the original change status to rolled_back

Change Tracking

Every modification to HubSpot content is recorded with:
  • change_id: Unique identifier
  • page_id: The affected HubSpot page
  • field: Which field was modified
  • old_value: Value before the change
  • new_value: Value after the change
  • status: applied, failed, or rolled_back
  • audit_id: The audit that triggered the change
  • applied_at: Timestamp of the change
Only changes with status: "applied" can be rolled back. Failed or already rolled-back changes cannot be reverted.

Webhook Events

LatentGEO can receive HubSpot webhooks to stay in sync with your portal. See the Webhooks page for setup details.
Supported HubSpot events:
  • contact.creation: New contact added
  • contact.propertyChange: Contact property updated
  • deal.creation: New deal created
Webhook endpoint:
POST /api/webhooks/hubspot/incoming

Supported Fields

LatentGEO can modify the following HubSpot fields:
FieldDescriptionExample
html_titlePage title (appears in browser tab)“10 SEO Tips | Example”
meta_descriptionMeta description for search results”Learn the top 10 SEO tips…”
page_titleInternal page name in HubSpot”SEO Tips Blog Post”
Support for additional fields (canonical URLs, schema markup, social meta tags) is coming soon.

Common Errors

401 Unauthorized

  • Missing or invalid JWT token
  • OAuth state token expired or tampered with
  • User mismatch between OAuth start and callback

403 Forbidden

  • Attempting to access another user’s connection
  • Legacy ownerless connection in production mode
  • Cross-portal access attempt

404 Not Found

  • Connection, page, or change not found
  • HubSpot page was deleted from portal

400 Bad Request

  • Cannot rollback a change that isn’t in applied status
  • Invalid field name
  • Portal ID mismatch

Best Practices

  1. Test recommendations first: Review AI suggestions before bulk applying
  2. Sync regularly: Keep your page data fresh with periodic syncs
  3. Monitor change history: Track which recommendations improved performance
  4. Use rollback wisely: Revert changes that don’t work, but give them time to take effect
  5. Match audit URLs: Ensure audit URLs match HubSpot page URLs for accurate recommendations
  6. Batch operations: Apply multiple changes at once for efficiency

Matching Audits to HubSpot Pages

For recommendations to work, LatentGEO matches audit results to HubSpot pages by URL:
Audit URL: https://www.example.com/blog/seo-tips

HubSpot Page URL: https://www.example.com/blog/seo-tips

            Recommendations Generated
Run audits on the live URLs of your HubSpot pages for the most accurate recommendations.

Next Steps

Webhooks

Set up webhook integrations for automation

GitHub Integration

Connect GitHub to audit blog content

Build docs developers (and LLMs) love