> ## Documentation Index
> Fetch the complete documentation index at: https://www.glyphhq.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Message model

> Method signatures, identity rules, and JSON value constraints shared by the Glyph SDKs.

Glyph accepts four message types: `profile`, `track`, `group`, and `page`. Every message belongs to the workspace named by its write key and to the customer named by `userId`.

## Identity

`userId` is the durable customer identity key. Send the stable identifier from your own database, not an email address or a value that can change.

A `profile` must also include `traits.email`. Glyph uses the address to display and contact the customer; `userId` remains the identity key.

Glyph does not accept anonymous identities or provide aliasing. Start sending messages once you know the customer.

## JavaScript and TypeScript

The browser and Node.js clients share these methods:

```ts theme={"dark"}
profile(userId: string, traits: ProfileTraits, options?: MessageOptions): Promise<void>

track(
  userId: string,
  event: string,
  properties?: JsonObject,
  options?: MessageOptions,
): Promise<void>

group(
  userId: string,
  groupId: string,
  traits?: JsonObject,
  options?: MessageOptions,
): Promise<void>
```

The browser client additionally provides:

```ts theme={"dark"}
page(
  userId: string,
  name?: string,
  properties?: JsonObject,
  options?: MessageOptions,
): Promise<void>
```

`MessageOptions` currently contains `timestamp?: Date | number | string`. The promise resolves after queueing and after any flush triggered by `flushAt`. Call `flush()` when the process must wait for an immediate delivery attempt.

## Python

The synchronous Python client provides:

```py theme={"dark"}
profile(user_id, traits, *, timestamp=None)
track(user_id, event, properties=None, *, timestamp=None)
group(user_id, group_id, traits=None, *, timestamp=None)
```

Python does not expose `page`. Use the browser SDK or the [HTTP API](/docs/reference/http-api) when you need page messages.

Methods return `None`. Enqueueing can block for delivery when the queue reaches `flush_at` or the flush interval has elapsed. Call `flush()` or `close()` before a short-lived process exits.

## Message fields

| Message   | Required fields          | Optional fields                   | Product behavior                                                                                           |
| --------- | ------------------------ | --------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `profile` | `userId`, `traits.email` | Other traits, `timestamp`         | Creates or shallowly updates customer traits.                                                              |
| `track`   | `userId`, `event`        | `properties`, `timestamp`         | Adds an event to the customer timeline.                                                                    |
| `group`   | `userId`, `groupId`      | `traits`, `timestamp`             | Adds account context as a timeline event. It does not create a separate account record or group analytics. |
| `page`    | `userId`                 | `name`, `properties`, `timestamp` | Adds a page-view event. Publicly exposed by the browser SDK only.                                          |

`userId`, `event`, `groupId`, and a supplied page name must be non-empty strings of at most 256 characters. Profile email must also be a non-empty string of at most 256 characters.

## JSON values

Traits and properties must be JSON-serializable objects. Valid values are strings, finite numbers, booleans, `null`, arrays, and nested objects containing those values.

Do not send functions, `undefined`, `BigInt`, class instances, byte buffers, or circular references. Keep event properties small and focused on the moment; put durable customer attributes in profile traits.

## Validation and delivery failures

Invalid identifiers and profile traits fail before the message is queued. JavaScript throws a `TypeError`; Python raises `TypeError`.

HTTP and network failures follow the retry and callback behavior in [Configuration & delivery](/docs/reference/configuration#error-handling). An explicit `flush()` waits for the delivery attempt, but HTTP failures are reported through `onError` or `on_error` instead of being raised as application errors.
