npm package: @praevis/web-sdk
Description: Praevis Exchange Web SDK - OpenRTB 2.6 compliant ad serving for publishers
Author: Praevis by Nucleus AI
Latest version: 1.0.0

# Praevis Exchange Web SDK

Official JavaScript/TypeScript SDK for integrating with Praevis Exchange. This lightweight SDK handles OpenRTB 2.6 bid requests, ad rendering, and event tracking.

## Features

- ✅ **OpenRTB 2.6 Compliant** - Full support for OpenRTB bid requests
- ✅ **TypeScript Support** - Complete type definitions included
- ✅ **Automatic Device Detection** - Collects device and site information
- ✅ **Event Tracking** - Built-in impression and click tracking
- ✅ **Easy Integration** - Simple API for requesting and rendering ads
- ✅ **Zero Dependencies** - Pure TypeScript, no external libraries
- ✅ **Universal Format** - UMD and ESM builds for any environment

## Installation

### NPM/Yarn

```bash
npm install @praevis/web-sdk
# or
yarn add @praevis/web-sdk
```

### CDN (Script Tag)

```html
<script src="https://unpkg.com/@praevis/web-sdk@latest/dist/praevis-sdk.min.js"></script>
<script>
  // SDK is available as window.PraevisSDK.default
  const sdk = new window.PraevisSDK.default({
    apiKey: 'pub_your_api_key'
  });
</script>
```

## Quick Start

### 1. Initialize the SDK

```javascript
import { PraevisSDK } from '@praevis/web-sdk';
// or
import PraevisSDK from '@praevis/web-sdk'; // default export

const sdk = new PraevisSDK({
  apiKey: 'pub_your_api_key_here', // Get from dashboard
  endpoint: 'https://exchange.praevis.com/rtb', // Optional, defaults to production
  timeout: 2000, // Optional, default 2000ms
  debug: false, // Optional, enable console logging
});
```

### 2. Add Ad Placeholders to HTML

```html
<div id="ad-banner-1"></div>
<div id="ad-banner-2"></div>
```

### 3. Request and Render Ads

```javascript
// Request and render in one call (recommended)
await sdk.renderAd({
  elementId: 'ad-banner-1',
  width: 300,
  height: 250,
  bidfloor: 0.75, // Minimum CPM in USD
});
```

## Usage Examples

### Basic Banner Ad

```javascript
const sdk = new PraevisSDK({
  apiKey: 'pub_smarttv_apps',
});

// Render a 300x250 banner
await sdk.renderAd({
  elementId: 'sidebar-ad',
  width: 300,
  height: 250,
  bidfloor: 1.0,
});
```

### Multiple Ad Units

```javascript
const adUnits = [
  { elementId: 'header-ad', width: 728, height: 90, bidfloor: 2.0 },
  { elementId: 'sidebar-ad', width: 300, height: 250, bidfloor: 1.5 },
  { elementId: 'footer-ad', width: 320, height: 50, bidfloor: 0.5 },
];

// Request all ads in parallel
await Promise.all(adUnits.map((unit) => sdk.renderAd(unit)));
```

### Manual Request and Render

```javascript
// Request bid only
const bidResponse = await sdk.requestAd({
  elementId: 'custom-ad',
  width: 300,
  height: 250,
  bidfloor: 1.0,
});

// Check if we got a bid
if (bidResponse.seatbid && bidResponse.seatbid.length > 0) {
  const bid = bidResponse.seatbid[0].bid[0];
  console.log('Won bid at $' + bid.price + ' CPM');

  // Manually render the ad
  const element = document.getElementById('custom-ad');
  element.innerHTML = bid.adm;
}
```

### With Custom Click Tracking

```javascript
await sdk.renderAd(
  {
    elementId: 'tracked-ad',
    width: 300,
    height: 250,
    bidfloor: 1.0,
  },
  {
    trackImpression: true, // Default: true
    trackClick: true, // Default: true
    clickUrl: 'https://your-tracking-url.com/click', // Optional custom URL
  }
);
```

### Error Handling

