@gravity-ai/api 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +4 -552
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,24 +1,6 @@
1
1
  # @gravity-ai/api
2
2
 
3
- The official Node.js/TypeScript SDK for the Gravity AI advertising API. Fetch contextually relevant ads based on conversation content.
4
-
5
- ## Table of Contents
6
-
7
- - [Installation](#installation)
8
- - [Quick Start](#quick-start)
9
- - [Migrating from v0](#migrating-from-v0)
10
- - [Client Configuration](#client-configuration)
11
- - [Integration Types](#integration-types)
12
- - [Web](#web)
13
- - [IDE / CLI](#ide--cli)
14
- - [Mobile](#mobile)
15
- - [General](#general)
16
- - [Response Types](#response-types)
17
- - [Error Handling](#error-handling)
18
- - [Using with React](#using-with-react)
19
- - [Best Practices](#best-practices)
20
-
21
- ---
3
+ The official Node.js/TypeScript SDK for the Gravity AI advertising API.
22
4
 
23
5
  ## Installation
24
6
 
@@ -26,541 +8,11 @@ The official Node.js/TypeScript SDK for the Gravity AI advertising API. Fetch co
26
8
  npm install @gravity-ai/api
27
9
  ```
28
10
 
29
- > **Note:** Requires Node.js 18+
30
-
31
- ---
32
-
33
- ## Quick Start
34
-
35
- ```typescript
36
- import { Client } from '@gravity-ai/api';
37
-
38
- const client = new Client('your-api-key');
39
-
40
- const response = await client.getAd({
41
- messages: [
42
- { role: 'user', content: 'What are some good hiking trails?' },
43
- ],
44
- sessionId: 'session-123',
45
- userId: 'user-456',
46
- numAds: 1,
47
- render_context: {
48
- placements: [{ placement: 'below_response' }]
49
- },
50
- testAd: true,
51
- });
52
-
53
- if (response) {
54
- const ad = response.ads[0];
55
- console.log(ad.adText);
56
- }
57
- ```
58
-
59
- ---
60
-
61
- ## Migrating from v0
62
-
63
- If you're upgrading from a previous version, there are key changes:
64
-
65
- **1. `sessionId` is now required**
66
-
67
- **2. `render_context` object with `placements` array is now required**
68
-
69
- **3. Response format changed to `ads` array**
70
-
71
- ```typescript
72
- // Before (v0)
73
- const ad = await client.getAd({ messages });
74
-
75
- // After (v1)
76
- const response = await client.getAd({
77
- messages,
78
- sessionId: 'session-123',
79
- numAds: 1,
80
- render_context: {
81
- placements: [{ placement: 'below_response' }]
82
- }
83
- });
84
- const ad = response?.ads[0];
85
- ```
86
-
87
- ---
88
-
89
- ## Client Configuration
90
-
91
- ```typescript
92
- import { Client } from '@gravity-ai/api';
93
-
94
- // Basic
95
- const client = new Client('your-api-key');
96
-
97
- // Advanced
98
- const client = new Client('your-api-key', {
99
- excludedTopics: ['politics', 'religion'], // Global exclusions
100
- relevancy: 0.6, // Min relevancy threshold (0.1-1)
101
- });
102
- ```
103
-
104
- | Option | Type | Default | Description |
105
- |--------|------|---------|-------------|
106
- | `endpoint` | `string` | `'https://server.trygravity.ai'` | API endpoint URL |
107
- | `excludedTopics` | `string[]` | `[]` | Topics to exclude from ad matching |
108
- | `relevancy` | `number` | `null` | Minimum relevancy score (0.1-1) |
109
-
110
- ---
111
-
112
- ## Integration Types
113
-
114
- Choose the integration type that matches your application. All types share a **common schema**.
115
-
116
- ### Common Fields
117
-
118
- | Field | Type | Description |
119
- |-------|------|-------------|
120
- | `messages` | `MessageObject[]` | Conversation context. Array of `{role, content}` objects. **Required.** |
121
- | `sessionId` | `string` | Session identifier for frequency capping. **Required.** |
122
- | `render_context` | `RenderContextObject` | Describes how the ad will be rendered in your app. **Required.** |
123
- | `userId` | `string` | Unique user identifier. |
124
- | `testAd` | `boolean` | Returns real ad without tracking. Use for testing. |
125
- | `numAds` | `number` | Number of ads to return (1-3). Must match `placements` length. |
126
-
127
- #### What is `render_context`?
128
-
129
- The `render_context` object describes how the ad will be rendered in your app, so Gravity can generate a more contextually relevant ad.
130
-
131
- For example:
132
- - **`placements`** — Where you plan to show the ad (below the response, in a sidebar, etc.)
133
- - **`max_ad_length`** — Character limit you can display, so we don't send copy that gets truncated
134
- - **`supports_markdown`** — Whether you can render formatted text
135
- - **`supports_images`** — Whether you can display brand logos or product images
136
-
137
- The more context you provide, the better we can optimize the ad copy, format, and creative for your specific integration.
138
-
139
- <details>
140
- <summary><strong>RenderContextObject</strong></summary>
141
-
142
- | Field | Type | Description |
143
- |-------|------|-------------|
144
- | `placements` | `PlacementObject[]` | Array of placement objects (1-3). Length must match `numAds`. **Required.** |
145
- | `max_ad_length` | `number` | Max characters for ad text. |
146
- | `supports_markdown` | `boolean` | Whether markdown rendering is supported. |
147
- | `supports_links` | `boolean` | Whether clickable links are supported. |
148
- | `supports_images` | `boolean` | Whether images can be displayed. |
149
- | `supports_cta_button` | `boolean` | Whether CTA buttons are supported. |
150
-
151
- </details>
152
-
153
- <details>
154
- <summary><strong>PlacementObject</strong></summary>
155
-
156
- | Field | Type | Description |
157
- |-------|------|-------------|
158
- | `placement` | `string` | **Required.** One of: `"above_response"`, `"below_response"`, `"inline_response"`, `"left_response"`, `"right_response"` |
159
- | `placement_id` | `string` | Optional tracking ID for this ad slot. |
160
-
161
- </details>
162
-
163
- <details>
164
- <summary><strong>DeviceObject</strong></summary>
165
-
166
- | Field | Type | Description |
167
- |-------|------|-------------|
168
- | `ip` | `string` | IP address for geo-targeting. **Required.** |
169
- | `ua` | `string` | User agent string. Enables browser/device detection. |
170
- | `os` | `string` | Operating system: `"macos"`, `"windows"`, `"linux"`, `"iOS"`, `"Android"`. |
171
- | `os_version` | `string` | OS version (e.g., `"17.2"`). |
172
- | `browser` | `string` | Browser name: `"chrome"`, `"safari"`, `"firefox"`. |
173
- | `device_type` | `string` | `"desktop"`, `"mobile"`, `"tablet"`. |
174
- | `device_model` | `string` | Device model (e.g., `"iPhone 15 Pro"`). |
175
- | `ifa` | `string` | IDFA/GAID for cross-app attribution. **Higher CPMs.** |
176
- | `timezone` | `string` | IANA timezone (e.g., `"America/New_York"`). |
177
- | `locale` | `string` | Locale (e.g., `"en-US"`). |
178
- | `connection_type` | `string` | `"wifi"` or `"cellular"`. |
179
-
180
- </details>
181
-
182
- <details>
183
- <summary><strong>UserObject</strong></summary>
184
-
185
- | Field | Type | Description |
186
- |-------|------|-------------|
187
- | `email` | `string` | User's email for identity matching. **Higher CPMs.** |
188
- | `gender` | `string` | `"male"`, `"female"`, `"other"`. |
189
- | `age` | `string` | Age range: `"18-24"`, `"25-34"`, `"35-44"`, etc. |
190
- | `keywords` | `string` | Comma-separated interest keywords. |
191
- | `subscription_tier` | `string` | `"free"`, `"pro"`, `"premium"`, `"enterprise"`. |
192
- | `user_created_at` | `string` | Account creation date (ISO 8601). |
193
- | `user_interests` | `string[]` | Array of user interests for targeting. |
194
-
195
- </details>
196
-
197
- ---
198
-
199
- ### Web
200
-
201
- **For:** Chat interfaces, AI assistants, web apps with conversational UI
202
-
203
- #### Web-specific Fields
204
-
205
- | Field | Type | Description |
206
- |-------|------|-------------|
207
- | `web.referrer` | `string` | Referring URL. Enables traffic source targeting. |
208
-
209
- #### Example
210
-
211
- ```typescript
212
- const response = await client.getAd({
213
- // Common fields
214
- messages: [
215
- { role: 'user', content: 'What are the best practices for React performance?' }
216
- ],
217
- sessionId: 'session-web-001',
218
- userId: 'user-web-789',
219
- numAds: 1,
220
- testAd: true,
221
- render_context: {
222
- placements: [
223
- { placement: 'right_response', placement_id: 'sidebar-1' }
224
- ],
225
- max_ad_length: 200
226
- },
227
-
228
- // Web-specific fields
229
- user: {
230
- email: 'webuser@example.com',
231
- subscription_tier: 'pro'
232
- },
233
- device: {
234
- ip: '203.0.113.50',
235
- ua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0',
236
- browser: 'chrome',
237
- device_type: 'desktop',
238
- timezone: 'Europe/London',
239
- locale: 'en-GB'
240
- },
241
- web: {
242
- referrer: 'https://google.com'
243
- }
244
- });
245
- ```
246
-
247
- ---
248
-
249
- ### IDE / CLI
250
-
251
- **For:** Dev tools like Cursor, Claude Code, GitHub Copilot, Windsurf and VS Code extensions
252
-
253
- #### IDE-specific Fields
254
-
255
- <details>
256
- <summary><strong>IDEObject</strong></summary>
257
-
258
- | Field | Type | Description |
259
- |-------|------|-------------|
260
- | `name` | `string` | IDE name: `"cursor"`, `"vscode"`, `"intellij"`. |
261
- | `session_duration_ms` | `number` | Time since IDE opened. Helps with engagement-based targeting. |
262
- | `active_file_language` | `string` | Current file language (e.g., `"typescript"`). |
263
-
264
- </details>
265
-
266
- #### Example
267
-
268
- ```typescript
269
- const response = await client.getAd({
270
- // Common fields
271
- messages: [
272
- { role: 'user', content: 'How do I set up authentication in my Express app?' }
273
- ],
274
- sessionId: 'session-ide-001',
275
- userId: 'user-dev-123',
276
- numAds: 1,
277
- testAd: true,
278
- render_context: {
279
- placements: [
280
- { placement: 'below_response' }
281
- ],
282
- max_ad_length: 280,
283
- supports_markdown: true,
284
- supports_links: true
285
- },
286
-
287
- // IDE-specific fields
288
- user: {
289
- email: 'developer@example.com'
290
- },
291
- device: {
292
- ip: '192.168.1.100',
293
- os: 'macos',
294
- timezone: 'America/New_York',
295
- locale: 'en-US'
296
- },
297
- ide: {
298
- name: 'cursor',
299
- session_duration_ms: 3600000,
300
- active_file_language: 'typescript'
301
- }
302
- });
303
- ```
304
-
305
- ---
306
-
307
- ### Mobile
308
-
309
- **For:** iOS apps, Android apps, React Native, Flutter
310
-
311
- #### Mobile-specific Fields
312
-
313
- <details>
314
- <summary><strong>AppObject</strong></summary>
315
-
316
- | Field | Type | Description |
317
- |-------|------|-------------|
318
- | `version` | `string` | Your app version. |
319
-
320
- </details>
321
-
322
- #### Example
323
-
324
- ```typescript
325
- const response = await client.getAd({
326
- // Common fields
327
- messages: [
328
- { role: 'assistant', content: 'I found several Italian restaurants nearby.' },
329
- { role: 'user', content: 'Which one has the best pasta?' }
330
- ],
331
- sessionId: 'session-mobile-001',
332
- userId: 'user-app-456',
333
- numAds: 1,
334
- testAd: true,
335
- render_context: {
336
- placements: [
337
- { placement: 'inline_response' }
338
- ],
339
- max_ad_length: 150,
340
- supports_images: true,
341
- supports_cta_button: true
342
- },
343
-
344
- // Mobile-specific fields
345
- user: {
346
- email: 'user@example.com',
347
- subscription_tier: 'premium',
348
- user_created_at: '2023-06-15T00:00:00Z',
349
- user_interests: ['food', 'dining', 'travel']
350
- },
351
- device: {
352
- ip: '198.51.100.23',
353
- ua: 'MyApp/2.1.0 (iPhone; iOS 17.2)',
354
- os: 'iOS',
355
- os_version: '17.2',
356
- device_model: 'iPhone 15 Pro',
357
- ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC',
358
- timezone: 'America/Los_Angeles',
359
- locale: 'en-US',
360
- connection_type: 'wifi'
361
- },
362
- app: {
363
- version: '2.1.0'
364
- }
365
- });
366
- ```
367
-
368
- ---
369
-
370
- ### General
371
-
372
- **For:** Any integration not covered above.
373
-
374
- #### Example
375
-
376
- ```typescript
377
- const response = await client.getAd({
378
- // Common fields
379
- messages: [
380
- { role: 'user', content: 'Where can I buy marathon gear?' }
381
- ],
382
- sessionId: 'session-general-001',
383
- userId: 'user-general-123',
384
- numAds: 1,
385
- testAd: true,
386
- render_context: {
387
- placements: [
388
- { placement: 'below_response' }
389
- ]
390
- },
391
-
392
- // Optional fields
393
- device: {
394
- ip: '192.168.1.1',
395
- timezone: 'America/New_York',
396
- locale: 'en-US'
397
- }
398
- });
399
- ```
400
-
401
- ---
402
-
403
- ## Response Types
404
-
405
- ### AdResponse
406
-
407
- ```typescript
408
- interface AdResponse {
409
- ads: Ad[]; // Array of ads (one per placement)
410
- numAds: number; // Number of ads returned
411
- totalPayout?: number; // Total payout across all ads
412
- }
413
- ```
414
-
415
- ### Ad
416
-
417
- ```typescript
418
- interface Ad {
419
- adText: string; // Ad copy text
420
- adId: string; // Unique ad identifier
421
- title?: string; // Ad title
422
- brandName?: string; // Brand name
423
- brandImage?: string; // Brand logo URL
424
- url?: string; // Landing page URL
425
- favicon?: string; // Favicon URL
426
- impUrl?: string; // Impression tracking URL (null for testAd)
427
- clickUrl?: string; // Click-through URL (null for testAd)
428
- payout?: number; // Payout amount (null for testAd)
429
- }
430
- ```
431
-
432
- ### Request Types
433
-
434
- ```typescript
435
- interface MessageObject {
436
- role: 'user' | 'assistant';
437
- content: string;
438
- }
439
-
440
- interface RenderContextObject {
441
- placements: PlacementObject[]; // Required, 1-3 items
442
- max_ad_length?: number;
443
- supports_markdown?: boolean;
444
- supports_links?: boolean;
445
- supports_images?: boolean;
446
- supports_cta_button?: boolean;
447
- }
448
-
449
- interface PlacementObject {
450
- placement: 'above_response' | 'below_response' | 'inline_response' | 'left_response' | 'right_response';
451
- placement_id?: string;
452
- }
453
- ```
454
-
455
- ---
11
+ ## Documentation
456
12
 
457
- ## Error Handling
458
-
459
- The client returns `null` on failure. Errors are logged to console.
460
-
461
- ```typescript
462
- const response = await client.getAd({
463
- messages,
464
- sessionId: 'session-123',
465
- numAds: 1,
466
- render_context: { placements: [{ placement: 'below_response' }] }
467
- });
468
-
469
- // Returns null on:
470
- // - Network errors
471
- // - 401: Invalid API key
472
- // - 422: Validation error (missing sessionId, render_context, or numAds/placements mismatch)
473
- // - 204: No relevant ad found
474
- // - 429: Rate limit exceeded
475
-
476
- if (!response) {
477
- // Handle gracefully - don't break the user experience
478
- }
479
- ```
480
-
481
- | Status | Meaning |
482
- |--------|---------|
483
- | `200` | Ad(s) matched and returned successfully |
484
- | `204` | No matching ads found (null response) |
485
- | `401` | Invalid or missing API key |
486
- | `422` | Validation error (e.g., missing `sessionId`, `render_context`, or `numAds`/`placements` mismatch) |
487
- | `429` | Rate limit exceeded |
488
-
489
- ---
490
-
491
- ## Using with React
492
-
493
- For React applications, use the companion package `@gravity-ai/react`:
494
-
495
- ```bash
496
- npm install @gravity-ai/api @gravity-ai/react
497
- ```
498
-
499
- ```tsx
500
- import { Client } from '@gravity-ai/api';
501
- import { AdBanner } from '@gravity-ai/react';
502
-
503
- const client = new Client('your-api-key');
504
-
505
- function ChatApp() {
506
- const [ad, setAd] = useState(null);
507
-
508
- useEffect(() => {
509
- client.getAd({
510
- messages,
511
- sessionId: 'session-123',
512
- userId: 'user-456',
513
- numAds: 1,
514
- render_context: { placements: [{ placement: 'below_response' }] },
515
- testAd: true,
516
- }).then(res => setAd(res?.ads[0] || null));
517
- }, [messages]);
518
-
519
- return <AdBanner ad={ad} theme="dark" />;
520
- }
521
- ```
522
-
523
- ---
524
-
525
- ## Best Practices
526
-
527
- 1. **`sessionId` and `render_context` are required** — Enable frequency capping and ad placement tracking.
528
-
529
- 2. **`numAds` must match `placements` length** — Request 2 ads? Provide 2 placement objects.
530
-
531
- 3. **Include `userId` when available** — Improves targeting and increases CPMs.
532
-
533
- 4. **Use `testAd: true` during development** — Prevents generating real impressions or clicks.
534
-
535
- 5. **Handle null responses gracefully** — Don't break the UX when no ad is available.
536
-
537
- 6. **Fire `impUrl` when the ad is visible** — Required for proper impression tracking.
538
-
539
- 7. **Include `device.ip` for geo-targeting** — Enables location-based ads and higher CPMs.
540
-
541
- 8. **Include `user.email` when available** — Enables identity matching for significantly higher CPMs.
542
-
543
- ---
544
-
545
- ## TypeScript
546
-
547
- Full TypeScript support with exported types:
548
-
549
- ```typescript
550
- import { Client } from '@gravity-ai/api';
551
- import type {
552
- AdParams,
553
- Ad,
554
- AdResponse,
555
- MessageObject,
556
- RenderContextObject,
557
- PlacementObject,
558
- DeviceObject,
559
- UserObject,
560
- } from '@gravity-ai/api';
561
- ```
13
+ For full documentation, examples, and API reference, visit:
562
14
 
563
- ---
15
+ **[https://www.trygravity.ai/api](https://www.trygravity.ai/api)**
564
16
 
565
17
  ## License
566
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ai/api",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Gravity JS SDK for retrieving targeted advertisements",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",