Domain skill
hubspot
Markdown synced from browser-harness domain skills.
- Host
- hubspot
- Files
- 1
Agent prompt
Use this skill
Copy this prompt into your coding agent to make it enable browser-harness domain skills and read this exact domain folder before automating.
Set up https://github.com/browser-use/browser-harness for me if it is not already installed. If setup is needed, read `install.md` first to install and connect it to my real browser. Then read `SKILL.md` for normal usage and always read `helpers.py` because that is where the browser-harness functions are. Enable domain skills if they are not already enabled by setting `BH_DOMAIN_SKILLS=1` for browser-harness. Use the `hubspot` domain skill from `agent-workspace/domain-skills/hubspot/`. Read every markdown file for this domain before inventing an approach: - agent-workspace/domain-skills/hubspot/private-app-webhooks.md Use those domain-skill notes to complete my task for `hubspot` in my real browser. When you open a setup, verification, or task tab, activate it so I can see the active browser tab.
Skill contents
What the agent will read
editing a Private App's webhook subscriptions
private-app-webhooks.md
- For adding or removing property-change subscriptions on a Private App (the v3 webhook surface). Assumes the app already exists.
- https://app-<region>.hubspot.com/private-apps/{portalId}/{appId}/webhooks — read-only view of current subscriptions. Useful for verification after a change. <region> is na1, na2, eu1, etc.
- https://app-<region>.hubspot.com/private-apps/{portalId}/{appId}/edit — drops you into the editor. From here, click the Webhooks tab in the left rail to reach the subscription editor.
- The read-only /webhooks page does not have a "Create subscription" button. Get into edit mode first.
Show full markdown
For adding or removing property-change subscriptions on a Private App (the v3 webhook surface). Assumes the app already exists.
URL map
https://app-<region>.hubspot.com/private-apps/{portalId}/{appId}/webhooks— read-only view of current subscriptions. Useful for verification after a change.<region>isna1,na2,eu1, etc.https://app-<region>.hubspot.com/private-apps/{portalId}/{appId}/edit— drops you into the editor. From here, click the Webhooks tab in the left rail to reach the subscription editor.
The read-only /webhooks page does not have a "Create subscription" button. Get into edit mode first.
Flow (add a single property subscription)
- Go to
/private-apps/{portalId}/{appId}/editand click the Webhooks tab in the left sidebar. - Click Create subscription — a right-side drawer opens titled "Create new webhook subscriptions".
- Select Which object types? → e.g.
Company. (Coordinate-click required — see gotcha below.) - Select Listen for which events? → e.g.
Property changed. A new "Which properties?" picker appears. - Click the property picker → type the property name into its search box → click the matching option.
- Click Subscribe at the drawer footer. The new row appears in the draft subscription list with
Details / Pause / Unsubscribebuttons. - Close the drawer (Cancel is fine — it cancels only further additions, not the subscription you just created).
- Click Commit changes at the top-right. A short "Saving…" indicator appears; on success the page transitions out of edit mode back to the app detail view.
After commit, HubSpot's docs say webhook settings can take up to 5 minutes to propagate. In practice the new subscription is usually live in seconds — observed sub-30s end-to-end (property edit → webhook delivery) with no provisioning delay.
Gotchas
Object-type / event-type dropdowns are React-Select; .click() on the <div role="option"> doesn't stick
The dropdown items render as <div class="Select-option" role="option"> inside a <div role="listbox"> portal. Calling .click() on that div from JS opens the dropdown and may visually highlight the row, but the selection chip never appears in the form. The form state only updates on a real synthesized mouse event at the option's screen coordinates.
Pattern that works:
// 1. Open the dropdown via the trigger button
const trigger = [...document.querySelectorAll('button')]
.find(b => b.textContent.trim() === 'Select one or more object types');
trigger.click();
// 2. Read the option's coordinates...
const opt = [...document.querySelectorAll('[role="option"]')]
.find(o => o.textContent.trim() === 'Company');
const r = opt.getBoundingClientRect();
// → r.x + r.width/2, r.y + r.height/2
Then issue a coordinate click through CDP at the returned (x, y). .click() from JS will not work; the React-Select widget swallows it.
The Subscribe button's textContent is "SubscribeLoading"
The button renders a co-located loading indicator inside it whose text concatenates with the visible label. Searching for b.textContent.trim() === 'Subscribe' returns nothing. Match with a prefix instead:
const btn = [...document.querySelectorAll('button')]
.find(b => /^Subscribe/.test(b.textContent.trim()));
The button is still functional — the issue is only matching it.
Two-step save: drawer Subscribe ≠ commit
Clicking Subscribe in the drawer adds the row to a draft list that's visible on the left side of the screen while the drawer stays open (so you can keep adding more). Nothing is persisted until you click Commit changes at the top-right. If you close the page after Subscribe but before Commit, the draft is discarded silently.
This is also why Cancel in the drawer doesn't undo the Subscribe you just clicked — it only closes the drawer without adding more subscriptions. The committed/uncommitted state of existing draft rows is independent of the drawer.
Read-only Webhooks tab has its own /webhooks URL; navigation can leave you on the wrong tab
After Commit changes, the page redirects to the app detail view (no /webhooks suffix), which doesn't list the subscriptions. To verify, explicitly navigate to /private-apps/{portalId}/{appId}/webhooks — that's the read-only listing. Don't rely on the post-commit redirect to show you the result.
Cache delay claim: "up to 5 minutes"
HubSpot's banner says "Webhook settings can be cached for up to five minutes. When making changes to the webhook URL, concurrency limit, or subscription settings, it may take up to five minutes to see your changes go into effect." Observed reality: a new subscription delivered events within seconds in one test. Don't rely on the 5-min ceiling for cutover ordering — assume it could be near-instant.
Verification
The read-only Webhooks tab lists each property subscription as its own row. To check programmatically that a specific property is subscribed:
const subscribedProps = (() => {
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
const out = new Set();
let n;
while ((n = walker.nextNode())) {
const t = n.nodeValue.trim();
if (/^(type|name|target_)/.test(t) && t.length < 50 && !t.includes(' ')) {
out.add(t);
}
}
return [...out];
})();
Adjust the regex to your property naming. The "no space" filter excludes the human-readable labels that share the same text node area.
What this skill doesn't cover
- The
expanded object supportbeta toggle in the drawer — not needed for standard property-change subscriptions; leave OFF unless the task explicitly requires it. - Removing a subscription (the
Unsubscribeper-row button) — straightforward; same Commit-changes gate applies. - Webhook target URL changes — different flow (single text input near the top of the Webhooks tab), not covered here.
- Concurrency limit — same; single text input.