> ## 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.

# Configuration & delivery

> Client options, batching, retries, and error handling — shared by every Glyph SDK.

Every Glyph SDK uses the same wire contract and delivery behavior. The options below control queueing, batching, retries, and error reporting.

## Client options

JavaScript options are camelCase constructor fields; Python options are snake\_case keyword arguments. Defaults are identical everywhere.

| JavaScript        | Python                   | Default                 | Description                                                                                                                                             |
| ----------------- | ------------------------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `writeKey`        | `write_key`              | — (required)            | Workspace write key. Must start with `glyph_pk_` (live) or `glyph_test_` (test environment).                                                            |
| `flushAt`         | `flush_at`               | `20`                    | Queue size that triggers a flush.                                                                                                                       |
| `flushIntervalMs` | `flush_interval_seconds` | 5 s                     | Time-based flush. JS runs a background timer; see [Python flushing](/docs/sdks/python#flushing) for how the synchronous client applies this at enqueue time. |
| `timeoutMs`       | `timeout_seconds`        | 10 s                    | Per-request timeout.                                                                                                                                    |
| `maxRetries`      | `max_retries`            | `3`                     | Retry attempts after the first failed delivery.                                                                                                         |
| `apiHost`         | `api_host`               | `https://in.glyphhq.io` | Ingest host override.                                                                                                                                   |
| `onError`         | `on_error`               | —                       | Callback invoked when a batch ultimately fails. See [error handling](#error-handling).                                                                  |
| `fetch`           | —                        | global `fetch`          | Custom fetch implementation (JS only).                                                                                                                  |

Platform-specific options — `autoFlush` on the [browser SDK](/docs/sdks/browser), `flushOnExit` on the [Node SDK](/docs/sdks/node) — are documented on their SDK pages.

## Batching

Messages queue in memory and are sent as JSON to `POST /api/v1/ingest` with the write key as a bearer token. A single queued message is sent as a bare object; multiple messages are wrapped in `{ "batch": [...] }`. Batches are capped at **100 messages** — a larger queue drains in successive requests.

Each message includes an SDK-generated UUID in `messageId`. The value stays the same across retries, allowing the server to deduplicate a repeated delivery.

## Timestamps

Without a `timestamp`, the SDK uses the call time in UTC with millisecond precision (`2026-06-05T00:00:00.000Z`). A JavaScript `Date` or Python `datetime` is serialized in the same format. Strings and numbers (epoch milliseconds) pass through unchanged for historical imports.

## Validation

SDK methods validate input before queueing and throw `TypeError` for:

* `userId`, `event`, and `groupId` must be non-empty strings of at most 256 characters.
* `profile` traits must include a non-empty `email`.
* `page` names, when provided, follow the same rules.

Traits and properties must be JSON-serializable objects. Use strings, numbers, booleans, `null`, arrays, and nested objects. Do not send functions, `undefined`, `BigInt`, class instances, or circular references. The complete method shapes are listed in [Message model](/docs/reference/message-model).

## Retries

A delivery attempt that fails with a retryable status — `408`, `429`, `500`, `502`, `503`, `504` — or a network error is retried up to `maxRetries` times with exponential backoff: 500 ms base, doubling per attempt, capped at 30 s, with jitter. A `Retry-After` header on a retryable response is honored.

Non-retryable statuses (for example `401` from a revoked write key, or `422` from an invalid payload) fail immediately without retrying.

The server responds after the transaction commits. If a request times out after committing, a retry sends the same `messageId` and the server deduplicates it.

### Rate limits

Each write key has an ingest budget of **600 messages per 60-second sliding window** by default; some plans have a higher limit. The budget counts messages, not requests. A `429` response includes `Retry-After` and is retryable. If `maxRetries` is exhausted, the SDK returns the batch to the queue for the next flush. Pace sustained sends such as [backfills](/docs/guides/backfill#work-within-the-rate-limit) below the limit.

## Error handling

When a batch exhausts its retries or encounters a non-retryable failure, the error callback receives the error, affected messages, and delivery context:

<CodeGroup>
  ```ts JavaScript theme={"dark"}
  onError: (error, messages, context) => {
    // context: { retryable: boolean, status?: number }
  }
  ```

  ```py Python theme={"dark"}
  def on_error(error, messages, context):
      # context: DeliveryContext(retryable: bool, status: int | None)
      ...
  ```
</CodeGroup>

What happens to the batch depends on whether the failure was retryable:

* **Retryable** (server errors, timeouts, network failures) — the batch goes back on the queue and is attempted again on the next flush. Nothing is lost while the process lives.
* **Non-retryable** (auth or validation failures) — the batch is dropped after `onError` is called. The callback is your only chance to log or persist it.

HTTP delivery failures are reported through the error callback rather than thrown from `track`/`profile`/`group`/`page`. Input validation and serialization errors are programming errors and may still throw at the call site or during an explicit flush.
