# Transcription Viewer Integration Guide

This guide explains how to integrate and use the Transcription Viewer single-page application in an existing web application. The Transcription Viewer single-page application allows users to view an individual Transcript in detail.

> \[!NOTE]
>
> In past pre-release documentation, the Transcription Viewer single-page application was called Annotator or Conversation Viewer. The old name is still used in some places, such as app retrieval URLs.

![The Conversational Intelligence Transcription Viewer single-page application UI.](./voice_intelligence_transcription_viewer.png)

You can embed the single-page application's UI into an existing web app or render it in a new window. In both cases, the app requests the single-page application's code by calling a specific URL with an authorization token.

A [sample implementation of the single-page application](https://github.com/twilio/voice-intelligence-samples/tree/main/transcript-viewer-integration-demo) is available on GitHub for reference.

## Prerequisites

Before beginning this guide, complete these steps:

* [Create a Twilio Account](https://www.twilio.com/try-twilio).
  * Note the Account SID and Auth Token from the [Console](https://console.twilio.com/).
* [Create an Intelligence Service](/docs/conversational-intelligence/onboarding#services).
  * Note the SID of the Service from the [API](/docs/conversational-intelligence/api/service-resource#fetch-a-service) or the [Console](https://console.twilio.com/us1/develop/conversational-intelligence/services).
* Have at least one [Transcript](/docs/conversational-intelligence/api/transcript-resource) associated with the Intelligence Service.

## Instructions

The following steps explain how to integrate the Transcription Viewer single-page application into a web app and display a single Transcript.

### Step 1: Identify the Transcript's SID

First, identify the SID of the Transcript that the Transcript Viewer single-page application will display. You can get the Transcript SID in multiple ways.

#### Option 1: Fetch a Transcript's SID by Recording SID via API

If you know the SID of the Recording that generated the Transcript, then you can find the Transcript's SID by calling the [Fetch Multiple Transcripts endpoint](/docs/conversational-intelligence/api/transcript-resource#fetch-multiple-conversational-intelligence-transcript-resources) and passing the `SourceSid` as a query parameter to the Recording SID. The response includes a `sid` key with the Transcript's SID, shown as `GTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` in the example below.

Fetch a Transcript by Recording SID

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function listTranscript() {
  const transcripts = await client.intelligence.v2.transcripts.list({
    sourceSid: "REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    limit: 20,
  });

  transcripts.forEach((t) => console.log(t.accountSid));
}

listTranscript();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

transcripts = client.intelligence.v2.transcripts.list(
    source_sid="REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", limit=20
)

for record in transcripts:
    print(record.account_sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Intelligence.V2;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var transcripts = await TranscriptResource.ReadAsync(
            sourceSid: "REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", limit: 20);

        foreach (var record in transcripts) {
            Console.WriteLine(record.AccountSid);
        }
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.intelligence.v2.Transcript;
import com.twilio.base.ResourceSet;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        ResourceSet<Transcript> transcripts =
            Transcript.reader().setSourceSid("REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX").limit(20).read();

        for (Transcript record : transcripts) {
            System.out.println(record.getAccountSid());
        }
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	intelligence "github.com/twilio/twilio-go/rest/intelligence/v2"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &intelligence.ListTranscriptParams{}
	params.SetSourceSid("REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
	params.SetLimit(20)

	resp, err := client.IntelligenceV2.ListTranscript(params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		for record := range resp {
			if resp[record].AccountSid != nil {
				fmt.Println(*resp[record].AccountSid)
			} else {
				fmt.Println(resp[record].AccountSid)
			}
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$transcripts = $twilio->intelligence->v2->transcripts->read(
    ["sourceSid" => "REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"],
    20
);

foreach ($transcripts as $record) {
    print $record->accountSid;
}
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'rubygems'
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

transcripts = @client
              .intelligence
              .v2
              .transcripts
              .list(
                source_sid: 'REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
                limit: 20
              )

transcripts.each do |record|
   puts record.account_sid
end
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:intelligence:v2:transcripts:list \
   --source-sid REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

```bash
curl -X GET "https://intelligence.twilio.com/v2/Transcripts?SourceSid=REXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&PageSize=20" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "transcripts": [
    {
      "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "service_sid": "GAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "sid": "GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "date_created": "2010-08-31T20:36:28Z",
      "date_updated": "2010-08-31T20:36:28Z",
      "status": "queued",
      "channel": {},
      "data_logging": false,
      "language_code": "en-US",
      "media_start_time": null,
      "duration": 0,
      "customer_key": null,
      "url": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "redaction": true,
      "links": {
        "sentences": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Sentences",
        "media": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Media",
        "operator_results": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/OperatorResults"
      }
    }
  ],
  "meta": {
    "key": "transcripts",
    "page": 0,
    "page_size": 50,
    "first_page_url": "https://intelligence.twilio.com/v2/Transcripts?LanguageCode=en-US&SourceSid=REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&ServiceSid=GAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&AfterDateCreated=2019-11-22T23%3A46%3A00Z&PageSize=50&Page=0",
    "next_page_url": null,
    "previous_page_url": null,
    "url": "https://intelligence.twilio.com/v2/Transcripts?LanguageCode=en-US&SourceSid=REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&ServiceSid=GAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&AfterDateCreated=2019-11-22T23%3A46%3A00Z&PageSize=50&Page=0"
  }
}
```

#### Option 2: Fetch all Transcripts via API

If a Recording SID isn't available, call the [Fetch Multiple Transcripts endpoint](/docs/conversational-intelligence/api/transcript-resource#fetch-multiple-conversational-intelligence-transcript-resources) without the `SourceSid` query parameter. This will return all Transcripts associated with the Twilio Account. The response includes a `sid` key with a Transcript's SID, shown as `GTXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` in the example below.

Fetch all Transcripts for an Account

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function listTranscript() {
  const transcripts = await client.intelligence.v2.transcripts.list({
    limit: 20,
  });

  transcripts.forEach((t) => console.log(t.accountSid));
}

listTranscript();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

transcripts = client.intelligence.v2.transcripts.list(limit=20)

for record in transcripts:
    print(record.account_sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Intelligence.V2;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var transcripts = await TranscriptResource.ReadAsync(limit: 20);

        foreach (var record in transcripts) {
            Console.WriteLine(record.AccountSid);
        }
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.intelligence.v2.Transcript;
import com.twilio.base.ResourceSet;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        ResourceSet<Transcript> transcripts = Transcript.reader().limit(20).read();

        for (Transcript record : transcripts) {
            System.out.println(record.getAccountSid());
        }
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	intelligence "github.com/twilio/twilio-go/rest/intelligence/v2"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &intelligence.ListTranscriptParams{}
	params.SetLimit(20)

	resp, err := client.IntelligenceV2.ListTranscript(params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		for record := range resp {
			if resp[record].AccountSid != nil {
				fmt.Println(*resp[record].AccountSid)
			} else {
				fmt.Println(resp[record].AccountSid)
			}
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$transcripts = $twilio->intelligence->v2->transcripts->read([], 20);

foreach ($transcripts as $record) {
    print $record->accountSid;
}
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'rubygems'
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

transcripts = @client
              .intelligence
              .v2
              .transcripts
              .list(limit: 20)

transcripts.each do |record|
   puts record.account_sid
end
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:intelligence:v2:transcripts:list
```

```bash
curl -X GET "https://intelligence.twilio.com/v2/Transcripts?PageSize=20" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "transcripts": [
    {
      "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "service_sid": "GAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "sid": "GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "date_created": "2010-08-31T20:36:28Z",
      "date_updated": "2010-08-31T20:36:28Z",
      "status": "queued",
      "channel": {},
      "data_logging": false,
      "language_code": "en-US",
      "media_start_time": null,
      "duration": 0,
      "customer_key": null,
      "url": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "redaction": true,
      "links": {
        "sentences": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Sentences",
        "media": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Media",
        "operator_results": "https://intelligence.twilio.com/v2/Transcripts/GTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/OperatorResults"
      }
    }
  ],
  "meta": {
    "key": "transcripts",
    "page": 0,
    "page_size": 50,
    "first_page_url": "https://intelligence.twilio.com/v2/Transcripts?LanguageCode=en-US&SourceSid=REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&ServiceSid=GAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&AfterDateCreated=2019-11-22T23%3A46%3A00Z&PageSize=50&Page=0",
    "next_page_url": null,
    "previous_page_url": null,
    "url": "https://intelligence.twilio.com/v2/Transcripts?LanguageCode=en-US&SourceSid=REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&ServiceSid=GAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&AfterDateCreated=2019-11-22T23%3A46%3A00Z&PageSize=50&Page=0"
  }
}
```

#### Option 3: Find the Transcript SID via webhook event

If the Intelligence Service is set up to send a [webhook event](/docs/conversational-intelligence/api/service-resource#webhookurl) when a transcription completes, the webhook payload includes the `transcript_sid` key.

### Step 2: Create a one-time token (OTT)

The Transcription Viewer single-page application requires a short-lived, single-use token called a one-time token (OTT) to start a session. The OTT is used to obtain scoped Conversational Intelligence API access so the single-page application can fetch an individual Transcript. The scoped API access is limited to one hour in a single user session. Token refresh isn't supported.

> \[!CAUTION]
>
> The request to create an OTT uses global Twilio Account credentials and requires a secure backend server. Don't expose Twilio Account credentials on the frontend.

#### Request an OTT

Make a `POST` request to the following endpoint to request an OTT:

```bash
https://ai.twilio.com/v1/Tokens
```

To authenticate requests to the Twilio APIs, Twilio supports [HTTP Basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). Use your *API key* as the username and your *API key secret* as the password. You can create an API key either [in the Twilio Console](/docs/iam/api-keys/keys-in-console) or [using the API](/docs/iam/api-keys/key-resource-v1).

**Note**: Twilio recommends using API keys for authentication in production apps. For local testing, you can use your Account SID as the username and your Auth token as the password. You can find your Account SID and Auth Token in the [Twilio Console](https://www.twilio.com/console).

Learn more about [Twilio API authentication](/docs/usage/requests-to-twilio).

#### OTT request body parameters

The OTT request body supports the following parameters.

| Parameter Name                              | Description                                                                                                                                                                   | Type      | Required? |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------- |
| `ott_ttl`                                   | A field that specifies a custom OTT expiry period in seconds, also known as time-to-live (TTL). If unspecified, the default is `60` seconds.                                  | `integer` | No        |
| `grants`                                    | An array of `grant` objects. Only one `grant` is required for the Transcription Viewer single-page application.                                                               | `array`   | Yes       |
| `grants[].product`                          | A field that specifies the product functionality. Must be set to `annotator` for the Transcription Viewer single-page application.                                            | `string`  | Yes       |
| `grants[].service_sid`                      | The SID of the Intelligence Service associated with the Transcription.                                                                                                        | `string`  | Yes       |
| `grants[].transcript_sid`                   | The SID of the Transcription.                                                                                                                                                 | `string`  | Yes       |
| `grants[].metadata`                         | An object containing metadata.                                                                                                                                                | `object`  | No        |
| `grants[].metadata.userId`                  | A field to identify the user who is using the Transcription Viewer single-page application.                                                                                   | `string`  | No        |
| `grants[].metadata.isDownloadButtonVisible` | A field that specifies whether or not a download button is visible. If visible, the Transcription Viewer single-page application user can download the audio of a Transcript. | `boolean` | No        |

#### OTT Response properties

If the OTT request is successful, the response includes the following properties:

| Property Name | Description                                                                                              | Type     |
| ------------- | -------------------------------------------------------------------------------------------------------- | -------- |
| `token`       | The value of the OTT.                                                                                    | `string` |
| `expiration`  | The date and time of the OTT's expiration, in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format. | `string` |

#### Code samples

```js title="Request a one-time token"
fetch("https://ai.twilio.com/v1/Tokens", {
    "headers": {
      "authorization": `Basic ${btoa(ACCOUNT_SID + ":" + AUTH_TOKEN)}`,
      "content-type": "application/json"
    },
    "body": JSON.stringify({
      "grants": [{
          "product": "annotator",
          "service_sid": "GA00000000000000000000000000000000",
          "transcript_sid": "GT00000000000000000000000000000000",
          "metadata": { 
            "userId": "Jason Bourne", 
            "isDownloadButtonVisible": true 
        }
      }]
     }),
    "method": "POST"
  });
```

```js title="Request a one-time token with a 10-minute TTL"
fetch("https://ai.twilio.com/v1/Tokens", {
  "headers": {
    "authorization": `Basic ${btoa(ACCOUNT_SID + ":" + AUTH_TOKEN)}`,
    "content-type": "application/json"
  },
  "body": JSON.stringify({
    "ott_ttl": 600,
    "grants": [{
          "product": "annotator",
          "service_sid": "GA00000000000000000000000000000000",
          "transcript_sid": "GT00000000000000000000000000000000",
          "metadata": { 
            "userId": "Jason Bourne", 
            "isDownloadButtonVisible": true 
        }
     }]
   }),
  "method": "POST"
});
```

### Step 3: Initialize and display the Transcription Viewer single-page application

Next, use the OTT as a URL query parameter to create a single-page application initialization URL using the latest Transcription Viewer single-page application build. This sample single-page application initialization URL assumes the OTT is stored in an environment variable named `TOKEN`:

```bash
https://assets.twilio.com/public_assets/annotator/latest/index.html?token=$TOKEN
```

How the single-page application initialization URL is used depends on how the single-page application is displayed. The single-page application can be displayed by either rendering it in a new window or embedding it into an existing web app.

#### Display option 1: Render the single-page application in a new window

To display the Transcription Viewer single-page application in its own browser window, redirect a window to the single-page application initialization URL:

```js
app.get('/transcription-viewer/standalone', async (req, res) => {
    const serviceSid = req.query.serviceSid;
    const transcriptSid = req.query.transcriptSid;

    const token = await client.getTranscriptionViewerToken(serviceSid, transcriptSid);
    let url = `https://assets.twilio.com/public_assets/annotator/latest/index.html?token=${token}`;
    return res.redirect(url);
});
```

Review the [demo app](https://github.com/twilio/voice-intelligence-samples/tree/main/transcript-viewer-integration-demo) for a sample implementation of the [backend](https://github.com/twilio/voice-intelligence-samples/blob/main/transcript-viewer-integration-demo/src/server/index.js#L50) of a single-page application.

#### Display option 2: Embed the single-page application

You can embed the Transcription Viewer single-page application into an existing web app using an HTML iframe. Add the single-page application initialization URL to an iframe tag as shown in the following example, noting that the `$TOKEN` variable must be generated from the backend:

```html
<iframe src="https://assets.twilio.com/public_assets/annotator/latest/index.html?token=$TOKEN" allow="clipboard-read; clipboard-write;">
```

Review the [demo app](https://github.com/twilio/voice-intelligence-samples/tree/main/transcript-viewer-integration-demo) for sample implementations of the [frontend](https://github.com/twilio/voice-intelligence-samples/blob/main/transcript-viewer-integration-demo/views/transcript-viewer-embedded.ejs) and [backend](https://github.com/twilio/voice-intelligence-samples/blob/main/transcript-viewer-integration-demo/src/server/index.js#L19) of an embedded single-page application.
