# Embed SDK

## Introduction

The Embed SDK enables deeper interaction between your application and Toucan embeds, providing a seamless user experience with complete control over what appears in your embedded content.

To get started, simply navigate to **Admin Area > Embed Manager > Embed Settings** and copy the provided embed SDK script into your application. You’re all set to begin customizing!

<figure><img src="https://1809014303-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZxYYf1KpgarKMgMsDCrw%2Fuploads%2Fgit-blob-0faa9002638d5ef5c0dd865162eda75f2f37535f%2Fembed-sdk.png?alt=media" alt=""><figcaption><p>Embed SDK - scripts</p></figcaption></figure>

## SDK Key

Create a dedicated token for authentication by following the steps in our [Embed SDK Authentication](https://docs-v3.toucantoco.com/visualizations-and-layouts/embedding/embed-sdk/embed-sdk-authentication) documentation.

## Glossary

### **IDs**

* **embedId**: This unique identifier is used in each embed script.
* **DOMId**: A combination of `embedId` and a random hash, allowing you to integrate the same embed multiple times on a single page.

**Example**:

```javascript
// Given
embedId = '62156d3a-8c9c-412b-946c-ddcd59db8da7'

// Then
DOMId = '62156d3a-8c9c-412b-946c-ddcd59db8da7-daderck'
```

### Filters

The SDK provides access to **Filters**, enabling targeted data customization within embeds.

## TcTcEmbed

When you include the embed script, it automatically attaches the `TcTcEmbed` object to `window`, ready for instantiation. Use the following code to initialize:

```javascript
const instance = await TcTcEmbed.initialize();
```

### `getAll()`

**Description**: Returns an array of all embedded HTML elements on the page.\
\
**Parameters**: None\
\
**Returns**: `HTMLElement[]`

**Example**:

```javascript
const instance = await TcTcEmbed.initialize();
const embeds = instance.getAll(); 
// Output: [HTMLElement, HTMLElement...]
```

### `embedDOMIds()`

**Description**: Returns an array of `DOMId`s for all embeds.\
\
**Hint**: `embedId` is not the same as `DOMId` and helps avoid integration issues when using the same embed multiple times on the same page.\
\
**Parameters**: None\
\
**Returns**: `string[]`

**Example**:

```javascript
const embedDOMIds = instance.embedDOMIds();
// Output: ['62156d3a-8c9c-412b-946c-ddcd59db8da7', 'e88b8884-1ce2-45c6-9b84-0b609680989f', ...]
```

### `setExtraVariablesForAllEmbeds()`

**Description**: Sets external context variables for all embeds.

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>variables</code></td><td>object</td><td align="center">✅</td><td>Variables that can be used in the embed content config</td></tr></tbody></table>

**Returns**: `void`

**Example:**

```javascript
const instance = await TcTcEmbed.initialize();

instance.setExtraVariablesForAllEmbeds({ youVariable: 'your value' });
```

### `setFilterValueForAllEmbeds()`

**Description**: Sets a specific filter value for all embeds.

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>filterId</code></td><td>string</td><td align="center">✅</td><td>The ID of the filter whose value you wish to change</td></tr><tr><td><code>value</code></td><td>object</td><td align="center">✅</td><td>The new filter value</td></tr></tbody></table>

**Returns**: `void`

* When using a filter with multiple selectable values (ex. a checkbox filter), to select all values in this filter, you need to send:

```
[{ anyKey: '__VOID__' }]
```

The name of the key (here `anyKey`) can be anything, only the value `__VOID__` matters.

* When using a filter with one selectable value (ex: dropdown filter), to set all values in this filter, you need to send:

```
{ columnName: '__VOID__' }
```

Where columnName is the name of the filtered column in your data.

**Example 1: Main Case**

```javascript
const instance = await TcTcEmbed.intialize();

instance.setFilterValueForAllEmbeds('FILTER_ID', { columnName: 'Customer A' });
```

**Example 2: Select all values of a multiple selector filter**

```javascript
const instance = await TcTcEmbed.intialize();

instance.setFilterValueForAllEmbeds('FILTER_ID', [{ anyKey: 'Customer A' }]);
```

**Example 3: Select all values of a single selector filter**

```javascript
const instance = await TcTcEmbed.intialize();

instance.setFilterValueForAllEmbeds('FILTER_ID', { columnName: 'Customer A' });
```

### `insertEmbedById()`

**Description**: Programmatically inserts an embed into the DOM.

{% hint style="warning" %}
**Important** Requires an authentication token (see [Embed SDK Authentication](https://docs-v3.toucantoco.com/visualizations-and-layouts/embedding/embed-sdk/embed-sdk-authentication))
{% endhint %}

**Parameters:**

<table><thead><tr><th width="296">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>embedId</code></td><td>string</td><td align="center">✅</td><td>The ID of the embed you want to insert</td></tr><tr><td><code>targetEl</code></td><td>HTMLElement</td><td align="center">✅</td><td>The container in which you want to insert your embed</td></tr><tr><td><code>parameters.token</code></td><td>string</td><td align="center">❌</td><td>The token used to identify your user</td></tr><tr><td><code>parameters.filters</code></td><td>Record&#x3C;string, any></td><td align="center">❌</td><td>The initial values of your filters</td></tr><tr><td><code>parameters.panel</code></td><td>boolean</td><td align="center">❌</td><td>To display or hide the additional panel</td></tr><tr><td><code>parameters.header</code></td><td>boolean</td><td align="center">❌</td><td>To display or hide the story’s header</td></tr><tr><td><code>parameters.compact</code></td><td>boolean</td><td align="center">❌</td><td>To force display of compact mode if value is <code>true</code></td></tr><tr><td><code>parameters.stage</code></td><td>string</td><td align="center">❌</td><td>To get the staging version of the application if the value is <code>staging</code></td></tr><tr><td><code>parameters.variables.extra</code></td><td>Record&#x3C;string, any></td><td align="center">❌</td><td>The extra variables you can use in your Toucan embeds</td></tr></tbody></table>

**Returns:**

* **🟢 Success:** `Promise<Embed>`
* **🔴 Error:**
  * If `targetEl` isn't an `HTMLElement`.

**Example:**

```javascript
const instance = await TcTcEmbed.initialize('SDK_AUTH_TOKEN');

await instance.insertEmbedById(
    'MY_EMBED_ID',
    document.getElementById('parent-container'),
    {
        token: 'USER_TOKEN',
        lang: 'en',
        filters: {
            'FILTER_ID': {
                column: 'value'
            }
        },
        panel: false,
        header: true,
        variables: {
            extra: {
                var1: 'valueA'
            }
        }
    }
);
```

**Example with a checkbox filter with multiple values set:**

```javascript
const instance = await TcTcEmbed.initialize('SDK_AUTH_TOKEN');
                
await instance.insertEmbedById(
    'MY_EMBED_ID',
    document.getElementById('parent-container'),
    {
        token: 'USER_TOKEN',
        lang: 'en',
        filters: {
            'FILTER_ID': {
                column: ['value1', 'value2']
            }
        },
        panel: false,
        header: true
    }
);
```

### `destroy()`

**Description**: Destroy the embed and clean up event subscriptions.

**Use case**: You **must** call `destroy()` before reinserting a new embed into the same container, or when the container is removed from the DOM.

This method ensures that:

* Event listeners registered via `subscribe()` or `subscribeToAllEvents()` are removed
* The embed instance is destroyed cleanly

**Returns**: `void`

**Example:**

```javascript
const instance = await TcTcEmbed.initialize('SDK_AUTH_TOKEN');

// Insert an embed
let embed = await instance.insertEmbedById(
    'MY_EMBED_ID',
    document.getElementById('parent-container'),
    {
        token: 'USER_TOKEN',
        lang: 'en'
    }
);

// Later, before inserting a new embed in the same container:
embed.destroy();

embed = await instance.insertEmbedById(
    'OTHER_EMBED_ID',
    document.getElementById('parent-container'),
    {
        token: 'USER_TOKEN',
        lang: 'en'
    }
);
```

**When to use:**

Call `destroy()`:

* Before inserting a new embed into the same container
* When navigating away from the page or view containing the embed
* When the embed's container is being removed from the DOM

{% hint style="success" %}
**Best practice**: Always keep a reference to your embed instance and call `.destroy()` before reusing the same container.
{% endhint %}

{% hint style="info" %}
**Note**: `destroy()` automatically unsubscribes from all SDK-level event listeners registered via `subscribe()` or `subscribeToAllEvents()`.
{% endhint %}

### `get()`

**Description**: Gets an embed instance using either `DOMId` or `embedId`.

{% hint style="info" %}
Using DOMId instead of embedId can be useful if you use the same embed several times on the same page.
{% endhint %}

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>embedId</code> or <code>DOMId</code></td><td>string</td><td align="center">✅</td><td>The ID or DOMId of the embed you want to insert</td></tr><tr><td><code>maxWait</code></td><td>number</td><td align="center">❌</td><td>The maximum waiting time in milliseconds before stopping the search for an embed in the DOM (default: <strong>2000ms</strong>)</td></tr></tbody></table>

**Returns:** `Promise<Embed>`

**Example:**

```javascript
const instance = await TcTcEmbed.initialize();

// With EmbedId
const embed = await instance.get('MY_EMBED_ID');
// With custom max wait time of 5 seconds
const embed = await instance.get('MY_EMBED_ID', 5000);

// With DOMId
const embedDOMIds = instance.embedDOMIds();

const embed = await instance.get(embedDOMIds[0]);
// With custom max wait time of 5 seconds
const embed = await instance.get(embedDOMIds[0], 5000);
```

### `sendPDFReport()`

**Description**: Sends a PDF report synchronously for a targeted application to a list of users.\
Enables synchronous sending of a PDF report for a specific application to a list of recipients. Each recipient is represented as an object containing a token and optional variables. Tokens are used to directly access user context and permissions, including their email (in the `username` field), groups, and any other attributes needed to ensure the correct PDF report is sent.

{% hint style="info" %}
If you don't know what it is, click [here](https://docs-v3.toucantoco.com/visualizations-and-layouts/apps/pdf-report) for more information.
{% endhint %}

{% hint style="warning" %}
**Important** Requires an authentication token (see [Embed SDK Authentication](https://docs-v3.toucantoco.com/visualizations-and-layouts/embedding/embed-sdk/embed-sdk-authentication))
{% endhint %}

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>smallAppUrlPart</code></td><td>string</td><td align="center">✅</td><td>PDF Report's Small App URL<br>Example: if your small app is accessible with the URL <code>https://acme.toucantoco.com/my-app</code>, then use <code>my-app</code></td></tr><tr><td><code>users[].token</code></td><td>string</td><td align="center">✅</td><td>The token used to identify your user</td></tr><tr><td><code>users[].variables</code></td><td>Record&#x3C;string, any></td><td align="center">❌</td><td>Override global variables for specific users</td></tr><tr><td><code>reportId</code></td><td>string</td><td align="center">✅</td><td>Report ID. Can be found in the URL of a given PDF report</td></tr><tr><td><code>variables</code></td><td>Record&#x3C;string, any></td><td align="center">❌</td><td>Filters or extraVariables used into the PDF Report</td></tr></tbody></table>

**Returns:**

* **🟢 Success:** `Promise`
* **🔴 Error:**
  * If any email failed to reach its user.

```javascript
const instance = await TcTcEmbed.initialize('SDK_AUTH_TOKEN');

const my_users = [
  { token: 'AUTH_TOKEN_A' },
  { token: 'AUTH_TOKEN_B' },
  { token: 'AUTH_TOKEN_C', variables: { shop: 'shop B' } },
]

instance.sendPDFReport(
  'my_small_app_id',
  my_users,
  'report_id',
  { shop: 'shop A' },
)
```

All recipients will receive a PDF report for shop A, except the third user, who will receive a report customized for shop B.

## Embed

### `refreshDataQueries()`

**Description**: Refreshes the data in a given embed.

**Parameters:** None

**Returns:** `void`

**Example:**

```javascript
// My user performs an action that changes the data
// As a developer, I want to refresh the data in the displayed story
const instance = await TcTcEmbed.initialize();
const embedDOMIds = instance.embedDOMIds();
const embed = await instance.get(embedDOMIds[0]);

embed.refreshDataQueries();
```

### `filterIds()`

**Description**: Retrieves all filter IDs for a given embed.\
\
**Parameters**: None\
\
**Returns**: `string[]`

{% hint style="warning" %}
Avoid calling this method during initialization, as the filters could not be loaded yet.

Prefer using `getFilterIdsAsync()` instead as it is guaranteed to resolve when the filters have loaded, unlike `filterIds()`.
{% endhint %}

{% hint style="info" %}
Use `filterIds` for scenarios like binding it to a button click or user interaction.
{% endhint %}

**Example:**

```javascript
const filterIds = embed.filterIds();
// ['filterA', 'filterB', ...]
```

### `getFilterIdsAsync()`

**Description**: Retrieves the filter IDs asynchronously. This method guarantees that the filters' configuration is fully loaded before resolving.\
\
**Parameters**: None\
\
**Returns**: `Promise<string[]>`

{% hint style="info" %}
Use this method when you need to ensure that the filters' configuration is fully loaded, such as during the initialization phase.

This method is particularly useful for embedding scenarios where the timing of the filters' configuration load is uncertain.
{% endhint %}

**Example:**

```javascript
const filterIds = await embed.getFilterIdsAsync(); 
// ['filterA', 'filterB', ...]
```

### `getFilter()`

**Description**: Retrieves a specific filter by ID.

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>filterId</code></td><td>string</td><td align="center">✅</td><td>The ID of the filter</td></tr></tbody></table>

**Returns**: `Filter`

**Example:**

```javascript
const filterIds = embed.filterIds();
// ['filterA', 'filterB', ...]

const filterA = embed.getFilter(filterIds[0]);
```

### `setExtraVariables()`

**Description**: Sets additional variables from external context for a given embed.

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>variables</code></td><td>object</td><td align="center">✅</td><td>The extra variables you can use in your Toucan embeds</td></tr></tbody></table>

**Returns**: `void`

**Example:**

```javascript
embed.setExtraVariables({ youVariable: 'your value' });
```

### `downloadPdf()`

**Description**: Renders the document to a PDF and triggers a browser download as soon as it is ready.

{% hint style="warning" %}
**Important** Requires an authentication token (see [Embed SDK Authentication](https://docs-v3.toucantoco.com/visualizations-and-layouts/embedding/embed-sdk/embed-sdk-authentication))
{% endhint %}

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>options.locale</code></td><td><code>'en' | 'fr' | 'jp' | 'es' | 'it'</code></td><td align="center">❌</td><td>Locale to use for generating the document.</td></tr></tbody></table>

**Returns:**

* **🟢 Success:** `Promise<void>` resolving when the PDF has been downloaded.
* **🔴 Error:**
  * If any call to the rendering service fails.
  * If the document fails to be downloaded.

### `exportAsPdfBlob()`

**Description**: Renders the document to a PDF and returns a `Blob` containing the PDF data.\
This is useful if you want to control where the document is going (ex. send it to your own API, display it in a modal, etc.).

{% hint style="warning" %}
**Important** Requires an authentication token (see [Embed SDK Authentication](https://docs-v3.toucantoco.com/visualizations-and-layouts/embedding/embed-sdk/embed-sdk-authentication))
{% endhint %}

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>options.locale</code></td><td><code>'en' | 'fr' | 'jp' | 'es' | 'it'</code></td><td align="center">❌</td><td>Locale to use for generating the document.</td></tr></tbody></table>

**Returns:**

* **🟢 Success:** `Promise<Blob>` resolving with the PDF data.
* **🔴 Error:**
  * If any call to the rendering service fails.
  * If the document fails to be downloaded to a Blob.

### `exportAsPdfPollingUrl()`

**Description**: Renders the document to a PDF and returns a polling API URL that is then used to retrieve the PDF file.\
An example of a use case might involve sending the URL to your own API and let your server process the document asynchronously while the user can leave the page.

Prefer using [`exportAsPdfBlob()`](#exportaspdfblob) if possible, use this method only for backend-to-backend communication that require asynchronous processing.

{% hint style="warning" %}
**Important** Requires an authentication token (see [Embed SDK Authentication](https://docs-v3.toucantoco.com/visualizations-and-layouts/embedding/embed-sdk/embed-sdk-authentication))
{% endhint %}

You **MUST** `GET` the returned URL with proper `Authorization` headers; you may reuse the same token you used to initialize the SDK:

```
Authorization: Bearer <embed_token>
```

You **MUST** poll the returned URL until the document is ready:

1. The URL will return a `404` while the document is being generated; then, continue polling the URL.
2. The URL will return a `200` with the PDF as the body response.
3. Note: The URL will return a `404` after the document has been retrieved a first time in step 2, as the document is being deleted from the rendering service.

{% hint style="warning" %}
**Important** You **MUST NOT** forget to add a retry count and/or timeout limits to your retry mechanism when polling the URL. Ex. Retry a maximum of 10 times with a 5-second delay between each attempt. Please adapt this logic to your use case, as some documents may take longer to generate, depending on the complexity and size of your content.
{% endhint %}

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>options.locale</code></td><td><code>'en' | 'fr' | 'jp' | 'es' | 'it'</code></td><td align="center">❌</td><td>Locale to use for generating the document.</td></tr></tbody></table>

**Returns:**

* **🟢 Success:** `Promise<string>` resolving with the URL to poll.
* **🔴 Error:**
  * If any call to the rendering service fails.

## Event Emitter System

**Description**: Listens to Toucan events for enhanced interaction within embeds.

{% hint style="info" %}
**Supported charts include:**

* Circularchart
* Leaderboard
* Linechart
* Barchart
* Barlinechart
* Heatmap
* Mapchart
* Bulletchart
* Stackedbarchart
  {% endhint %}

### `subscribe`

**Description**: Allows you to listen to Toucan Events. The following events are available:

**Events**:

* `chart:selection`: Triggered when a user selects an element.
* `chart:drill`: Triggered when a user interacts with a drillable element.

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>eventName</code></td><td>TcEvent</td><td align="center">✅</td><td>Toucan Event's name</td></tr><tr><td><code>callback</code></td><td>function</td><td align="center">✅</td><td>The token used to identify your user</td></tr></tbody></table>

**Callback function returns:** `EventData`

{% code title="" %}

```javascript
function callback(eventData: EventData, context: Context)
```

{% endcode %}

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>clickType</code></td><td>string</td><td><p>The corresponding user interaction with the chart. Possible values are: <code>click</code> and <code>dblclick</code></p><p><span data-gb-custom-inline data-tag="emoji" data-code="26a0">⚠️</span> Only supported on Mapcharts</p></td></tr><tr><td><code>dataRow</code></td><td>Record&#x3C;string, any></td><td>The corresponding data row to the user selection</td></tr><tr><td><code>dataLabel</code></td><td>string</td><td>The corresponding value in the column used for the label</td></tr><tr><td><code>type</code></td><td>string</td><td>Chart type selection (e.g: ‘zone’ for a Mapchart, ‘bar’ for a Leaderboard, …)</td></tr></tbody></table>

**Context:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>chartType</code></td><td>string</td><td>Chart's name</td></tr><tr><td><code>embedId</code></td><td>string</td><td>Embed Id</td></tr><tr><td><code>storyId</code></td><td>string</td><td>Story / Tile / Dashboard id</td></tr><tr><td><code>chartIndex</code></td><td>number</td><td>Chart’s index position inside an embedded story</td></tr><tr><td><code>drillInfo</code></td><td>Object</td><td></td></tr><tr><td><code>children</code></td><td>Record&#x3C;string, any></td><td>Children’s data</td></tr><tr><td><code>type</code></td><td>string</td><td>Always equals "drill".</td></tr></tbody></table>

#### `chart:selection`

```javascript
const instance = await TcTcEmbed.initialize();

const embed = await instance.get('my_embed_id');

embed.subscribe('chart:selection', (payload) => {
    // do amazing stuff in your application!
});
```

#### `chart:drill`

```javascript
const instance = await TcTcEmbed.initialize();

const embed = await instance.get('my_embed_id');

embed.subscribe('chart:selection', (payload) => {
    // do amazing stuff in your application!
});
```

### `unsubscribe`

**Description:** Destroy listeners to Toucan events.

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>eventName</code></td><td>TcEvent</td><td align="center">✅</td><td>Toucan Event's name</td></tr></tbody></table>

**Returns**: `void`

**Example:**

```javascript
embed.unsubscribe('chart:selection');
```

## Filter

**Description:** A `Filter` is an interface element used to adjust the data in visualizations, with values based on a specific column in the dataset.

### `values()`

**Description:** Return all data row values for a given `Filter`

**Parameters:** None

**Returns:** `Record<string, any>[]`

**Example:**

```javascript
const myFilter = embed.getFilter('FILTER_ID');

const values = myFilter.values();
// [{ customer: 'Customer A', country: 'USA'}, { customer: 'Customer B', country: 'France }, { customer: 'Customer C', country: 'Spain' }]
```

### `currentValue()`

**Description:** Return the current value for a given `Filter`

**Parameters:** None

**Returns:** `Record<string, any>[]`

**Example:**

```javascript
const myFilter = embed.getFilter('FILTER_ID');

const currentValue = myFilter.currentValue();
// '{ customer: 'Customer A', country: 'USA'}'
```

### `setValue()`

**Description:** Set the current value for a given `Filter`

**Parameters:**

<table><thead><tr><th width="235">Parameter</th><th width="189">Type</th><th width="120" align="center">Mandatory</th><th>Description</th></tr></thead><tbody><tr><td><code>value</code></td><td>any</td><td align="center">✅</td><td>A value that is available in the Filter values</td></tr></tbody></table>

**Returns**: `void`

**Example:**

```javascript
const myFilter = embed.getFilter('FILTER_ID');

myFilter.setValue({ customer: 'Customer B'});

// For hierarchical requesters, you have to specify columns for all level
// Example level 0 = USA
myFilter.setValue({ level0: 'USA' });

// Example level O = USA and level 1 = Minnesota
myFilter.setValue({ level0: 'USA', level1: 'Minnesota' });
```
