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

# Terminal / CLI SDK

> Integrate Gravity ads and tracking into Node.js, Bun, and Deno terminal applications using @gravity-ai/api.

## Installation

```bash theme={null}
npm install @gravity-ai/api
```

Set `GRAVITY_API_KEY` in your server environment.

## How the pieces fit together

<Steps>
  <Step title="Initialize the pixel">
    `gravityPixel()` handles session and visitor tracking automatically. Initialize it once when your app starts.
  </Step>

  <Step title="Prepare context">
    `gravityContext()` captures device signals and session info. Pass the pixel's visitor and session IDs to link tracking with ad requests.
  </Step>

  <Step title="Fetch ads">
    `gravity.getAds(req, messages, placements)` reads the context, adds the client IP, and returns matched ads. Runs in parallel with your LLM call.
  </Step>
</Steps>

## Initialize the pixel

```ts theme={null}
import { gravityPixel } from '@gravity-ai/api';

const pixel = gravityPixel({ pixelId: 'YOUR_PIXEL_ID' });
await pixel.start();
```

Find `YOUR_PIXEL_ID` in your dashboard under **Settings → Platform Settings**.

The pixel automatically manages sessions, visitor IDs, and attribution — same as the browser pixel (`gr-pix.js`), but using local file storage instead of cookies. Session state is persisted and cleaned up automatically on process exit.

| Parameter               | Type      | Default                                        | Description                                                |
| ----------------------- | --------- | ---------------------------------------------- | ---------------------------------------------------------- |
| `pixelId`               | `string`  | —                                              | **Required.** Your Gravity pixel ID.                       |
| `appName`               | `string`  | `'terminal'`                                   | Application label, used as page title in events.           |
| `eventEndpoint`         | `string`  | `'https://api.trygravity.ai/track/gr-events'`  | Event endpoint URL.                                        |
| `sessionEndpoint`       | `string`  | `'https://api.trygravity.ai/track/gr-session'` | Session endpoint URL.                                      |
| `sessionTimeoutMinutes` | `number`  | `30`                                           | Session idle timeout in minutes.                           |
| `attrMaxAgeDays`        | `number`  | `180`                                          | Max age for persisted attribution in days.                 |
| `sessionMaxPages`       | `number`  | `50`                                           | Max entries in invocation history.                         |
| `hashIdentityFields`    | `boolean` | `true`                                         | Hash identity fields with SHA-256 before sending.          |
| `storageDir`            | `string`  | `'~/.gravity'`                                 | Custom storage directory for session and attribution data. |

## Prepare context

```ts theme={null}
import { gravityContext } from '@gravity-ai/api';

const gravity_context = gravityContext({
  sessionId: pixel.getSessionId()!,
  user: {
    userId: currentUser.id,
    gruid: pixel.getVisitorId(),
    grclid: pixel.getClickId(),
    graid: pixel.getGraid(),
  },
});
```

`gravityContext()` auto-detects terminal device signals (OS, timezone, locale). Required parameters:

| Parameter     | Type     | Required | Description                 |
| ------------- | -------- | -------- | --------------------------- |
| `sessionId`   | `string` | Yes      | From `pixel.getSessionId()` |
| `user.userId` | `string` | **Yes**  | Stable per-user identifier  |

## Fetch ads

```ts theme={null}
import { Gravity } from '@gravity-ai/api';

const gravity = new Gravity({ production: true });

const { ads } = await gravity.getAds(
  { body: { gravity_context }, headers: {} },
  messages,
  [{ placement: 'inline_response', placement_id: 'main' }],
);
```

<Warning>
  `gravity.getAds()` never throws. On any failure, it returns `{ ads: [] }` silently. Safe to fire-and-forget.
</Warning>

## Full example

```ts theme={null}
import { gravityPixel, gravityContext, Gravity } from '@gravity-ai/api';

// 1. Initialize pixel
const pixel = gravityPixel({ pixelId: 'YOUR_PIXEL_ID' });
await pixel.start();

// 2. Set up ad client
const gravity = new Gravity({ production: true });

// 3. On each user interaction
async function handleQuery(userId: string, messages: any[]) {
  const ctx = gravityContext({
    sessionId: pixel.getSessionId()!,
    user: {
      userId,
      gruid: pixel.getVisitorId(),
      grclid: pixel.getClickId(),
    },
  });

  const { ads } = await gravity.getAds(
    { body: { gravity_context: ctx }, headers: {} },
    messages,
    [{ placement: 'inline_response', placement_id: 'main' }],
  );

  return ads;
}
```

## FAQ

<AccordionGroup>
  <Accordion title="Do I need a separate package?">
    No. `gravityPixel` ships inside `@gravity-ai/api`. Just `npm install @gravity-ai/api` and import it.
  </Accordion>

  <Accordion title="Does this work in Bun and Deno?">
    Yes. It uses standard APIs and falls back gracefully when Node-specific modules aren't available.
  </Accordion>

  <Accordion title="Does the ad request block my LLM response?">
    No. Fire `gravity.getAds()` in parallel with your LLM call. It never throws, so failures are silent.
  </Accordion>

  <Accordion title="Where does the API key go?">
    Set `GRAVITY_API_KEY` as an environment variable. The `Gravity` class reads it automatically. You can also pass it via `new Gravity({ apiKey: '...' })`.
  </Accordion>
</AccordionGroup>
