Extensions API

Reading worksheet data in an extension

How a Tableau extension gets its data: props for a viz extension, the summary data reader for a dashboard, nativeValue vs formattedValue, and row caps.

Eric SummersUpdated 2026-09-18markdown

The two extension kinds get their data in different ways, and confusing them is a common early mistake. A viz extension is handed its data. A dashboard extension goes and reads it. This page covers both paths, the value fields you read, and why you cap large reads.

A viz extension is handed its data

A hosted viz extension component does not call any data method itself. The host resolves the worksheet's Marks card and passes the data in as props to your Component function:

function Component({ data, schema, theme, fields }) {
  // data: array of plain row objects, may be empty
  // schema: [{ name, type }] describing the fields, may be undefined
  // fields: your Marks-card tile ids mapped to the field name dropped there
  // ...
}

Every value the component draws is there because the user dragged a field onto a tile you declared on the Marks card, and fields tells you which field landed where. Look columns up in data by that name, and always keep a schema-inference fallback so the same component still renders in a preview harness where there is no Marks card:

const valueField = fields?.value || schema?.find(f => f.type === 'number')?.name;

If you are writing a raw (non-hosted) viz extension by hand instead, you call worksheet.getVisualSpecificationAsync() to learn which field is on which encoding tile, then read the rows with the summary data reader below. The hosted contract does that plumbing for you. See viz extension encodings for declaring the tiles.

A dashboard extension reads through the reader

A dashboard extension has no props: it reaches into the dashboard and reads a worksheet itself. Get a worksheet, open a summary data reader, page through it, and release it:

const dash = tableau.extensions.dashboardContent.dashboard;
const ws = dash.worksheets[0];
const reader = await ws.getSummaryDataReaderAsync();
const table = await reader.getAllPagesAsync();
await reader.releaseAsync();

getSummaryDataReaderAsync is the current path and it pages through large results. The older getSummaryDataAsync returns everything in one call and is fine for small data, but the reader is what keeps a big worksheet from blowing up memory. Always releaseAsync() when you are done.

Find columns by name, read nativeValue

getSummaryData returns columns in pill order, which changes every time the user rearranges the sheet. Never index a column by position. Match it by field name (from the encodings) or by dataType ('float' / 'int' for a measure):

const cols = table.columns;
const mCol = cols.find(c => c.fieldName === 'Sales');
const rows = table.data.map(r => r[mCol.index].nativeValue);

Each cell has two values. nativeValue is the typed underlying value (a number, a Date), and it is what you do arithmetic and scales with. formattedValue is a display string with the worksheet's formatting baked in (currency symbols, thousands separators, rounding), and parsing it as a number quietly poisons your totals. Rule: nativeValue for maths, formattedValue for what you print.

Cap large reads, and never truncate silently

Reading an unbounded worksheet is a way to freeze Tableau. Cap the read, and pick a cap for each distinct concern rather than one blanket number. The kit extensions use a layered pattern, for example the ridgeline mark:

Cap Value Purpose
READ_CAP 100,000 rows Checked before the first page. Over it, the chart reads nothing and says so (filter, or use a coarser field).
RIDGE_CAP 50 series Legibility: the largest-total categories are kept.
MAX_MARKS 4,000 points The smallest-total series drop first.

The point of separate caps is that "too much data to read at all" and "too many marks to draw legibly" are different problems with different remedies. The one non-negotiable rule: every trim must show a visible note (the kit writes one in a corner of the viz). Nothing should be dropped silently, because a chart that quietly shows half the data is worse than one that refuses and tells you why.

FAQ

Does a viz extension call getSummaryDataAsync?

A hosted viz component does not: it receives data, schema, and fields as props from the host. A hand-written viz extension calls getVisualSpecificationAsync() for the encoding-to-field mapping and then reads rows through the summary data reader.

getSummaryDataAsync or getSummaryDataReaderAsync?

Use getSummaryDataReaderAsync for anything that might be large: it pages through the result instead of materialising it all at once, and you release it when done. getSummaryDataAsync returns everything in one call and is fine only for small, bounded data.

Why are my totals wrong?

Almost always because you summed formattedValue (a display string) or indexed a column by position. Sum nativeValue, and find columns by field name or dataType, never by a hard-coded index that shifts when pills are reordered.

How many rows should I read?

Cap it. A read cap around 100,000 rows before the first page protects Tableau, and a separate mark cap keeps the chart legible. Whatever caps you pick, surface a visible note whenever a cap trims the data so nothing is truncated silently.