Loading...
Loading...
This skill should be used when the user asks to "build a HubSpot app", "create a HubSpot app", "add a card to HubSpot", "create an app card", "build a UI extension", "set up HubSpot webhooks", "configure HubSpot app", "add a settings page to HubSpot app", "build a HubSpot home page", "fetch data in HubSpot extension", "list an app on the HubSpot marketplace", "submit a HubSpot app listing", "marketplace listing requirements", or mentions building on the HubSpot developer platform 2025.2. Provides comprehensive guidance for building full HubSpot apps with best practices, CLI commands, file structure, and App Marketplace listing requirements.
npx skill4agent add cashmyrr/skills hubspot-app-builder2025.2npm install -g @hubspot/cli@latesths account authhs project createmarketplaceprivateoauthstaticcardsettingsapp-functionwebhooksworkflow-actionhs project addmy-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.jsonapp-hsmeta.json{
"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"
}
}
}uid_-.typeappstaticredirectUrlsreadcrm.objects.contacts.readhs 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 dependencies*-hsmeta.json.jsx.tsxcards/*-hsmeta.json{
"uid": "my-card",
"type": "card",
"config": {
"name": "My Card",
"description": "Card description.",
"location": "crm.record.tab",
"entrypoint": "/app/cards/MyCard.jsx",
"objectTypes": ["contacts"]
}
}| 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 |
contactscompaniesdealsticketsorderscartsp_customObjectNameapp_object_uidimport 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>
);
};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>
);
};useExtensionApi<location>()useExtensionContext<location>()useExtensionActions<location>()useCrmProperties(["prop1", "prop2"])@hubspot/ui-extensions/crmuseAssociations({ toObjectType, properties, pageLength })@hubspot/ui-extensions/crmimport { 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();permittedUrls.fetchapp-hsmeta.jsonAuthorizationX-HubSpot-Signature-v3X-HubSpot-Signature-v3Signature.isValid()@hubspot/api-clientlocal.json{
"proxy": {
"https://api.example.com": "http://localhost:8080"
}
}@hubspot/ui-extensionsFlexBoxDividerGridTextHeadingImageLinkInputTextAreaSelectMultiSelectCheckboxRadioButtonDateInputNumberInputButtonLoadingButtonIconButtonAlertLoadingSpinnerTagBadgeModalModalBodyModalFooterPanelPanelBodyPanelFooterTableTableHeadTableBodyTableRowTableCellFormFormField@hubspot/ui-extensions/crmCrmPropertyListCrmAssociationTableCrmAssociationPivotTableReportChartsrc/app/webhooks/webhooks-hsmeta.json{
"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
}
]
}
}
}crmObjectsobject.*legacyCrmObjectscontact.creationhubEventscontact.privacyDeletionconversation.*X-HubSpot-Signature-v3targetUrlhubspot.fetch()Signature.isValid()@hubspot/api-clientreferences/signature-validation.mdpackage.json{
"name": "my-card",
"version": "0.1.0",
"dependencies": {
"@hubspot/ui-extensions": "latest",
"react": "^18.2.0"
},
"devDependencies": {
"typescript": "^5.3.3"
}
}hs project install-deps| Distribution | Auth Type | Install Limit |
|---|---|---|
| | 1 standard account + 10 test accounts |
| | Up to 10 allowlisted accounts |
| | 25 before listing; unlimited after |
references/marketplace-listing.mdhs project dev # Starts dev server with hot reload.jsx.tsxapp.hubspot.comimport { logger } from "@hubspot/ui-extensions";
logger.info("Info message");
logger.debug("Debug message");
logger.warn("Warning message");
logger.error("Error message");references/app-configuration.mdapp-hsmeta.jsonreferences/ui-extensions-sdk.mdreferences/ui-components.mdreferences/features.mdreferences/signature-validation.mdreferences/marketplace-listing.md