> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# HubSpot

<!-- -->

[Server](#)[ ](https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/hubspot)

<!-- -->

[Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/hubspot)[ ](https://www.npmjs.com/package/@walkeros/server-destination-hubspot)

<!-- -->

[Package](https://www.npmjs.com/package/@walkeros/server-destination-hubspot)

<!-- -->

Beta

Server-side event delivery to [HubSpot](https://www.hubspot.com/) via the official [`@hubspot/api-client`](https://www.npmjs.com/package/@hubspot/api-client) SDK. Sends custom behavioral events, upserts contacts via the CRM API, and supports optional batch mode with graceful shutdown.

<!-- -->

Where this fits

HubSpot is a **server destination** in the walkerOS flow:

Receives events server-side from the collector, resolves contact identity (email or objectId), optionally upserts contact properties, then sends the custom event to HubSpot.

## Installation[​](#installation "Direct link to Installation")

```
npm install @walkeros/server-destination-hubspot
```

* Integrated
* Bundled

```
import { startFlow } from '@walkeros/collector';
import { destinationHubspot } from '@walkeros/server-destination-hubspot';

await startFlow({
  destinations: {
    hubspot: {
      code: destinationHubspot,
      config: {
        settings: {
          accessToken: 'YOUR_HUBSPOT_ACCESS_TOKEN',
          eventNamePrefix: 'pe12345678_',
        },
      },
    },
  },
});
```

Add to your `flow.json` destinations:

```
"destinations": {
  "hubspot": {
    "package": "@walkeros/server-destination-hubspot",
    "config": {
      "settings": {
        "accessToken": "YOUR_HUBSPOT_ACCESS_TOKEN",
        "eventNamePrefix": "pe12345678_"
      }
    }
  }
}
```

[See bundled mode setup](https://www.walkeros.io/docs/getting-started/modes/bundled.md) | [CLI reference](https://www.walkeros.io/docs/apps/cli.md)

## Configuration[​](#configuration "Direct link to Configuration")

This <!-- -->destination<!-- --> uses the standard <!-- -->destination<!-- --> config wrapper (consent, data, env, id, ...). For the shared fields see [destination<!-- --> configuration](https://www.walkeros.io/docs/destinations.md#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to Settings")

| Property            | Type                     | Description                                                                                                                                       | More |
| ------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `accessToken*`      | `string`                 | HubSpot private app access token. Create one in HubSpot Settings > Integrations > Private Apps. Requires analytics.behavioral\_events.send scope. |      |
| `eventNamePrefix*`  | `string`                 | Fully qualified event name prefix: pe{HubID}\_ (e.g. pe12345678\_). Find it in HubSpot under Data Management > Custom Events.                     |      |
| `email`             | `string`                 | walkerOS mapping value path to resolve contact email from events (like user.email). Required for contact association.                             |      |
| `objectId`          | `string`                 | walkerOS mapping value path to resolve HubSpot CRM objectId from events. Alternative to email for contact association.                            |      |
| `identify`          | `any`                    | Destination-level contact upsert mapping. Resolves to { email, properties }. Fires contact update on first push and re-fires when values change.  |      |
| `defaultProperties` | `Record<string, string>` | Static event properties added to every event occurrence. Useful for hs\_touchpoint\_source, hs\_page\_content\_type, etc.                         |      |
| `batch`             | `boolean`                | Use batch API for events (accumulate and flush). Default: false.                                                                                  |      |
| `batchSize`         | `integer`                | Batch size before auto-flush. Only used when batch: true. Default: 50. Max: 500.                                                                  |      |

\* Required fields

## Mapping[​](#mapping "Direct link to Mapping")

Per-event rules under `config.mapping`. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

| Property     | Type     | Description                                                                                                                                                  | More |
| ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- |
| `eventName`  | `string` | Override eventName for this rule. Without the prefix -- just the event name part (e.g. purchase\_completed). The eventNamePrefix is prepended automatically. |      |
| `identify`   | `any`    | Per-event contact upsert. Resolves to { email, properties }. Overrides destination-level identify. Use with silent: true on login/identify events.           |      |
| `properties` | `any`    | Additional event properties mapping. Resolved values are merged with defaultProperties and serialized to strings.                                            |      |

## Examples

### Default event

A walker event is sent to HubSpot as a custom behavioral event keyed by the user email.

Event

```
{
  "name": "product view",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "detail",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "email": "user@example.com"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "e5f46aac7f076491",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000100,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
events.send.basicApi.send({
  "eventName": "pe12345678_product_view",
  "email": "user@example.com",
  "occurredAt": {},
  "properties": {}
})
```

### Default properties

Destination-level default properties are merged into every HubSpot event payload, such as traffic source metadata.

Event

```
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "email": "user@example.com"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "30a3574bfbc23ac5",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000102,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
events.send.basicApi.send({
  "eventName": "pe12345678_page_view",
  "email": "user@example.com",
  "occurredAt": {},
  "properties": {
    "hs_touchpoint_source": "walkerOS",
    "hs_page_content_type": "STANDARD_PAGE"
  }
})
```

### Destination identify

Destination-level identify upserts the HubSpot contact with mapped properties before sending the behavioral event.

Event

```
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "email": "user@example.com",
    "firstName": "Jane",
    "lastName": "Doe"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "e016c5b6a0688987",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000103,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
crm.contacts.basicApi.update("user@example.com", {
  "properties": {
    "firstname": "Jane",
    "lastname": "Doe"
  }
}, "email");

events.send.basicApi.send({
  "eventName": "pe12345678_page_view",
  "email": "user@example.com",
  "occurredAt": {},
  "properties": {}
})
```

### Custom event name

A mapping supplies a custom HubSpot event name and maps order data into properties for the behavioral event.

Event

```
{
  "name": "order complete",
  "data": {
    "total": 99.5,
    "currency": "EUR",
    "id": "ord-123"
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "email": "user@example.com"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "1f13c5da9788a31b",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000101,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "order complete",
  "settings": {
    "eventName": "purchase_completed",
    "properties": {
      "map": {
        "revenue": "data.total",
        "currency": "data.currency",
        "order_id": "data.id"
      }
    }
  }
}
```

Out

```
events.send.basicApi.send({
  "eventName": "pe12345678_purchase_completed",
  "email": "user@example.com",
  "occurredAt": {},
  "properties": {
    "revenue": "99.5",
    "currency": "EUR",
    "order_id": "ord-123"
  }
})
```

### Object id association

The HubSpot event is associated via objectId instead of email, resolved from the walker user id.

Event

```
{
  "name": "product view",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "detail",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "hs-contact-789"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "4b85ffe33bdcc561",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000105,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
events.send.basicApi.send({
  "eventName": "pe12345678_product_view",
  "objectId": "hs-contact-789",
  "occurredAt": {},
  "properties": {}
})
```

### User login identify

A user login only upserts the HubSpot contact with profile and lifecycle properties, skipping the event send.

Event

```
{
  "name": "user login",
  "data": {
    "email": "login@acme.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "lifecycle": "lead"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "lang": "elb"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "email": "user@example.com"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "cd093b34b5580de4",
  "trigger": "test",
  "entity": "user",
  "action": "login",
  "timestamp": 1700000104,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "silent": true,
  "settings": {
    "identify": {
      "map": {
        "email": "data.email",
        "properties": {
          "map": {
            "firstname": "data.first_name",
            "lastname": "data.last_name",
            "lifecyclestage": "data.lifecycle"
          }
        }
      }
    }
  }
}
```

Out

```
crm.contacts.basicApi.update("login@acme.com", {
  "properties": {
    "firstname": "Jane",
    "lastname": "Doe",
    "lifecyclestage": "lead"
  }
}, "email")
```

Every event must be associated with a contact via `email` or `objectId`. The `email` path defaults to `user.email`. Events where neither value can be resolved are skipped with a warning.

## Contact upsert[​](#contact-upsert "Direct link to Contact upsert")

Use the `identify` setting (destination-level or per-rule) to upsert HubSpot contact properties alongside event tracking. The resolved mapping must produce `{ email, properties }`. State-based dedup prevents redundant API calls when identity has not changed.
