hubspot-app-builder
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHubSpot App Builder (Platform 2025.2)
HubSpot应用构建工具(平台2025.2版本)
This skill guides the development of full HubSpot apps on the latest developer platform (version ), covering project creation, configuration, UI extensions, webhooks, and distribution.
2025.2本Skill指导开发者基于最新的HubSpot开发者平台(版本)开发完整的HubSpot应用,涵盖项目创建、配置、UI扩展、Webhooks设置及应用分发等内容。
2025.2Prerequisites
前置条件
- HubSpot CLI v7.6.0+:
npm install -g @hubspot/cli@latest - Authenticate:
hs account auth - Node.js 18+
- A HubSpot developer account
- HubSpot CLI v7.6.0及以上版本:
npm install -g @hubspot/cli@latest - 身份验证:
hs account auth - Node.js 18+
- 一个HubSpot开发者账户
Project Setup Workflow
项目搭建流程
1. Create the Project
1. 创建项目
shell
hs project createFollow CLI prompts to configure:
- Distribution: (for App Marketplace listing) or
marketplace(for specific accounts)private - Auth: (multiple accounts) or
oauth(single account)static - Features: Select from ,
card,settings,app-function,webhooksworkflow-action
To add a feature later:
shell
hs project addshell
hs project create按照CLI提示完成配置:
- 分发方式:(用于应用市场上架)或
marketplace(仅针对特定账户)private - 认证方式:(支持多账户)或
oauth(仅单账户)static - 功能选择:可从、
card、settings、app-function、webhooks中选择workflow-action
后续如需添加功能:
shell
hs project add2. Project File Structure
2. 项目文件结构
my-project-folder/
├── hsproject.json
└── src/
└── app/
├── app-hsmeta.json # Top-level app config (required)
├── cards/ # UI extension cards
│ ├── MyCard.jsx
│ ├── my-card-hsmeta.json
│ └── package.json
├── settings/ # App settings page
│ ├── Settings.tsx
│ ├── settings-hsmeta.json
│ └── package.json
├── app-events/ # App events (open beta)
│ └── my-event-hsmeta.json
├── app-objects/ # App objects (open beta)
│ └── my-object-hsmeta.json
├── webhooks/ # Webhook subscriptions
│ └── webhooks-hsmeta.json
└── workflow-actions/ # Custom workflow actions
└── custom-action-hsmeta.jsonmy-project-folder/
├── hsproject.json
└── src/
└── app/
├── app-hsmeta.json # 顶层应用配置(必填)
├── cards/ # UI扩展卡片
│ ├── MyCard.jsx
│ ├── my-card-hsmeta.json
│ └── package.json
├── settings/ # 应用设置页面
│ ├── Settings.tsx
│ ├── settings-hsmeta.json
│ └── package.json
├── app-events/ # 应用事件(开放测试版)
│ └── my-event-hsmeta.json
├── app-objects/ # 应用对象(开放测试版)
│ └── my-object-hsmeta.json
├── webhooks/ # Webhook订阅
│ └── webhooks-hsmeta.json
└── workflow-actions/ # 自定义工作流动作
└── custom-action-hsmeta.json3. Configure app-hsmeta.json
app-hsmeta.json3. 配置app-hsmeta.json
app-hsmeta.jsonjson
{
"uid": "my_app_uid",
"type": "app",
"config": {
"name": "My App",
"description": "App description for installing users.",
"distribution": "marketplace",
"auth": {
"type": "oauth",
"redirectUrls": ["http://localhost:3000/oauth-callback"],
"requiredScopes": ["crm.objects.contacts.read"],
"optionalScopes": [],
"conditionallyRequiredScopes": []
},
"permittedUrls": {
"fetch": ["https://api.example.com"],
"iframe": [],
"img": []
},
"support": {
"supportEmail": "support@example.com",
"documentationUrl": "https://example.com/docs"
}
}
}Key rules:
- must be globally unique within the project (up to 64 chars, alphanumeric +
uid,_,-). - must match the parent folder name (
type)app - Use auth + remove
staticfor single-account private appsredirectUrls - At minimum, include one scope (e.g.,
read)crm.objects.contacts.read
json
{
"uid": "my_app_uid",
"type": "app",
"config": {
"name": "My App",
"description": "面向安装用户的应用描述。",
"distribution": "marketplace",
"auth": {
"type": "oauth",
"redirectUrls": ["http://localhost:3000/oauth-callback"],
"requiredScopes": ["crm.objects.contacts.read"],
"optionalScopes": [],
"conditionallyRequiredScopes": []
},
"permittedUrls": {
"fetch": ["https://api.example.com"],
"iframe": [],
"img": []
},
"support": {
"supportEmail": "support@example.com",
"documentationUrl": "https://example.com/docs"
}
}
}关键规则:
- 在项目内必须全局唯一(最多64个字符,支持字母、数字及
uid、_、-). - 必须与父文件夹名称匹配(即
type)app - 单账户私有应用请使用认证,并移除
static配置redirectUrls - 至少需包含一个权限范围(例如
read)crm.objects.contacts.read
4. Upload and Deploy
4. 上传与部署
shell
hs project upload # Upload and trigger a build
hs project open # Open project in HubSpot browser
hs project dev # Start local dev server with hot reload
hs project install-deps # Install package.json dependenciesshell
hs project upload # 上传并触发构建
hs project open # 在HubSpot浏览器中打开项目
hs project dev # 启动本地开发服务器并支持热重载
hs project install-deps # 安装package.json中的依赖5. Install the App
5. 安装应用
After uploading, install via HubSpot UI:
- Navigate to Development > Projects > [Project Name] > [App UID]
- Click the Distribution tab
- For test accounts: click Add test install(s)
- For standard accounts: click Install now
上传完成后,通过HubSpot UI进行安装:
- 导航至开发 > 项目 > [项目名称] > [应用UID]
- 点击分发标签页
- 测试账户:点击添加测试安装
- 标准账户:点击立即安装
UI Extensions
UI扩展
All UI extensions share the same structure: a config + a React component file ( or ).
*-hsmeta.json.jsx.tsx所有UI扩展均采用相同结构:一个配置文件 + 一个React组件文件(或)。
*-hsmeta.json.jsx.tsxApp Card Configuration (cards/*-hsmeta.json
)
cards/*-hsmeta.json应用卡片配置(cards/*-hsmeta.json
)
cards/*-hsmeta.jsonjson
{
"uid": "my-card",
"type": "card",
"config": {
"name": "My Card",
"description": "Card description.",
"location": "crm.record.tab",
"entrypoint": "/app/cards/MyCard.jsx",
"objectTypes": ["contacts"]
}
}Supported locations:
| Location | Value | Notes |
|---|---|---|
| CRM middle column | | Most common; supports custom tabs |
| CRM right sidebar | | No CRM data components here |
| CRM preview panel | | Record previews across CRM |
| Help desk sidebar | | Requires |
| App home page | | Full-screen extension |
| App settings page | | Config UI in HubSpot settings |
Supported objectTypes: , , , , , , ,
contactscompaniesdealsticketsorderscartsp_customObjectNameapp_object_uidjson
{
"uid": "my-card",
"type": "card",
"config": {
"name": "My Card",
"description": "卡片描述。",
"location": "crm.record.tab",
"entrypoint": "/app/cards/MyCard.jsx",
"objectTypes": ["contacts"]
}
}支持的部署位置:
| 位置 | 值 | 说明 |
|---|---|---|
| CRM中间栏 | | 最常用,支持自定义标签页 |
| CRM右侧边栏 | | 此处不支持CRM数据组件 |
| CRM预览面板 | | 跨CRM的记录预览区域 |
| 帮助台侧边栏 | | 需要 |
| 应用主页 | | 全屏扩展 |
| 应用设置页面 | | HubSpot设置中的配置UI |
支持的对象类型: , , , , , , ,
contactscompaniesdealsticketsorderscartsp_customObjectNameapp_object_uidReact Component Pattern
React组件模式
jsx
import React from "react";
import { hubspot, Text, Button, Flex } from "@hubspot/ui-extensions";
// Required: register extension with HubSpot
hubspot.extend(({ context, actions }) => (
<MyCard context={context} addAlert={actions.addAlert} />
));
const MyCard = ({ context, addAlert }) => {
return (
<Flex direction="column" gap="medium">
<Text>Hello, {context.user.firstName}!</Text>
<Button onClick={() => addAlert({ type: "success", title: "Done", message: "Action completed" })}>
Click me
</Button>
</Flex>
);
};jsx
import React from "react";
import { hubspot, Text, Button, Flex } from "@hubspot/ui-extensions";
// 必填:向HubSpot注册扩展
hubspot.extend(({ context, actions }) => (
<MyCard context={context} addAlert={actions.addAlert} />
));
const MyCard = ({ context, addAlert }) => {
return (
<Flex direction="column" gap="medium">
<Text>你好,{context.user.firstName}!</Text>
<Button onClick={() => addAlert({ type: "success", title: "完成", message: "操作已完成" })}>
点击我
</Button>
</Flex>
);
};SDK Hooks (Preferred Approach)
SDK钩子(推荐方式)
tsx
import { hubspot, Button, useExtensionApi } from "@hubspot/ui-extensions";
import { useCrmProperties } from "@hubspot/ui-extensions/crm";
hubspot.extend<'crm.record.tab'>(() => <MyCard />);
const MyCard = () => {
// Access both context and actions
const { context, actions } = useExtensionApi<'crm.record.tab'>();
// Fetch CRM properties from the current record
const { properties, isLoading } = useCrmProperties(["firstname", "lastname", "email"]);
if (isLoading) return <Text>Loading...</Text>;
return (
<Button onClick={() => actions.addAlert({ message: `Hello ${properties.firstname}!` })}>
Say Hello
</Button>
);
};Available hooks:
- — access both context + actions
useExtensionApi<location>() - — access context only
useExtensionContext<location>() - — access actions only
useExtensionActions<location>() - — from
useCrmProperties(["prop1", "prop2"])@hubspot/ui-extensions/crm - — from
useAssociations({ toObjectType, properties, pageLength })@hubspot/ui-extensions/crm
tsx
import { hubspot, Button, useExtensionApi } from "@hubspot/ui-extensions";
import { useCrmProperties } from "@hubspot/ui-extensions/crm";
hubspot.extend<'crm.record.tab'>(() => <MyCard />);
const MyCard = () => {
// 访问上下文和动作
const { context, actions } = useExtensionApi<'crm.record.tab'>();
// 从当前记录获取CRM属性
const { properties, isLoading } = useCrmProperties(["firstname", "lastname", "email"]);
if (isLoading) return <Text>加载中...</Text>;
return (
<Button onClick={() => actions.addAlert({ message: `你好 ${properties.firstname}!` })}>
打招呼
</Button>
);
};可用钩子:
- — 同时访问上下文和动作
useExtensionApi<location>() - — 仅访问上下文
useExtensionContext<location>() - — 仅访问动作
useExtensionActions<location>() - — 来自
useCrmProperties(["prop1", "prop2"])@hubspot/ui-extensions/crm - — 来自
useAssociations({ toObjectType, properties, pageLength })@hubspot/ui-extensions/crm
Fetching External Data
获取外部数据
jsx
import { hubspot } from "@hubspot/ui-extensions";
// In component
const response = await hubspot.fetch("https://api.example.com/data", {
method: "GET",
timeout: 5000,
});
const data = await response.json();Requirements:
- Add the URL to in
permittedUrls.fetchapp-hsmeta.json - URLs must use HTTPS (no localhost — use proxy for local dev)
- Max 20 concurrent requests per account; 15s timeout; 1MB payload limit
- No custom headers except ; HubSpot signs requests automatically with
AuthorizationX-HubSpot-Signature-v3
Your backend must validate on every request coming from a CRM card or settings page fetch. This is the same validation required for webhooks — use from . Without it, anyone can send fake requests to your endpoint.
X-HubSpot-Signature-v3Signature.isValid()@hubspot/api-clientFor local dev proxy, create in the project root:
local.jsonjson
{
"proxy": {
"https://api.example.com": "http://localhost:8080"
}
}jsx
import { hubspot } from "@hubspot/ui-extensions";
// 在组件中使用
const response = await hubspot.fetch("https://api.example.com/data", {
method: "GET",
timeout: 5000,
});
const data = await response.json();要求:
- 需将URL添加至中的
app-hsmeta.json配置permittedUrls.fetch - URL必须使用HTTPS(本地开发请使用代理,不支持直接localhost)
- 每个账户最多支持20个并发请求;超时时间15秒; payload上限1MB
- 除外不允许自定义请求头;HubSpot会自动使用
Authorization对请求进行签名X-HubSpot-Signature-v3
你的后端必须验证来自CRM卡片或设置页面fetch请求的签名。 这与Webhook所需的验证方式相同——可使用中的方法。若不验证,任何人都可向你的端点发送伪造请求。
X-HubSpot-Signature-v3@hubspot/api-clientSignature.isValid()本地开发代理配置:在项目根目录创建
local.jsonjson
{
"proxy": {
"https://api.example.com": "http://localhost:8080"
}
}Available UI Components
可用UI组件
Import from :
@hubspot/ui-extensions- Layout: ,
Flex,Box,DividerGrid - Text/Display: ,
Text,Heading,ImageLink - Input: ,
Input,TextArea,Select,MultiSelect,Checkbox,RadioButton,DateInputNumberInput - Actions: ,
Button,LoadingButtonIconButton - Feedback: ,
Alert,LoadingSpinner,TagBadge - Overlay: ,
Modal,ModalBody,ModalFooter,Panel,PanelBodyPanelFooter - Data: ,
Table,TableHead,TableBody,TableRowTableCell - Form: ,
FormFormField
Import from (CRM points only, not sidebar):
@hubspot/ui-extensions/crm- — display/edit CRM properties
CrmPropertyList - — show associated records
CrmAssociationTable CrmAssociationPivotTableReportChart
从导入:
@hubspot/ui-extensions- 布局:,
Flex,Box,DividerGrid - 文本/展示:,
Text,Heading,ImageLink - 输入控件:,
Input,TextArea,Select,MultiSelect,Checkbox,RadioButton,DateInputNumberInput - 动作组件:,
Button,LoadingButtonIconButton - 反馈组件:,
Alert,LoadingSpinner,TagBadge - 覆盖层:,
Modal,ModalBody,ModalFooter,Panel,PanelBodyPanelFooter - 数据组件:,
Table,TableHead,TableBody,TableRowTableCell - 表单:,
FormFormField
从导入(仅支持CRM主区域,不支持侧边栏):
@hubspot/ui-extensions/crm- — 展示/编辑CRM属性
CrmPropertyList - — 显示关联记录
CrmAssociationTable CrmAssociationPivotTableReportChart
Webhooks Configuration
Webhooks配置
Create :
src/app/webhooks/webhooks-hsmeta.jsonjson
{
"uid": "my-webhooks",
"type": "webhooks",
"config": {
"settings": {
"targetUrl": "https://api.example.com/webhook",
"maxConcurrentRequests": 10
},
"subscriptions": {
"crmObjects": [
{
"subscriptionType": "object.creation",
"objectType": "contact",
"active": true
},
{
"subscriptionType": "object.propertyChange",
"objectType": "contact",
"active": true
}
],
"legacyCrmObjects": [
{
"subscriptionType": "contact.propertyChange",
"propertyName": "email",
"active": true
}
],
"hubEvents": [
{
"subscriptionType": "contact.privacyDeletion",
"active": true
}
]
}
}
}Use for new-format events (). Use for classic types like . Use for and .
crmObjectsobject.*legacyCrmObjectscontact.creationhubEventscontact.privacyDeletionconversation.*创建:
src/app/webhooks/webhooks-hsmeta.jsonjson
{
"uid": "my-webhooks",
"type": "webhooks",
"config": {
"settings": {
"targetUrl": "https://api.example.com/webhook",
"maxConcurrentRequests": 10
},
"subscriptions": {
"crmObjects": [
{
"subscriptionType": "object.creation",
"objectType": "contact",
"active": true
},
{
"subscriptionType": "object.propertyChange",
"objectType": "contact",
"active": true
}
],
"legacyCrmObjects": [
{
"subscriptionType": "contact.propertyChange",
"propertyName": "email",
"active": true
}
],
"hubEvents": [
{
"subscriptionType": "contact.privacyDeletion",
"active": true
}
]
}
}
}新格式事件()使用配置。经典类型如使用配置。和等事件使用配置。
object.*crmObjectscontact.creationlegacyCrmObjectscontact.privacyDeletionconversation.*hubEventsSignature Validation (Required)
签名验证(必填)
HubSpot signs all outbound requests with :
X-HubSpot-Signature-v3- Webhook deliveries — HubSpot POSTs event payloads to your
targetUrl - Card / settings page fetch — any call from a UI extension is proxied and signed by HubSpot
hubspot.fetch()
Both must be validated the same way using from . For the complete implementation, see .
Signature.isValid()@hubspot/api-clientreferences/signature-validation.mdHubSpot会使用对所有出站请求进行签名:
X-HubSpot-Signature-v3- Webhook投递 — HubSpot将事件负载POST至你的
targetUrl - 卡片/设置页面fetch — UI扩展中的任何调用都会被HubSpot代理并签名
hubspot.fetch()
两者需使用相同方式验证,即通过中的方法。完整实现请参考。
@hubspot/api-clientSignature.isValid()references/signature-validation.mdpackage.json
for UI Extensions
package.jsonUI扩展的package.json
示例
package.jsonjson
{
"name": "my-card",
"version": "0.1.0",
"dependencies": {
"@hubspot/ui-extensions": "latest",
"react": "^18.2.0"
},
"devDependencies": {
"typescript": "^5.3.3"
}
}Install:
hs project install-depsjson
{
"name": "my-card",
"version": "0.1.0",
"dependencies": {
"@hubspot/ui-extensions": "latest",
"react": "^18.2.0"
},
"devDependencies": {
"typescript": "^5.3.3"
}
}安装依赖:
hs project install-depsDistribution & Auth Summary
分发与认证汇总
| Distribution | Auth Type | Install Limit |
|---|---|---|
| | 1 standard account + 10 test accounts |
| | Up to 10 allowlisted accounts |
| | 25 before listing; unlimited after |
| 分发方式 | 认证类型 | 安装限制 |
|---|---|---|
| | 1个标准账户 + 10个测试账户 |
| | 最多10个白名单账户 |
| | 上架前最多25个安装;上架后无限制 |
App Marketplace Listing
应用市场上架
Before submitting to the HubSpot App Marketplace, the app must meet these key requirements:
Technical minimums:
- OAuth is the sole authorization method — no API keys or private app tokens
- At least 3 active installs from unaffiliated accounts with OAuth-authenticated API activity in the past 30 days
- Only request scopes the app actually uses; all requested scopes must appear in the Shared data table
- Classic CRM cards are not allowed (deprecated June 16, 2025)
Listing content:
- Content must be integration-specific (not general product marketing)
- All URLs must be live, publicly accessible, and under 250 characters — add HubSpot Crawler to your site allow list before submitting
- Include: setup documentation, Install button URL, support resources, Terms of Service, Privacy Policy, and pricing (matching your website exactly)
- Bi-directional sync must be declared in Shared data when both read and write scopes are requested for the same object
App cards (if using UI extensions):
- Do not use HubSpot brand names in card names or icons
- One primary button per surface; destructive buttons must use destructive styling
- Must not access or display sensitive data
Review process: Initial review within 10 business days; full cycle up to 60 days. Only one app can be under review at a time.
For the complete requirements checklist, see .
references/marketplace-listing.md在提交至HubSpot应用市场前,应用必须满足以下核心要求:
技术最低要求:
- 仅允许使用OAuth作为授权方式 — 不支持API密钥或私有应用令牌
- 至少有3个来自非关联账户的活跃安装,且在过去30天内有OAuth认证的API活动
- 仅请求应用实际需要的权限范围;所有请求的权限范围必须出现在「共享数据」表格中
- 不允许使用经典CRM卡片(2025年6月16日已废弃)
上架内容要求:
- 内容必须针对集成本身(而非通用产品营销)
- 所有URL必须可正常访问、公开可用且长度不超过250字符 — 提交前请将「HubSpot爬虫」加入网站白名单
- 需包含:安装文档、安装按钮URL、支持资源、服务条款、隐私政策及定价(需与官网完全一致)
- 当对同一对象同时请求读和写权限范围时,必须在「共享数据」中声明双向同步
应用卡片(如使用UI扩展):
- 卡片名称或图标中不得使用HubSpot品牌名称
- 每个界面仅保留一个主要按钮;破坏性按钮必须使用破坏性样式
- 不得访问或展示敏感数据
审核流程: 初始审核需10个工作日;完整流程最长可达60天。同一时间仅允许一个应用处于审核状态。
完整要求清单请参考。
references/marketplace-listing.mdLocal Development
本地开发
shell
hs project dev # Starts dev server with hot reloadAfter starting, a local development homepage appears in the test account showing active dev sessions. Changes to / files reload automatically.
.jsx.tsxNote (Chrome 142+): Accept the local network access popup from on first launch.
app.hubspot.comshell
hs project dev # 启动开发服务器并支持热重载启动后,测试账户中会显示本地开发主页,展示活跃的开发会话。修改/文件会自动重载。
.jsx.tsx注意(Chrome 142+):首次启动时需接受弹出的本地网络访问授权。
app.hubspot.comDebugging
调试
View logs: Development > Monitoring > Logs > UI Extensions in HubSpot.
In code, use the logger:
js
import { logger } from "@hubspot/ui-extensions";
logger.info("Info message");
logger.debug("Debug message");
logger.warn("Warning message");
logger.error("Error message");查看日志:在HubSpot中导航至开发 > 监控 > 日志 > UI扩展。
代码中可使用日志工具:
js
import { logger } from "@hubspot/ui-extensions";
logger.info("信息消息");
logger.debug("调试消息");
logger.warn("警告消息");
logger.error("错误消息");Additional Resources
额外资源
Reference Files
参考文档
For detailed configuration and patterns, consult:
- — Complete
references/app-configuration.mdschema, scopes, auth typesapp-hsmeta.json - — SDK hooks, context fields, actions API
references/ui-extensions-sdk.md - — All UI components with examples
references/ui-components.md - — App events, app objects (open beta), settings page, home page
references/features.md - — Full signature validation implementation for webhooks and card/settings page fetch endpoints
references/signature-validation.md - — Full App Marketplace listing requirements, brand rules, app card criteria, and review process
references/marketplace-listing.md
如需详细配置和模式说明,请查阅:
- — 完整的
references/app-configuration.mdschema、权限范围、认证类型app-hsmeta.json - — SDK钩子、上下文字段、动作API
references/ui-extensions-sdk.md - — 所有UI组件及示例
references/ui-components.md - — 应用事件、应用对象(开放测试版)、设置页面、主页
references/features.md - — Webhooks及卡片/设置页面fetch端点的完整签名验证实现
references/signature-validation.md - — 完整的应用市场上架要求、品牌规则、应用卡片标准及审核流程
references/marketplace-listing.md
Official Documentation
官方文档
- Create an app
- App configuration reference
- Manage apps in HubSpot
- UI extensions overview
- App cards reference
- UI extensions SDK
- Fetching data
- UI components overview
- App home page
- Settings page
- App events (beta)
- App objects (beta)
- Configure webhooks
- App Marketplace listing requirements
- How to list your app
- App certification requirements