<div align="center">
   <a href="https://usercentrics.com"><img src="https://usercentrics.com/wp-content/uploads/2024/09/UC_Web_Black.svg" style="max-width: 250px" alt="Usercentrics" /></a>
</div>

<h1 align="center">Browser SDK V3</h1>
<blockquote align="center">
A lightweight, framework-agnostic SDK for building custom consent management solutions.
</blockquote>

<p align="center">
    <a href="https://usercentrics.com/"><b>Website</b></a> •
    <a href="https://usercentrics.com/docs"><b>Documentation (Coming Soon)</b></a>
</p>

<div align="center">

[![npm version](https://img.shields.io/npm/v/@usercentrics/cmp-web-sdk.svg?style=flat-square)](https://www.npmjs.com/package/@usercentrics/cmp-web-sdk)
[![install size](https://img.shields.io/badge/dynamic/json?url=https://packagephobia.com/v2/api.json?p=@usercentrics/cmp-web-sdk&query=$.install.pretty&label=install%20size&style=flat-square)](https://packagephobia.now.sh/result?p=@usercentrics/cmp-web-sdk)
[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@usercentrics/cmp-web-sdk?style=flat-square)](https://bundlephobia.com/package/@usercentrics/cmp-web-sdk@latest)
[![npm downloads](https://img.shields.io/npm/dm/@usercentrics/cmp-web-sdk.svg?style=flat-square)](https://npm-stat.com/charts.html?package=@usercentrics/cmp-web-sdk)

</div>

## Overview

Browser SDK V3 is a lightweight headless library which you can integrate with your own custom user interface for consent management

> 💡 The SDK includes full TypeScript definitions for all exported classes and methods.

## Table of Contents

  - [Installing](#installing)
    - [Package manager](#package-manager)
  - [Example](#example)
  - [Usercentrics API](#usercentrics-api)
    - [Applying Consent](#applying-consent)
      - [acceptAllConsents](#acceptallconsents)
      - [denyAllConsents](#denyallconsents)
      - [updateServiceConsent](#updateserviceconsent)
      - [updateServicesConsents](#updateservicesconsents)
      - [updateCategoryConsent](#updatecategoryconsent)
      - [updateCategoriesConsents](#updatecategoriesconsents)
      - [saveConsents](#saveconsents)
    - [Data](#data)
      - [getServices](#getservices)
      - [getServicesBaseInfo](#getservicesbaseinfo)
      - [getCategories](#getcategories)
      - [getLanguages](#getlanguages)
    - [Other methods](#other-methods)
      - [changeLanguage](#changelanguage)
      - [areAllConsentsAccepted](#areallconsentsaccepted)
      - [areAllConsentsDenied](#areallconsentsdenied)
      - [getIsConsentRequired](#getisconsentrequired)
  - [Implementation Examples](#implementation-examples)
  - [Building your custom TCF UI](#considerations-for-building-your-custom-tcf-ui)
  - [License](#license)

## Installing

### Package manager

Using npm:

```bash
$ npm install @usercentrics/cmp-web-sdk
```

Using yarn:

```bash
$ yarn add @usercentrics/cmp-web-sdk
```

Once the package is installed, you can import the library using `import` or `require` approach:

```js
import WebSdk, {GdprWebSdk} from '@usercentrics/cmp-web-sdk'
```

You can also use the default export, for a more generic approach:

```js
import WebSdk from '@usercentrics/cmp-web-sdk';
````

If you use `require` for importing, **only default export is available**:

```js
const WebSdk = require('@usercentrics/cmp-web-sdk');
```

For some bundlers and some ES6 linters you may need to do the following:

```js
import { default as WebSdk } from '@usercentrics/cmp-web-sdk';
```

## Example

Initializing the generic SDK
```js
import WebSdk from '@usercentrics/cmp-web-sdk';

(async () => {
    // Create the SDK instance
    const webSdk = new WebSdk();
    const cmpController = await webSdk.initBySetting('YOUR_SETTINGS_ID'); // Initialize the SDK with your SettingsId
})();
```

Initializing the GDPR-specific SDK
```js
import { GdprWebSdk } from '@usercentrics/cmp-web-sdk';

(async () => {
    // Create the SDK instance
    const webSdk = new GdprWebSdk();
    // Initialize the SDK with your SettingsId
    const cmpController = await webSdk.initBySetting('YOUR_SETTINGS_ID'); 
})();
```

Initializing the TCF-specific SDK
```js
import { TcfWebSdk } from '@usercentrics/cmp-web-sdk';

(async () => {
    // Create the SDK instance
    const webSdk = new TcfWebSdk();
    // Initialize the SDK with your SettingsId
    const cmpController = await webSdk.initBySetting('YOUR_SETTINGS_ID'); 
})();
```

Initializing the US-specific SDK
```js
import { UsWebSdk } from '@usercentrics/cmp-web-sdk';

(async () => {
    // Create the SDK instance
    const webSdk = new UsWebSdk();
    // Initialize the SDK with your SettingsId
    const cmpController = await webSdk.initBySetting('YOUR_SETTINGS_ID');
})();
```

## Usercentrics API

### Applying Consent

##### acceptAllConsents

```js
await webSdk.acceptAllConsents();
```

##### denyAllConsents

```js
await webSdk.denyAllConsents();
```

##### updateServiceConsent

Update a single service consent

```js
await webSdk.updateServiceConsent({
    id: 'SERVICE_ID',
    consent: true, // or false
});
```

##### updateServicesConsents

Update multiple services consents

```js
await webSdk.updateServicesConsents([
  {
    id: 'SERVICE_ID_1',
    consent: true, // or false
  },
  {
    id: 'SERVICE_ID_2',
    consent: false, // or true
  }
]);
```

##### updateCategoryConsent

Update a Category consent

```js
await webSdk.updateCategoryConsent({
  id: 'CATEGORY_ID',
  consent: true, // or false
});
```

##### updateCategoriesConsents

Update multiple categories consents

```js
await webSdk.updateCategoriesConsents([
  {
    id: 'CATEGORY_ID_1',
    consent: true, // or false
  },
  {
    id: 'CATEGORY_ID_2',
    consent: false, // or true
  },
]);
```

#### saveConsents

> **Note**: Consent usage
> All of the above methods just change the consent state internally
> to persist the user decision (e.g. after a save consent button click by the user) you need to persist/save the consents

```js
await webSdk.saveConsents();
```

### Data

#### getServices
```js
await webSdk.getServices();
```

#### getServicesBaseInfo
```js
await webSdk.getServicesBaseInfo();
```

#### getCategories
```js
await webSdk.getCategories();
```

#### getLanguages
```js
await webSdk.getLanguages();
```

### Other methods

#### changeLanguage
Change the language to a supported language
For the list of supported languages, please refer to [getLanguages](#getLanguages)
```js
await webSdk.changeLanguage('en');
```

#### areAllConsentsAccepted
Returns `true` if all the consents are accepted
```js
const allConsentsAccepted = await webSdk.areAllConsentsAccepted();
```

#### areAllConsentsDenied
Returns `true` if all the consents are denied
```js
const allConsentsDenied = await webSdk.areAllConsentsDenied();
```

#### getIsConsentRequired
Returns `true` if a user decision is needed
```js
const isConsentRequired = await webSdk.getIsConsentRequired();
```

## Implementation Examples

### GDPR

```js
// import GDPR optimized GdprWebSdk
import { GdprWebSdk, GdprCmpController, UiView } from '@usercentrics/cmp-web-sdk';

// Vanilla JS view
class CmpView {
  private cmpController: GdprCmpController;
  private cmpElement: HTMLDivElement;

  constructor(cmpController: GdprCmpController) {
    this.cmpController = cmpController;
  }

  public async init() {
    // create and attach the ui view
      
    const cmpElement = document.createElement('div');
    cmpElement.id = 'cmp';

    if (typeof cmpElement.attachShadow === 'function') {
      // optional: attach shadow
      cmpElement.attachShadow({ mode: 'open' });
    }

    this.cmpElement = (cmpElement.shadowRoot as HTMLDivElement) || cmpElement;
    this.setView(this.cmpController.ui.initialView || 'none');

    return new Promise((resolve) => {
      if (document.body) {
        document.body.appendChild(cmpElement);
        resolve();
      }

      document.addEventListener('DOMContentLoaded', () => {
        document.body.append(cmpElement);
        resolve();
      });
    });
  }

  public setView(view: UiView) {
    const consents = JSON.stringify(this.cmpController.dps.getServicesConsents()); // data example

    switch (view) {
      case 'none':
        // do not show the cmp, do not show a cmp button/trigger
        this.cmpElement.innerHTML = '';
        break;
      case 'button':
        // do not show the cmp, show a cmp button/trigger
        this.cmpElement.innerHTML = 'custom button view';
        break;
      case 'first':
        // the cmp needs to be shown
        this.cmpElement.innerHTML = `custom first layer view: ${consents}`;
        break;
      case 'second':
        //  the optional custom secondary layer (never an initial view)
        this.cmpElement.innerHTML = `custom second layer view ${consents}`;
        break;
    }
  }
}

(async () => {
  const gdprWebSdk = new GdprWebSdk();
  const gdprCmpController = await gdprWebSdk.initBySetting('YOUR_GDPR_SETTINGS_ID');

  const cmpView = new CmpView(gdprCmpController);
  await cmpView.init();
})();
```

## Considerations for building your custom TCF UI

> Note: This does NOT apply if you use the unaltered Usercentrics UI together with this SDK

If you plan to build your own custom UI for TCF, Usercentrics cannot be liable that your custom UI conforms to all the IAB rules and guidelines. In this case, you can still use this SDK, but you need to register your solution at the IAB yourself. You can then enter your cmp-id (provided by the IAB) and cmp-version through the Usercentrics Admin Interface.

In the case that you build your own TCF UI it is **NOT** allowed to use the default Usercentrics cmp-id and cmp-version.

## License

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)