```javascript
try {
  const success = await sdk.renderAd({
    elementId: 'my-ad',
    width: 300,
    height: 250,
  });

  if (!success) {
    console.log('No bid received, showing fallback ad');
    // Show your house ad or other fallback
  }
} catch (error) {
  console.error('Ad request failed:', error);
}
```

### Debug Mode

```javascript
const sdk = new PraevisSDK({
  apiKey: 'pub_test_key',
  debug: true, // Enable detailed console logging
});

// All requests will log:
// - Bid requests sent
// - Bid responses received
// - Rendering events
// - Tracking events
// - Errors
```

## API Reference

### `new PraevisSDK(config)`

Initialize the SDK with configuration.

**Parameters:**

| Parameter         | Type      | Required | Default                              | Description                     |
| ----------------- | --------- | -------- | ------------------------------------ | ------------------------------- |
| `config.apiKey`   | `string`  | Yes      | -                                    | Your publisher API key          |
| `config.endpoint` | `string`  | No       | `https://exchange.praevis.com/rtb`   | Exchange endpoint URL           |
| `config.timeout`  | `number`  | No       | `2000`                               | Request timeout in milliseconds |
| `config.debug`    | `boolean` | No       | `false`                              | Enable debug logging            |

**Example:**

```javascript
const sdk = new PraevisSDK({
  apiKey: 'pub_prod_news001',
  timeout: 3000,
  debug: process.env.NODE_ENV === 'development',
});
```

### `sdk.requestAd(adUnit)`

Request a bid for an ad unit.

**Parameters:**

| Parameter          | Type     | Required | Default | Description                 |
| ------------------ | -------- | -------- | ------- | --------------------------- |
| `adUnit.elementId` | `string` | Yes      | -       | HTML element ID for the ad  |
| `adUnit.width`     | `number` | Yes      | -       | Ad width in pixels          |
| `adUnit.height`    | `number` | Yes      | -       | Ad height in pixels         |
| `adUnit.bidfloor`  | `number` | No       | `0.01`  | Minimum bid price (CPM USD) |

**Returns:** `Promise<BidResponse>` - OpenRTB 2.6 bid response

**Example:**

```javascript
const response = await sdk.requestAd({
  elementId: 'my-ad',
  width: 300,
  height: 250,
  bidfloor: 1.5,
});
```

### `sdk.renderAd(adUnit, options?)`

Request and render an ad in one call.

**Parameters:**

| Parameter                   | Type      | Required | Default | Description                      |
| --------------------------- | --------- | -------- | ------- | -------------------------------- |
| `adUnit`                    | `AdUnit`  | Yes      | -       | Ad unit configuration (see above) |
| `options.trackImpression`   | `boolean` | No       | `true`  | Fire impression tracking pixel   |
| `options.trackClick`        | `boolean` | No       | `true`  | Fire click tracking pixel        |
| `options.clickUrl`          | `string`  | No       | -       | Custom click tracking URL        |

**Returns:** `Promise<boolean>` - `true` if ad rendered successfully, `false` if no bid

**Example:**

```javascript
const success = await sdk.renderAd(
  {
    elementId: 'my-ad',
    width: 728,
    height: 90,
    bidfloor: 2.0,
  },
  {
    trackImpression: true,
    trackClick: true,
  }
);
```

## Common Ad Sizes

| Size        | Width | Height | Common Name         |
| ----------- | ----- | ------ | ------------------- |
| 300x250     | 300   | 250    | Medium Rectangle    |
| 728x90      | 728   | 90     | Leaderboard         |
| 160x600     | 160   | 600    | Wide Skyscraper     |
| 320x50      | 320   | 50     | Mobile Banner       |
| 300x600     | 300   | 600    | Half-Page Ad        |
| 970x250     | 970   | 250    | Billboard           |
| 320x100     | 320   | 100    | Large Mobile Banner |

## Browser Support

- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
- Opera 76+
- Mobile browsers (iOS Safari 14+, Chrome Android 90+)

## Privacy & Compliance

The SDK automatically:
- Respects user's Do Not Track (DNT) preference
- Collects only necessary device information
- Does not store cookies or local storage (except for tracking consent if you implement it)
- Compliant with GDPR, CCPA, and COPPA

