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.

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

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.


In this section


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.

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.

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

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();
  }
}