---
schema_version: "1"
id: bffa07361098083a2523f43ac7ba487dc6ef7abf283b84f2fe44bc55e9103349
title: Get Data From Embedded Views
collection: tableau
version: current
locale: en-us
portal_url: https://docs.salesforce.com/tableau/current/en-us/api/embedding_api/docs/embedding_api_data.md
canonical_url: https://help.tableau.com/current/api/embedding_api/en-us/docs/embedding_api_data.html
source_site: help.tableau.com
content_type: documentation
content_hash: 25456c811ad3e7cda004e40ffb3e0050feb8dac6510d32a5a2d73131a4227a76
description: Documentation for the Tableau Embedding API
---
# Get Data From Embedded Views

  

The Embedding API v3 provides methods that you can use to access the data in an embedded view. The data you can access includes the summary or aggregated data, and also the underlying data (or full data). In addition, the Tableau data model has two layers, a logical layer and the underlying physical layer.

For information about the structure of the data model, see [The Tableau Data Model](https://help.tableau.com/current/pro/desktop/en-us/datasource_datamodel.htm).

In the embedded view, there are three sources of data that you can query.

- worksheet
- data source
- marks data (selected marks)

The following section describes how to obtain data from the worksheet and the data source. For information about how to get data from selected marks, see [Select Marks in the View](/current/api/embedding_api/en-us/docs/embedding_api_select_marks.html).

* * *

## About the data

Before you access data in a view, it might be helpful to understand how Tableau structures the data. To that end this section provides a brief description of some of the key components that you need to use to retrieve data using the Embedding API v3.

### Logical tables

Starting in Tableau 2020.2, with the introduction of the new data model and logical tables, you need to use the `Worksheet.getUnderlyingTablesAsync` method or the `Datasource.getLogicalTablesAsync` method to first return the array of `LogicalTable` objects. The `LogicalTable` objects returned are determined by the measures in the worksheet. The `LogicalTable` objects correspond to the tables shown in the default view on the **Data Source** page in Tableau. These tables make up the _logical layer_. You can retrieve the underlying or logical data from each `LogicalTable` in the worksheet or data source.

| Object/Property | Description |
| --- | --- |
| `LogicalTable` | Object that represents a logical table in a data source, or logical table used in a worksheet |
| `LogicalTable.caption` | The name of the logical table as it appears in Tableau. |
| `LogicalTable.id` | The identifier used to specify the logical table. Use this value to call `Worksheet.getUnderlyingTableDataAsync` and `Worksheet.getUnderlyingTableDataReaderAsync`, or `Datasource.getLogicalTableDataAsync` and `Datasource.getLogicalTableDataReaderAsync`. |

### DataTable and DataTableReader

In the Embedding API v3, the data is returned from an embedded view in a `DataTable` object. The `DataTable` object contains the columns and data values, and information about the data, whether it is underlying or summary data, and in the case of underlying data, whether there is more data than can be returned in a single call. If there are more rows of data than can be returned (10,000 rows for `getUnderlyingTableDataAsync` and `getLogicalTableDataAsync`), you can use a method that returns a `DataTableReader`. The `DataTableReader` makes it easy to page through and retrieve a large amount of data.

The `DataTableReader` returns information about the total number of rows of data, and the number of pages of data available. Each page is a `DataTable`. You can use the `DataTableReader` to get all pages or to get specific pages. For more information, see [DataTableReader](/current/api/embedding_api/en-us/reference/interfaces/DataTableReader.html).

**Note:** The DataTableReader method, `Worksheet.getSummaryDataReaderAsync()`, returns the `DataTable` with its colunms sorted in alphabetical (ascending) order and not in the order the fields (columns) appear in the Tableau view. For more information, see [Sort order and the DataTableReader](#sort-order-and-the-datatablereader).

### Data access and Tableau user roles and permissions

When you embed a Tableau view into your web application, you need to consider whether users will have permission to see that view and have access to the underlying data. The Embedding API allows access to the data in the embedded view based upon a user’s role (creator, explorer, viewer) and permissions granted to that role. When someone accesses the Tableau view embedded in your web application, the same authentication and permissions apply as if they were accessing the view on Tableau directly.

| Data Methods | Viewer | Explorer | Creator |
| --- | --- | --- | --- |
| `Worksheet.getSummaryDataReaderAsync` | x | x | x |
| `Worksheet.getSummaryDataAsync` | x | x | x |
| `Worksheet.getUnderlyingDataAsync` |   | x | x |
| `Worksheet.getUnderlyingTableDataAsync` |   | x | x |
| `Worksheet.getUnderlyingTableDataReaderAsync` |   | x | x |
| `Worksheet.getUnderlyingTablesAsync` |   | x | x |
| `Datasource.getLogicalTableDataAsync`, `Datasource.getLogicalTableDataReaderAsync` |   | x | x |

* * *

## Get data from a worksheet

The Embedding API v3 provides several methods for accessing data from an embedded view. The method you use depends in part upon how you want to use the data. When you have the worksheet object, you can get the summary data (aggregated data) or the full data (underlying data) directly from the worksheet using these methods:

| Method | Tableau Version | Embedding API v3 Library | Returns | Status |
| --- | --- | --- | --- | --- |
| `Worksheet.getSummaryDataAsync()` | 2022.3 and later | 3.3 and later | DataTable | Deprecated |
| `Worksheet.getSummaryDataReaderAsync()` | 2022.4 and later | 3.4 and later | DataTableReader | Current |
| `Worksheet.getUnderlyingDataAsync()` | 2022.3 | 3.3 | DataTable | Deprecated |
| `Worksheet.getUnderlyingTableDataAsync` | 2022.3 and later | 3.3 and later | DataTable | Current |
| `Worksheet.getUnderlyingTableDataReaderAsync` | 2022.4 and later | 3.3 and later | DataTableReader | Current |
| `Worksheet.getUnderlyingTablesAsync` | 2022.3 and later | 3.3 and later | LogicalTable | Current |

### Get summary data from a worksheet

Summary data, or aggregated data, is the data visible in a worksheet. To get the summary data you must first access the worksheet object. After you have the worksheet, you can call the methods to retrieve the data. Starting with Tableau 2022.4 and with Embedding API 3.4.0 library, you should use the `getSummaryDataReaderAsync()` method.

**Note:** The `getSummaryDataAsync` is deprecated, as it could fail when called on a worksheet that has many rows of data. Use the `getSummaryDataReaderAsync()` method instead.

#### Use `getAllPagesAsync` for summary data (less than 4M)

If your summary data is less than 4,000,000 rows, you can use the `getAllPagesAsync()` method to retrieve a single `DataTable` from the `DataTableReader`. The following example shows how to do this.

1. Get the currently active worksheet.
2. From the worksheet, use the `getSummaryDataReaderAsync` method to create the `DataTableReader`.
3. Call the `getAllPagesAsync` method to return all of the summary data (up to 4,000,000 rows, or 400 pages).
4. After you have retrieved the summary data, call the `releaseAsync` method to free up the `DataTableReader`.

```

// Use `await` only inside an `async` method

let vizActiveSheet = viz.workbook.activeSheet;
if (vizActiveSheet.sheetType === "worksheet") {
  const dataTableReader = await vizActiveSheet.getSummaryDataReaderAsync();
  const dataTable = await dataTableReader.getAllPagesAsync();
  await dataTableReader.releaseAsync();
  // ... process data table ...
}

```

#### Use `getSummaryDataReaderAsync` for summary data (greater than 4M)

If your summary data contains more than 4,000,000 rows (or 400 pages), use the summary `DataTableReader` to iterate through the pages of data for all rows in the worksheet. In this case, you process each `DataTable` sequentially. You can control the page size, using the optional `pageRowCount` parameter when you call `getSummaryDataReaderAsync`. The default page size is 10,000 rows.

1. Get the currently active worksheet.
2. From the worksheet, use the `getSummaryDataReaderAsync` method to create the `DataTableReader`.
3. Create a loop to retrieve each page of summary data, using `DataTableReader.pageCount` or `DataTableReader.totalRowCount` property of the summary `DataTableReader` to determine the number of pages to process.
4. Use the `getPageAsync` method to get the DataTable from each page.
5. After you have retrieved all pages of the summary data, call the `releaseAsync` method to free up memory from the `DataTableReader`.

```

// Use `await` only inside an `async` method

let vizActiveSheet = viz.workbook.activeSheet;
if (vizActiveSheet.sheetType === "worksheet") {
    const dataTableReader = await vizActiveSheet.getSummaryDataReaderAsync();
    for (let currentPage = 0; currentPage < dataTableReader.pageCount; currentPage++) {
        const dataTablePage = await dataTableReader.getPageAsync(currentPage);
        // ... process current page ....
    }
    // free up resources
    await dataTableReader.releaseAsync();
}

```

### Get underlying data from a worksheet

Underlying data, or full data, is all the data in the workbook, not just the data available in the current view. There are two methods you can use to retrieve this data. Which one you use depends upon the amount of underlying data there is. If you have less than 10,000 rows of data, use `Worksheet.getUnderlyingTableDataAsync`. If you have more, you can use the DataTableReader (`getUnderlyingTableDataReaderAsync`) to retrieve pages of data.

- [Use `getUnderlyingTableDataAsync` for less than 10K rows of data](#use-getunderlyingtabledataasync-for-less-than-10k-rows-of-data)
- [Use `getUnderlyingTableDataReaderAsync` for more than 10K rows of data](#use-getunderlyingtabledatareaderasync-for-more-than-10k-rows-of-data)

#### Use `getUnderlyingTableDataAsync` for less than 10K rows of data

If the data doesn’t contain more than 10,000 rows, you can use the `getUnderlyingTableDataAsync` method to get data from a worksheet. The basic steps are as follows:

1. From the worksheet, call the `getUnderlyingTablesAsync` method to return the array of logical tables.
2. Using the `logicalTable.id`, call the `getUnderlyingTableDataAsync` method to return a `DataTable` containing the underlying data (up to 10,000 rows) for the logical table. Repeat this step for each logical table.

You can specify the number of rows of data to return by setting `GetUnderlyingDataOptions.maxRows` property. If unspecified (`maxRows == '0'`), the call to `getUnderlyingTableDataAsync` requests all rows in the logical table. Note that the maximum number of rows returned from the `getUnderlyingTableDataAsync` method is limited to 10,000 rows. You can use the `DataTable` property, `isTotalRowCountLimited`, to test whether there is more data. A value of true indicates that the calling function requested more rows than the limit (10,000) and the underlying data source contains more rows than can be returned. If the data contains more than 10,000 rows, use `getUnderlyingTableDataReaderAsync` method instead.

```

// assumes this code is in an async method

const sheet = viz.workbook.activeSheet.worksheets.find(sheet => sheet.name === "Storm Map Sheet");

const tables = await sheet.getUnderlyingTablesAsync();
const options = {
    maxRows: 1000, // Max rows to return. Use 0 to return all rows.
    ignoreAliases: false,
    ignoreSelection: true,
    includeAllColumns: false
}
const underlyingTableData = await sheet.getUnderlyingTableDataAsync(tables[0].id, options);

```

#### Use `getUnderlyingTableDataReaderAsync` for more than 10K rows of data

If the data contains more than 10,000 rows, use the `getUnderlyingTableDataReaderAsync` method to get data from a worksheet. In this case, you create a `DataTableReader` to iterate through the pages of data. You process each `DataTable` sequentially. You can control the page size, using the optional `pageRowCount` parameter when you call `getUnderlyingTableDataReaderAsync`. The default page size is 10,000 rows.

The basic steps are as follows:

1. From the worksheet, call the `getUnderlyingTablesAsync` method to return the array of logical tables.
2. Using the `logicalTable.id`, call the `getUnderlyingTableDataReaderAsync` method to create the `DataTableReader`.
3. Create a loop to retrieve each page of underlying data, using `DataTableReader.pageCount` or `DataTableReader.totalRowCount` property of the `DataTableReader` to determine the number of pages to process.
4. Use the `getPageAsync` method to get the DataTable from each page.
5. After you have retrieved all pages of the summary data, call the `releaseAsync()` method to free up memory from the `DataTableReader`.

```

// assumes this code is in an async method

let vizActiveSheet = viz.workbook.activeSheet;
if (vizActiveSheet.sheetType === "worksheet") {
   // Call to get the underlying logical tables used by the worksheet
   const underlyingTablesData = await vizActiveSheet.getUnderlyingTablesAsync();
   const logicalTableId = underlyingTablesData[0].id;
   // Use the above logicalTableId to get the underlying data reader on the active sheet
   const dataTableReader = await vizActiveSheet.getUnderlyingTableDataReaderAsync(logicalTableId);
   // loop through the pages
   const pageNumber = 0;
   while (pageNumber < dataTableReader.pageCount) {
      let currentPageDataTable = await dataTableReader.getPageAsync(pageNumber);
      // process page ...
      console.log(currentPageDataTable);
      pageNumber++;
    }
    // free up resources
    await pageReader.releaseAsync();

}

```

The `getUnderlyingTableDataReaderAsync` method attempts to prepare all the rows of the table to be read as pages. There is a limit to the number of rows that can be prepared to conserve computing resources. The default limit is 1 million rows of data. You can change this default row limit with the Tableau Server and Tableau Cloud `ExtensionsAndEmbeddingReaderRowLimit` option.

If the underlying table has many columns, `getUnderlyingTableDataReaderAsync` can be sped up by only requesting native data values (`IncludeDataValuesOption.OnlyNativeValues`) in the `GetUnderlyingDataOptions`.

* * *

## Get data from a data source

The Embedding API v3 provides methods for accessing data from the data sources used by a worksheet. To get the data sources, you call the `getDataSourcesAsync` method from the worksheet. The method returns an array of data sources. The first data source in the array is the primary data source, additional data sources, if any, are secondary sources. Note that calling `getDataSourcesAsync` might negatively impact performance and responsiveness of the view that you are embedding. The method is partly asynchronous but includes some serial operations.

To get data from a data source, you can use a couple of different methods. Which one you use depends upon the amount of data there is. If you have less than 10,000 rows of data, use `Datasource.getLogicalTableDataAsync`. If you have more, use the DataTableReader (`Datasource.getLogicalTableDataReaderAsync`) to retrieve pages of data.

| Method | Tableau Version | Embedding API v3 Library | Status |
| --- | --- | --- | --- |
| `Datasource.getLogicalTableDataAsync` | Tableau 2022.4 and later | version 3.4 and later | Current |
| `Datasource.getLogicalTableDataReaderAsync` | Tableau 2022.4 and later | version 3.4 and later | Current |
| `Datasource.getLogicalTablesAsync` | Tableau 2022.3 and later | version 3.3 and later | Current |
| `Datasource.getUnderlyingDataAsync` | Tableau 2022.3 and later | version 3.3 and later | Deprecated |

* * *

### Use `getLogicalTableDataAsync` for less than 10K rows in the data source

If the data doesn’t contain more than 10,000 rows, you can use the `getLogicalTableDataAsync` method to get data from a data source. The basic steps are as follows:

1. From the data source, call the `geLogicalTablesAsync` method to return the array of logical tables.
2. Using the `logicalTable.id`, call the `getLogicalTableDataAsync` method to return a `DataTable` containing the underlying data (up to 10,000 rows) for the logical table. Repeat this step for each logical table.

You can specify the number of rows of data to return by setting `DataSourceUnderlyingDataOptions.maxRows` property. If unspecified (`maxRows == '0'`), the call to `getLogicalTableDataAsync` requests all rows in the logical table. Note that the maximum number of rows returned from the `getLogicalTableDataAsync` method is limited to 10,000 rows. You can use the `DataTable` property, `isTotalRowCountLimited`, to test whether there is more data. A value of true indicates that the calling function requested more rows than the limit (10,000) and the logical data source contains more rows than can be returned. If the data contains more than 10,000 rows, use `getLogicalTableDataReaderAsync` method instead.

The following example shows use of the `getLogicalTableDataAsync` method to get the data from a specific logical table in a data source. The example uses the JavaScript `find()` method to select the workbook, and uses the `getLogicalTablesAsync` method to get the array of data tables. This example gets the data from the first logical table.

```

// assumes that this code is in an async function

const dataSources = await worksheet.getDataSourcesAsync();
const dataSource = dataSources.find(datasource => datasource.name === "Sample - Superstore");
const logicalTables = await dataSource.getLogicalTablesAsync()
const dataTable = await dataSource.getLogicalTableDataAsync(logicalTables[0].id);
console.log(dataTable);

```

### Use `getLogicalTableDataReaderAsync` for more than 10K rows in the data source

If the data contains more than 10,000 rows, use the `getLogicalTableDataReaderAsync` method to get data from a data source. In this case, you create a `DataTableReader` to iterate through the pages of data for all rows in the worksheet. You process each `DataTable` sequentially. You can control the page size, using the optional `pageRowCount` parameter when you call `getLogicalTableDataReaderAsync`. The default page size is 10,000 rows.

The basic steps are as follows:

1. From the worksheet, call the `getLogicalTablesAsync` method to return the array of logical tables.
2. Using the `logicalTable.id`, call the `getLogicalTableDataReaderAsync` method to create the `DataTableReader`.
3. Create a loop to retrieve each page of logical data, using `DataTableReader.pageCount` or `DataTableReader.totalRowCount` property of the summary `DataTableReader` to determine the number of pages to process.
4. Use the `getPageAsync()` method to get the `DataTable` from each page.
5. After you have retrieved all pages of the data, call the `releaseAsync()` method to free up memory from the `DataTableReader`.

```

// assumes this code is in an async method

const pageRowCount = 1000;  // default is 10,000
const dataSources = await worksheet.getDataSourcesAsync();
const dataSource = dataSources.find(datasource => datasource.name === "Sample - Superstore");
const logicalTables = await dataSource.getLogicalTablesAsync()
const dataTableReader = await dataSource.getLogicalTableDataReaderAsync(logicalTables[0].id, pageRowCount);
   
const pageNumber = 0;
   while (pageNumber < dataTableReader.pageCount) {
      let currentPageDataTable = await dataTableReader.getPageAsync(pageNumber);
      // process page ...
      console.log(currentPageDataTable);
      pageNumber++;
    }
// release resources
await pageReader.releaseAsync();

```

### Use `getLogicalTableDataReaderAsync` to retrieve selected data from the data source

The following example shows how you could use the `getLogicalTableDataReaderAsync` and `getAllPagesAsync` methods to prepare pages of 10,000 rows each, and then how to get a maximum of 150,000 rows of native data from a specific logical table in a data source.

```

const dataSources = await worksheet.getDataSourcesAsync();
const dataSource = dataSources.find(datasource => datasource.name === "Sample - Superstore");
const logicalTables = await dataSource.getLogicalTablesAsync()
const dataTableReader = await dataSource.getLogicalTableDataReaderAsync(logicalTables[0].id, 10000,
    { includeDataValuesOption: tableau.IncludeDataValuesOption.OnlyNativeValues });
const dataTable = await dataTableReader.getAllPagesAsync(150000);
console.log(dataTable);
// release resources
await dataTableReader.releaseAsync();

```

The `getLogicalTableDataReaderAsync` method attempts to prepare all the rows of the table to be read as pages. There is a limit to the number of rows that can be prepared to conserve computing resources. The default limit is approximately 32 million cells (rows \* columns). However, if the data source has many columns, this number will be adjusted downward. You can change the default limit with the Tableau Server and Tableau Cloud `ExtensionsAndEmbeddingReaderCellLimit` option.

If the data source has many columns, you can improve the performance of `getLogicalTableDataReaderAsync` by only requesting native data values. This is shown in the example by specifying `tableau.IncludeDataValuesOption.OnlyNativeValues` as one of the `GetUnderlyingDataOptions`.

* * *

## Sort order and the DataTableReader

The `DataTableReader` sorts columns in alphabetical (ascending) order. If you use the `getSummaryDataReaderAsync()` method be aware that the columns in the summary data are not sorted in the order they appear in the Tableau view or in the View Data dialog box. If you want the summary data sorted as it appears in the Tableau view or the View Data dialog box, you’ll want to map the indices of columns as you read from the pages of the `DataTable`. If you want to use each page to construct a larger data table, you can use the index map and rearrange the data as you’re constructing the larger data table.

The following example code shows how you might use the `getSummaryColumnsInfoAsync()` method to create an index map that you can use to read the data in the order the columns appear in the view. When you call the `getSummaryDataReaderAsync()` method it returns a `DataTableReader`. In the example, the `DataTableReader` gets the first page of summary data. The example then creates an index map (using the column `fieldId`) that is used to iterate over the rows of data in the `DataTable`, reading the columns of data in view order. If you had multiple pages of summary data, you could add code to loop through those.

Note that you can specify the columns to include when you call `getSummaryDataReaderAsync()`, but you can’t specify the sort order.

_Example showing how to read from the summary data table in view order_

```

let dataTableReader;
try {
  // Gets an array of columns with the same order as the columns in the Tableau view.
  const columns = await worksheet.getSummaryColumnsInfoAsync();
  // Get the DataTableReader and the first DataTable page (assumes dataTableReader.pageCount > 0).
  dataTableReader = await worksheet.getSummaryDataReaderAsync();
  let dataTablePage = await dataTableReader.getPageAsync(0);

  // DataTable is sorted in alphabetical (ascending) order.
  const sortedColumns = dataTablePage.columns;
  // To read the DataTable's columns in the Tableau view order we must map the 'columns' array to the 
  // indices of the 'sortedColumns' array using the 'fieldId' identifier.
  const indexMap = [];
  columns.forEach((column) => {
    // find index of 'column' in 'sortedColumns' array
    for (let index = 0; index < sortedColumns.length; index++) {
      if (column.fieldId === sortedColumns[index].fieldId) {
        indexMap.push(index);
        break;
      }
    }
  });

  // Process first DataTable page, iterating over each row.
  for (let rowIndex = 0; rowIndex < dataTablePage.totalRowCount; rowIndex++) {
    let row = dataTablePage.data[rowIndex];

    // For a given row, iterate over the columns in order of Tableau view using the 'indexMap'.
    for (let columnIndex = 0; columnIndex < indexMap.length; columnIndex++) {
      let mappedIndex = indexMap[columnIndex];
      let dataValue = row[mappedIndex];
      // Process data value here.
    }
  }

  // Iterate over the remaining DataTable pages.
  for (let currentPage = 1; currentPage < dataTableReader.pageCount; currentPage++) {
    dataTablePage = await dataTableReader.getPageAsync(currentPage);
    // Process remaining DataTable pages here
    // (similarly to how the first DataTable page was processed in the code above).
  }
} finally {
  // free up allocated resources
  if (dataTableReader) {
    await dataTableReader.releaseAsync();
  }
}

```

  

#### On This Page