**User Consent:**
You are responsible for obtaining user consent before serving personalized ads. See our [Privacy Policy](https://praevis.com/privacy) for details.

```javascript
// Example: Only initialize SDK after user consent
if (userHasConsentedToAds()) {
  const sdk = new PraevisSDK({ apiKey: 'pub_key' });
  await sdk.renderAd({ elementId: 'ad', width: 300, height: 250 });
}
```

## TypeScript Support

Full TypeScript definitions are included:

```typescript
import PraevisSDK, { PraevisConfig, AdUnit, BidResponse } from '@praevis/web-sdk';

const config: PraevisConfig = {
  apiKey: 'pub_key',
  timeout: 3000,
};

const sdk = new PraevisSDK(config);

const adUnit: AdUnit = {
  elementId: 'my-ad',
  width: 300,
  height: 250,
  bidfloor: 1.0,
};

const response: BidResponse = await sdk.requestAd(adUnit);
```

## Troubleshooting

### No Ads Showing

1. **Check API Key**: Verify your API key in the dashboard
2. **Check Console**: Enable `debug: true` to see detailed logs
3. **Check Bid Floor**: Try lowering `bidfloor` (e.g., `0.01`)
4. **Check Element**: Ensure the HTML element exists before calling `renderAd`

### Slow Ad Loading

1. **Reduce Timeout**: Lower `timeout` to fail faster (e.g., `1000ms`)
2. **Check Network**: Use browser DevTools to inspect network requests
3. **Parallelize Requests**: Use `Promise.all()` for multiple ads

### CORS Errors

The Praevis Exchange API allows cross-origin requests. If you see CORS errors:
1. Verify you're using the correct endpoint
2. Check that your domain is registered in the dashboard
3. Ensure you're sending the correct API key

## Examples

### React Component

```jsx
import { useEffect, useState } from 'react';
import PraevisSDK from '@praevis/web-sdk';

function AdBanner({ width, height, bidfloor }) {
  const [sdk] = useState(() => new PraevisSDK({ apiKey: 'pub_key' }));
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    sdk
      .renderAd({
        elementId: 'react-ad',
        width,
        height,
        bidfloor,
      })
      .then(setLoaded);
  }, [sdk, width, height, bidfloor]);

  return (
    <div>
      <div id="react-ad"></div>
      {!loaded && <div>Loading ad...</div>}
    </div>
  );
}
```

### Vue Component

```vue
<template>
  <div>
    <div :id="elementId"></div>
    <div v-if="!loaded">Loading ad...</div>
  </div>
</template>

<script>
import PraevisSDK from '@praevis/web-sdk';

export default {
  props: ['width', 'height', 'bidfloor'],
  data() {
    return {
      elementId: 'vue-ad-' + Math.random().toString(36).slice(2),
      loaded: false,
      sdk: new PraevisSDK({ apiKey: 'pub_key' }),
    };
  },
  mounted() {
    this.sdk
      .renderAd({
        elementId: this.elementId,
        width: this.width,
        height: this.height,
        bidfloor: this.bidfloor,
      })
      .then((success) => {
        this.loaded = success;
      });
  },
};
</script>
```

### Next.js Page

```jsx
'use client';

import { useEffect, useRef } from 'react';
import PraevisSDK from '@praevis/web-sdk';

export default function AdPage() {
  const sdkRef = useRef(null);

  useEffect(() => {
    if (!sdkRef.current) {
      sdkRef.current = new PraevisSDK({ apiKey: 'pub_key' });
    }

    sdkRef.current.renderAd({
      elementId: 'nextjs-ad',
      width: 300,
      height: 250,
      bidfloor: 1.0,
    });
  }, []);

  return (
    <div>
      <h1>My Next.js Page</h1>
      <div id="nextjs-ad"></div>
    </div>
  );
}
```

## Support

- **Documentation**: https://docs.praevis.com
- **Email**: support@praevis.com
- **Dashboard**: https://dashboard.praevis.com

## License

MIT License - see LICENSE file for details

## Changelog

### v1.0.0 (2025-11-04)

- Initial release
- OpenRTB 2.6 support
- TypeScript definitions
- Automatic device detection
- Event tracking
- UMD and ESM builds