WebPivotTable Documentation
WebPivotTable (WPT) is a fully self-contained, embeddable pivot-table and charting component built as a standard Web Component. Drop it into any web page, React app, Vue app, Angular app, or plain HTML file with a single <web-pivot-table> element and a script tag.
Key characteristics:
- Framework-agnostic — works in Vanilla JS, React, Vue, Angular, Svelte, or any other framework.
- Three data source modes — Memory (browser-only), Server (DuckDB), and OLAP (MDX/XMLA).
- AI-powered analytics — connect OpenAI, Claude, Gemini, or any OpenAI-compatible endpoint for natural-language queries and insights.
- 20 UI languages — locale files loaded lazily from CDN or your own server.
- Rich chart & grid — 20+ Highcharts chart types, column resizing, freezing, sorting, filtering, conditional formatting, calculated fields.
- Fully themeable — CSS custom properties, 4 built-in presets (default, dark, ocean, forest), or craft your own.
- Self-hosted or CDN — ship the bundle yourself or load it from the WPT CDN.
Quick Start
The fastest way to get WPT running is a CDN script tag — one line of HTML, no build step:
<!-- 1. Load the WPT bundle from CDN -->
<script src="https://cdn.webpivottable.com/wpt/latest/wpt.js"></script>
<!-- 1. Load the script -->
<script src="https://cdn.webpivottable.com/wpt/latest/wpt.js"></script>
<!-- 2. Place the element anywhere in your page -->
<web-pivot-table id="wpt" style="width:100%;height:600px"></web-pivot-table>
<!-- 3. Load data and go -->
<script>
const wpt = document.getElementById('wpt')
// With static loading, direct calls work immediately
wpt.setWptFromCsvUrl('/data/sales.csv')
</script>Or install via npm (includes TypeScript declarations):
npm install webpivottable// registers <web-pivot-table> as a global custom element
import 'webpivottable'<web-pivot-table> custom element when imported. No manual customElements.define() call is needed.wpt:ready vs direct calls:• Static loading (CDN script tag in head) → direct calls work after mounting in ANY framework
• Dynamic loading (import(), createElement script) → always use
wpt:ready in ANY framework• ⚠️ Framework doesn't matter — React, Vue, Angular, Svelte all follow the same rule!
• ⚠️ Loading method determines the pattern — not your framework choice
Framework Integration
Vanilla JavaScript
Static loading (script in head) — direct calls work:
<!-- Script loaded statically in head -->
<script src="https://cdn.webpivottable.com/wpt/latest/wpt.js"></script>
<web-pivot-table id="wpt" style="width:100%;height:600px"></web-pivot-table>
<script>
const wpt = document.getElementById('wpt')
// ✅ Direct calls work with static loading
wpt.setOptions({ locale: 'en', leavePageWarning: true })
wpt.setWptFromCsvUrl('https://example.com/data.csv')
// Listen to events
wpt.eventBus.on('PIVOT_CHANGED', (payload) => {
console.log('Pivot changed', payload)
})
</script>Dynamic loading (createElement) — must use wpt:ready:
<!-- No script in head -->
<web-pivot-table id="wpt" style="width:100%;height:600px"></web-pivot-table>
<script>
const wpt = document.getElementById('wpt')
// ✅ Must wait for ready with dynamic loading
wpt.addEventListener('wpt:ready', () => {
wpt.setOptions({ locale: 'en' })
wpt.setWptFromCsvUrl('https://example.com/data.csv')
}, { once: true })
// Load script dynamically
const script = document.createElement('script')
script.src = 'https://cdn.webpivottable.com/wpt/latest/wpt.js'
document.head.appendChild(script)
</script>React
// Install: npm install webpivottable
import { useEffect, useRef } from 'react'
import 'webpivottable'
export function PivotTable({ csvUrl }) {
const ref = useRef(null)
useEffect(() => {
const wpt = ref.current
if (!wpt) return
// ✅ With npm import (dynamic loading), direct calls work after mounting
wpt.setOptions({
locale: 'en',
uiFlags: { export: true, save: true },
})
wpt.setWptFromCsvUrl(csvUrl)
// 💡 Only need wpt:ready if you dynamically load the script with createElement/import()
// Subscribe to events
const unsub = wpt.eventBus.on('DRILL_THROUGH', (detail) => {
console.log('Drill-through:', detail)
})
return () => {
unsub()
}
}, [csvUrl])
return (
<web-pivot-table
ref={ref}
style={{ width: '100%', height: '600px', display: 'block' }}
/>
)
}wpt:ready if you dynamically load the script with createElement() or import(). The timing rule is universal across all frameworks!type { WebPivotTableElement } from 'webpivottable' for full type safety.Vue 3
<template>
<web-pivot-table ref="wptRef" style="width:100%;height:600px" />
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import 'webpivottable'
const wptRef = ref(null)
let unsub: (() => void) | null = null
onMounted(() => {
const wpt = wptRef.value as any
// Vue can call methods directly after mounting
wpt.setOptions({ locale: 'en' })
wpt.setWptFromCsvUrl('/data/sales.csv')
unsub = wpt.eventBus.on('PIVOT_CHANGED', () => console.log('changed'))
})
onUnmounted(() => unsub?.())
</script>Angular
// app.module.ts — allow unknown custom elements
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
export class AppModule {}
// component.ts
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core'
import 'webpivottable'
@Component({
template: '<web-pivot-table #wpt style="width:100%;height:600px"></web-pivot-table>',
})
export class PivotComponent implements AfterViewInit {
@ViewChild('wpt') wptRef!: ElementRef
ngAfterViewInit() {
const wpt = this.wptRef.nativeElement
// Angular can call methods directly after view init
wpt.setOptions({ locale: 'en' })
wpt.setWptFromCsvUrl('/data/sales.csv')
}
}Svelte
<script>
import { onMount } from 'svelte'
import 'webpivottable'
let wptEl
onMount(() => {
// Svelte can call methods directly after mount
wptEl.setOptions({ locale: 'en' })
wptEl.setWptFromCsvUrl('/data/sales.csv')
})
</script>
<web-pivot-table bind:this={wptEl} style="width:100%;height:600px" />Multiple instances on one page
WPT supports any number of <web-pivot-table> elements on the same page. Each instance is completely isolated — its own Zustand store, its own event bus, its own data.
<!-- Static loading example -->
<script src="https://cdn.webpivottable.com/wpt/latest/wpt.js"></script>
<web-pivot-table id="wpt1" style="width:50%;height:500px;float:left"></web-pivot-table>
<web-pivot-table id="wpt2" style="width:50%;height:500px;float:left"></web-pivot-table>
<script>
const wpt1 = document.getElementById('wpt1')
const wpt2 = document.getElementById('wpt2')
// Direct calls work with static loading
wpt1.setWptFromCsvUrl('/sales.csv')
wpt2.setWptFromCsvUrl('/inventory.csv')
</script>Locale & Internationalization
Available languages
WPT ships with bootstrap strings for English and Chinese built in. Full translations for 20 languages are loaded lazily from the CDN (or your own server):
| Code | Language | Code | Language |
|---|---|---|---|
en | English (default) | zh | Chinese (Simplified) |
de | German | fr | French |
es | Spanish | pt | Portuguese |
it | Italian | tr | Turkish |
ja | Japanese | ko | Korean |
ru | Russian | pl | Polish |
nl | Dutch | sv | Swedish |
ar | Arabic | cs | Czech |
hu | Hungarian | ro | Romanian |
da | Danish | fi | Finnish |
Setting the locale
// Set via options (recommended)
wpt.setOptions({ locale: 'fr' })
// Or call the dedicated method (async — waits for locale file to load)
await wpt.setLocale('fr')
// Or set as the initial options attribute
<web-pivot-table options='{"locale":"de"}'></web-pivot-table>Locale file base URL
By default locale files are loaded from https://cdn.webpivottable.com/wpt/latest/locales. Override with localeBaseUrl to self-host translations:
wpt.setOptions({
locale: 'ja',
localeBaseUrl: 'https://my-cdn.example.com/wpt-locales',
// WPT will fetch: https://my-cdn.example.com/wpt-locales/ja.json
})node_modules/web-pivot-table/locales/ to your own CDN bucket to avoid any dependency on the WPT CDN.Options Reference
All options are passed via wpt.setOptions(opts) (merges with existing options) or as the options HTML attribute (JSON string). TypeScript types are exported from web-pivot-table as WptOptions.
Locale options
| Option | Type | Default | Description |
|---|---|---|---|
locale | string | 'en' | UI language code. See locale table above. |
localeBaseUrl | string | CDN URL | Base URL for locale JSON files. Override to self-host. |
leavePageWarning | boolean | false | Show a browser 'leave page?' prompt if the user has unsaved changes. |
Behaviour options
| Option | Type | Default | Description |
|---|---|---|---|
deferLayoutUpdate | boolean | false | Don't recompute the pivot automatically on every field change — wait for the user to click Refresh. Useful for large datasets. |
deferLayoutExcludeFilter | boolean | false | When deferLayoutUpdate is true, still update immediately when filters change. |
defaultToDistinctCount | boolean | false | When a STRING field is dragged to the Values zone, default its aggregation to Distinct Count instead of Count. |
drillThroughBySingleClick | boolean | false | Single-click a data cell to trigger drill-through. Default is double-click. |
defaultValueFormat | object | — | Default number format for new value fields: { category: 'NUMBER' | 'CURRENCY' | 'PERCENTAGE', negative: 'MINUS' | 'PARENTHESES' | ... } |
decimalPoint | string | '.' | Character used as decimal separator in formatted output (e.g. ',' for European locales). |
thousandsSep | string | ',' | Character used as thousands separator in formatted output (e.g. '.' for European locales). |
licenseKey | string | — | License key purchased at webpivottable.com/pricing. Hides the 'Powered by WPT' watermark when valid. |
initialWpt | string | object | — | Pre-load a saved .wpt file on component init. Value can be a JSON string or a parsed object. |
Server / proxy options
Configure these under the server key for all data-source proxy settings:
wpt.setOptions({
server: {
// File proxy — routes CSV/Excel/JSON fetches through your server
fileProxyEnabled: true,
fileProxy: 'https://api.example.com/wpt-proxy/file',
fileTimeout: 30000, // ms
// XMLA proxy — routes OLAP MDX requests through your server
xmlaProxyEnabled: true,
xmlaProxy: 'https://api.example.com/wpt-proxy/xmla',
xmlaTimeout: 60000,
// HTTP Basic Auth for file proxy
basicAuthEnabled: false,
username: '',
password: '',
// OLAP roles (semicolon-separated role names)
rolesEnabled: false,
roles: 'SalesRole;ReportingRole',
}
})Control panel options
| Option | Type | Default | Description |
|---|---|---|---|
controlPanel.show | boolean | true | Show or hide the right-side control panel on startup. |
controlPanel.floating | boolean | false | Float the panel over the grid instead of pushing it aside. |
controlPanel.position | 'left' | 'right' | 'right' | Side where the control panel docks. |
controlPanel.width | number | 280 | Width of the control panel in pixels. |
Layout options
| Option | Type | Default | Description |
|---|---|---|---|
layout.fitMode | 'fill' | 'contain' | 'cover' | 'fill' | How the component fills its container. |
layout.headerReserve | number | — | Extra pixel reserve for sticky header rendering. |
fullscreen | boolean | false | Toggle fullscreen programmatically. |
Limit options
| Option | Type | Default | Description |
|---|---|---|---|
limit.sourceDataMaxRows | number | — | Hard cap on rows imported from a CSV/Excel file. |
limit.sourceDataMaxColumns | number | — | Hard cap on columns imported from a CSV/Excel file. |
limit.sheetLayoutMaxRows | number | — | Maximum rows rendered in the pivot grid. |
limit.sheetLayoutMaxColumns | number | — | Maximum columns rendered in the pivot grid. |
limit.olapDrillThroughMaxRows | number | 1000 | Max rows returned from an OLAP drill-through query. |
Grid callback options
Per-row and per-cell style callbacks. These must be set programmatically (not serialized in .wpt files):
wpt.setOptions({
gridCallbacks: {
// Style an entire row based on its data
rowStyleFn: (flatRow, rowIndex) => {
if (flatRow.region === 'APAC') return { backgroundColor: '#e8f4f8' }
},
// Style a specific cell based on its column
cellValueStyleFn: (flatRow, col) => {
if (col.id === 'profit' && flatRow.profit < 0)
return { color: '#d32f2f', fontWeight: 700 }
},
},
})UI Flags
The uiFlags option object controls which toolbar buttons and UI elements are visible. All flags default to true (visible) unless noted otherwise.
wpt.setOptions({
uiFlags: {
// Toolbar visibility
export: true, // Export button
save: true, // Save WPT button
reset: true, // Reset button
fullScreen: true, // Fullscreen toggle
language: true, // Language selector
source: true, // Data source button
open: true, // Open WPT file
connectSource: true, // Connect data source dialog
sourceExport: true, // Export in source view
drillThroughExport: true,// Export in drill-through view
// Load-source sub-flags
loadFromCsv: true,
loadFromExcel: true,
loadFromGss: false, // Google Sheets (requires API key)
loadFromWs: true, // Web service / REST endpoint
loadFromOlap: true,
// Save sub-flags
saveToLocal: true,
saveToServer: false,
// Behaviour flags
gridChartSwitchOnToolbar: false, // Put Grid/Chart toggle in toolbar
hideToolbar: false, // Hide the entire toolbar
hideFieldSettings: false, // Disable field settings dialog
hideValueFieldSettings: false, // Disable value field settings
hideConditionalFormat: false, // Disable conditional format
hideCalculatedField: false, // Disable calculated fields
hideAiChat: false, // Hide the AI chat tab
fieldsPanel: true, // Show field list in control panel
fieldsPanelSetting: true, // Show options tab in control panel
// Prompts
dropPrompt: true, // Show "drop file here" prompt
pivotPrompt: true, // Show "drag fields" prompt
}
})Themes & Styling
WPT supports four built-in theme presets and full CSS custom-property overrides.
Built-in presets
wpt.setOptions({
theme: { preset: 'default' } // 'default' | 'dark' | 'ocean' | 'forest'
})Custom colors
wpt.setOptions({
theme: {
preset: 'default', // start from a preset
colors: {
primary: '#7c3aed', // brand / accent color
primaryText: '#fff',
background: '#f9fafb',
backgroundPanel: '#ffffff',
border: '#e5e7eb',
text: '#111827',
textSecondary: '#6b7280',
gridHeaderBackground: '#f3f4f6',
gridHeaderText: '#111827',
},
typography: {
fontSize: '13px',
lineHeight: 1.5,
},
shape: {
borderRadius: '6px',
},
},
})Memory Mode (CSV / Excel / JSON)
In Memory mode all data is loaded into the browser and processed client-side. No server required. Suitable for files up to approximately 100 MB (browser-dependent).
Supported input formats: CSV, TSV, Excel (.xls / .xlsx), JSON arrays, Google Sheets (public).
Load from URL
// CSV
wpt.setWptFromCsvUrl('/data/sales.csv')
// Excel
wpt.setWptFromExcelUrl('/data/report.xlsx')
// Web service returning JSON ({ fields:[...], data:[...] })
wpt.setWptFromWebService('https://api.example.com/pivot-data')
// Google Sheet (public, published to the web)
wpt.setWptFromGoogleSpreadSheet(
'https://docs.google.com/spreadsheets/d/SHEET_ID/export?format=csv'
)Load from a JavaScript array
// attrArray = field definitions, dataArray = rows
const attrArray = [
{ name: 'Region', type: 'STRING' },
{ name: 'Quarter', type: 'STRING' },
{ name: 'Revenue', type: 'NUMBER' },
]
const dataArray = [
['APAC', 'Q1', 120000],
['EMEA', 'Q1', 98000],
['APAC', 'Q2', 135000],
]
wpt.setWptFromDataArray(attrArray, dataArray)Load from a local file (file picker / drag-and-drop)
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0]
await wpt.setWptFromLocalFile(file) // type auto-detected from extension
})Cross-origin files — using a file proxy
If the CSV/Excel file is on a different origin, configure a file proxy on your server that forwards the request and sets CORS headers:
wpt.setOptions({
server: {
fileProxyEnabled: true,
fileProxy: '/api/wpt-proxy/file', // your server-side proxy endpoint
}
})
// Now cross-origin URLs work:
wpt.setWptFromCsvUrl('https://data.example.com/report.csv')The proxy endpoint receives a POST with a url parameter, fetches the file server-side, and returns the content with appropriate CORS headers.
Server Mode (DuckDB)
In Server mode data stays on your server and is queried by DuckDB. The browser sends structured pivot queries; the server returns only aggregated results. Raw data never reaches the browser — ideal for sensitive data and very large files.
Connecting to a server mode source
// Server mode source is set up server-side; the client receives a sourceId
// that references the pre-loaded dataset on the server.
wpt.setSourceObject({
mode: 'SERVER',
sourceId: 'abc123', // returned by your server after upload
name: 'Sales 2024',
fields: [...], // field definitions from server
})OLAP Mode (MDX / XMLA)
OLAP mode connects WPT directly to a multidimensional OLAP cube via the XMLA protocol. Compatible with Microsoft SSAS, SAP BW, Apache Kylin, Mondrian, ClickHouse, and any XMLA-compliant server.
Connecting to an OLAP cube
wpt.setWptFromOlapCube({
xmlaUrl: 'https://my-ssas-server/olap/msmdpump.dll',
catalogName: 'AdventureWorks',
cubeName: 'Sales',
})
// With a proxy (required for CORS or authentication)
wpt.setOptions({
server: {
xmlaProxyEnabled: true,
xmlaProxy: '/api/wpt-proxy/xmla',
basicAuthEnabled: true,
username: 'analyst',
password: 'secret',
}
})OLAP cube config object
| Field | Type | Description |
|---|---|---|
xmlaUrl | string | XMLA endpoint URL of the OLAP server. |
catalogName | string | Database / catalog name on the OLAP server. |
cubeName | string | Cube name within the catalog. |
WPT File Format
A .wpt file is a plain JSON object that captures the complete state of a WebPivotTable session: data source configuration, pivot field layout, display options, and optionally the raw data itself.
{
"version": "7.0",
"source": {
"mode": "MEMORY", // "MEMORY" | "SERVER" | "OLAP"
"type": "CSV", // "CSV" | "EXCEL" | "WSDATA" | "CUBE" | "WPT"
"name": "sales.csv",
"url": "https://...",
"fields": [
{ "id": "0", "name": "Region", "type": "STRING", "cellIndex": 0 },
{ "id": "1", "name": "Revenue", "type": "NUMBER", "cellIndex": 1 }
],
// Optional embedded data (set ignoreData:true to omit)
"data": [[...], [...]]
},
"sheet": {
"pivot": {
"rows": ["0"],
"columns": [],
"filters": [],
"values": [{ "id": "v0", "fieldId": "1", "name": "Sum of Revenue",
"stats": "SUM", "format": { "category": "CURRENCY" } }],
"fields": {
"0": { "sort": { "sortType": "LABEL", "sortDescend": 0 } }
}
},
"options": {
"displayMode": "grid",
"grid": { "fixedRows": 1, "fixedColumns": 1 },
"chart": { "type": "bar", "theme": "default" }
}
}
}Save and load programmatically
// Save — get a JSON string
const jsonStr = wpt.generateWptString() // includes data
const noDataStr = wpt.generateWptString(true) // excludes data (smaller)
// Save — get a JavaScript object
const jsonObj = wpt.generateWptJSON()
// Load from string / object
wpt.setWpt(JSON.parse(jsonStr))
// Load from URL
wpt.setWptFromWptUrl('/saved/report.wpt')Getting an Instance
// By id
const wpt = document.getElementById('my-wpt')
// By querySelector
const wpt = document.querySelector('web-pivot-table')
// All instances on the page
const all = document.querySelectorAll('web-pivot-table')
// In React — via ref
import { useRef } from 'react'
const ref = useRef(null)
// ref.current is the element after mount
// Check the WPT version
console.log(wpt.version) // e.g. "7.0.0"Data Methods
| Signature | Description |
|---|---|
getData() → WptDataRow[] | Returns the current in-memory raw data rows. |
setData(rows: WptDataRow[]) → void | Replace the current in-memory data with a new array of rows. Use setWptFromDataArray to also re-configure fields. |
getSourceObject() → object | Returns the full internal source object (fields, data, mode, etc.). |
setSourceObject(src: object) → void | Directly replace the internal source object. Advanced — use source methods when possible. |
getFieldCatalog() → FieldDescriptor[] | Returns structured field metadata: name, type, distinct count, sample values, and current zone. Ideal for feeding an LLM. |
Source Methods
Methods that load data and connect data sources. All are async (return a Promise).
| Signature | Description |
|---|---|
setWptFromCsvUrl(url, delimiter?) | Fetch and parse a CSV file from a URL. delimiter defaults to ','. |
setWptFromExcelUrl(url) | Fetch and parse an Excel (.xls/.xlsx) file from a URL. |
setWptFromWebService(url) | Fetch JSON data from a REST endpoint returning { fields, data } or an array of row objects. |
setWptFromGoogleSpreadSheet(url) | Load a public Google Sheet (published as CSV). |
setWptFromDataArray(attrArray, dataArray) | Load from JavaScript arrays. attrArray = [{name, type}], dataArray = rows. |
setWptFromOlapCube(config) | Connect to an XMLA OLAP cube. config = { xmlaUrl, catalogName, cubeName }. |
setWptFromLocalFile(file, type?) | Load from a File object (drag-drop or <input type=file>). Type auto-detected from extension. |
setWptFromWptUrl(url) | Load a saved .wpt JSON file from a URL. |
setWpt(wptObject) | Load from a parsed .wpt JSON object. |
generateWptString(ignoreData?) | Serialize current state to a JSON string. Pass true to omit raw data. |
generateWptJSON(ignoreData?) | Same as above but returns a plain JS object instead of a string. |
get-only counterparts
Every setWptFrom* method has a getSourceFrom* counterpart that parses and returns the source object without loading it into the component. Useful for pre-loading or validating data before display.
const source = await wpt.getSourceFromCsvUrl('/data.csv')
// inspect source.fields, source.data...
wpt.setSourceObject(source) // then load when readyPivot Methods
| Signature | Description |
|---|---|
getPivotState() → object | Returns the current pivot configuration: { rows, columns, filters, values, fields }. |
configurePivot(config) → void | Set the pivot configuration programmatically. Same shape as getPivotState() output. |
getPivotSummary() → object | Returns a human-readable summary of the current pivot (field names, stats, display mode). |
swapAxis() → void | Swap the rows and columns zones. |
clearAllPivot() → void | Remove all fields from all zones (rows, columns, filters, values). |
clearAllFilters() → void | Remove all active filters without changing zone assignments. |
refresh() → void | Force re-compute the pivot. Useful when data changes externally. |
Pre-configuring a pivot layout
// After loading data, automatically set up rows/columns/values:
await wpt.setWptFromCsvUrl('/data/sales.csv')
wpt.configurePivot({
rows: ['region_id'], // field ids from source.fields
columns: ['quarter_id'],
values: [{
id: 'v1',
fieldId: 'revenue_id',
name: 'Total Revenue',
stats: 'SUM',
format: { category: 'CURRENCY', decimal: 0 },
}],
})Lifecycle & UI Methods
| Signature | Description |
|---|---|
setOptions(opts) → WptOptions | Merge new options into the current options and re-render. Returns the merged options object. |
getOptions() → WptOptions | Returns the current options object. |
setLocale(lng) → Promise<void> | Switch the UI language. Loads the locale file if not already cached. |
getLocale() → string | Returns the current locale code (e.g. 'en'). |
reset() → void | Clear all data and return to the initial empty state. |
resize() → void | Trigger a layout measurement. Call after programmatically resizing the container element. |
setSize(w, h) → void | Set the element's CSS width/height. Accepts numbers (pixels) or CSS strings ('100%', '600px'). |
getSize() → {width, height} | Returns the current rendered dimensions in pixels. |
showLoading() → void | Show the loading overlay. |
hideLoading() → void | Hide the loading overlay. |
loadingMessage(msg) → void | Show a custom loading message in the overlay. |
errorMessage(msg) → void | Show an error message overlay. |
clearMessage() → void | Dismiss any active message overlay. |
showControlPanel() → void | Expand the right-side control panel. |
hideControlPanel() → void | Collapse the control panel. |
toggleControlPanel() → void | Toggle the control panel open/closed. |
Export Methods
Export methods are available on the WPT element. All are synchronous unless noted.
| Signature | Description |
|---|---|
exportGridToExcel(filename?) | Export the current pivot grid to a .xlsx Excel file. filename defaults to 'PivotGrid'. |
exportGridToPdf(filename?) | Export the pivot grid to a .pdf file. |
exportGridToHtml(filename?) | Export the pivot grid to a static .html file. |
printGrid() | Print the pivot grid using the browser print dialog. |
exportChartToImage(filename?) | Export the current chart as a PNG file. |
exportChartToPdf(filename?) | Export the current chart as a PDF (async). |
printChart() | Print the current chart using an isolated iframe. |
exportSourceToExcel(filename?) | Export the raw source data to a .xlsx file. |
exportSourceToCsv(filename?) | Export the raw source data as a .csv file. |
printSource() | Print the raw source data table. |
getDisplayMode() → 'grid' | 'chart' | 'both' | Returns the current display mode. |
// Export the grid to Excel
wpt.exportGridToExcel('SalesReport_2024')
// Export the chart as a PNG
wpt.exportChartToImage('SalesChart_Q4')Event Bus
Each WPT instance has its own isolated event bus accessible via wpt.eventBus. Use it to listen to user interactions and component state changes without modifying WPT internals.
Event types
| Event | Payload | When fired |
|---|---|---|
PIVOT_CHANGED | { sheet, source } | Any time the pivot layout changes (field move, filter, sort, etc.). |
DATA_LOADED | { source } | After a data source is successfully loaded. |
DRILL_THROUGH | { sheet, row, column } | User double-clicks (or single-clicks if configured) a data cell. |
OPEN_WPT | string | User triggers the Open WPT action. |
SAVE_WPT | string | User triggers the Save WPT action. |
NEW_WPT | string | User resets to a blank state. |
CONNECT_SOURCE | string | User opens the Connect Data Source dialog. |
Subscribing to events
const wpt = document.getElementById('wpt')
// Subscribe — returns an unsubscribe function
const unsub = wpt.eventBus.on('PIVOT_CHANGED', ({ sheet, source }) => {
console.log('Rows:', sheet.pivot.rows)
console.log('Values:', sheet.pivot.values)
})
// Unsubscribe when done
unsub()
// Or use .off() explicitly
const handler = (payload) => console.log(payload)
wpt.eventBus.on('DATA_LOADED', handler)
wpt.eventBus.off('DATA_LOADED', handler)Intercepting Save / Open with custom logic
// Override Save — store the WPT JSON in your own backend
wpt.eventBus.on('SAVE_WPT', async () => {
const json = wpt.generateWptString()
await fetch('/api/reports/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: json,
})
alert('Report saved!')
})
// Override Open — load from your own backend
wpt.eventBus.on('OPEN_WPT', async () => {
const res = await fetch('/api/reports/latest')
const json = await res.json()
wpt.setWpt(json)
})DOM CustomEvents (alternative to eventBus)
All event bus events are also dispatched as native DOM CustomEvents on the element itself, so you can use addEventListener instead of the event bus:
document.getElementById('wpt').addEventListener('PIVOT_CHANGED', (e) => {
console.log(e.detail) // same payload as eventBus
})AI Integration — Setup & Providers
WPT has a built-in AI assistant that understands your data, answers natural-language questions, configures the pivot automatically, generates narrative insights, explains cell values, and detects statistical anomalies.
Enabling AI
wpt.setOptions({
ai: {
enabled: true,
provider: 'openai', // 'openai' | 'anthropic' | 'google' | 'custom'
apiKey: 'sk-...', // your API key (client-side — consider a proxy for production)
model: 'gpt-4o-mini', // model name
temperature: 0.3, // 0.0 – 1.0
maxTokens: 1500,
// Optional: route through your own backend to hide the API key
endpoint: 'https://api.example.com/ai-proxy',
// Optional: context ID used for multi-instance differentiation
contextId: 'report-v1',
// Optional: custom system prompt prepended to every request
systemPrompt: 'You are a financial data analyst...',
// UI
showChatPanel: true, // open the AI chat tab on load
showInsightButton: true, // show "Generate Insights" button
}
})Provider & endpoint reference
| Provider | Example model | endpoint |
|---|---|---|
| OpenAI | gpt-4o-mini, gpt-4o | https://api.openai.com/v1 (default) |
| Anthropic | claude-3-5-sonnet-20241022 | https://api.anthropic.com/v1 |
gemini-1.5-flash | https://generativelanguage.googleapis.com/v1beta | |
| Custom | any | Any OpenAI-compatible endpoint URL |
endpoint to a backend proxy that injects the key server-side.AI Features
Natural language pivot configuration
The AI chat panel lets users ask questions in plain language. WPT sends the current field catalog (field names, types, sample values) as context. When the AI returns a configurePivot action, the pivot updates automatically.
// Open the AI tab programmatically
wpt.setOptions({ ai: { showChatPanel: true } })
// Or send a message from code
await wpt.aiSendMessage('Show revenue by quarter as a bar chart')
await wpt.aiSendMessage('Filter to APAC region only and sort by revenue descending')AI Insights
Generate a narrative summary of the currently displayed pivot data:
await wpt.aiGenerateInsights()
const text = wpt.aiGetInsights()
console.log(text)
// → "Revenue grew 23% YoY in APAC, led by Q3 at $342K. EMEA underperformed..."Cell explanation
// Click a cell in the grid to auto-populate, or pass context directly:
await wpt.aiExplainCell({
value: 342000,
fmtValue: '$342,000',
rowLabel: 'APAC',
colLabel: 'Q3 2024',
})Anomaly detection (client-side, free)
Z-score based anomaly detection runs entirely in the browser — no LLM calls, no API cost:
const anomalies = wpt.aiDetectAnomalies({ threshold: 2.5 })
// → [{ row: 'APAC', column: 'Q3', value: 342000, zScore: -2.8, direction: 'low' }]AI API Methods
| Signature | Description |
|---|---|
aiSendMessage(msg) → Promise<void> | Send a natural-language message to the AI assistant. |
aiGetMessages() → Message[] | Returns the full chat history: [{role:'user'|'assistant', content, action?}] |
aiClearHistory() → void | Clear the AI chat history. |
aiIsProcessing() → boolean | Returns true if the AI is currently generating a response. |
aiGenerateInsights() → Promise<void> | Generate a narrative summary of the current pivot data. |
aiGetInsights() → string | null | Returns the most recently generated insights text. |
aiExplainCell(cellContext) → Promise<void> | Ask the AI to explain a specific cell value. |
aiDetectAnomalies(opts?) → Anomaly[] | Detect outliers using z-score analysis. Client-side, no LLM call. |
Control Panel
The right-side control panel has three tabs: Fields, Options, and (when AI is enabled) AI.
Fields tab
- Field list (top half) — all available fields from the data source with type icons and value counts. Search and sort the list. Check a field to add it to the pivot automatically.
- Zone panels (bottom half) — drag fields from the list into Filters, Columns, Rows, or Values zones. Drag within a zone to reorder. Drag across zones to move.
- Defer Update checkbox — enable to batch changes; press Refresh to apply.
- Field settings — click the edit icon next to any field to open its settings: custom name, sort order, label/value/top-bottom filters, date grouping.
- Value field settings — click the edit icon on a Value field for: summarization (Sum/Count/Avg/etc.), Show Values As (% of total, running total, etc.), number format, display as number or sparkline.
Options tab
Shared pivot options plus display-mode-specific grid or chart options:
- Display mode: Grid / Chart
- Grid: freeze rows/columns, column widths, row height, show/hide totals and subtotals, conditional formatting
- Chart: chart type, theme, legend position, data labels, stacking
AI tab
Chat interface where users type natural language queries. Responses may include explanatory text and/or automatic pivot reconfigurations.
Pivot Features
Aggregation (Value Field Settings)
| Function | Notes |
|---|---|
| Sum | Default for numeric fields |
| Count | Count all non-null values |
| Distinct Count | Count unique values |
| Average | Arithmetic mean |
| Min / Max | Minimum / maximum value |
| Median | Middle value |
| Mode | Most frequent value |
| Std Dev | Standard deviation |
| Variance | Statistical variance |
| Percentile (Inc/Exc) | Nth percentile, configurable |
Show Values As
- No calculation (raw value)
- % of Grand Total
- % of Column Total
- % of Row Total
- % of Parent Column Total
- % of Parent Row Total
- Running Total by Row
- Running Total by Column
Field features
- Custom names — rename any field in the pivot without modifying source data.
- Sort — sort row/column labels alphabetically (A→Z or Z→A) or by a specific value field.
- Label filter — manually include/exclude values, or define a formula (contains, begins with, between, etc.).
- Value filter — filter rows/columns where a value field meets a condition.
- Top/Bottom filter — show only the top or bottom N items by a value.
- Date grouping — group date fields by Year, Quarter, Month, Week, or Day.
- Hide subtotals — suppress subtotal rows/columns for any dimension.
- Calculated fields — add formula-based computed fields (e.g.
Revenue - Cost).
Number formatting
Each value field can have an independent number format:
- General (raw value)
- Number (decimal places, thousands separator)
- Currency (symbol, prefix/suffix, decimal places)
- Percentage (decimal places)
- Negative number styles:
-1234,(1234), red text variants
Chart & Grid Features
Chart types (powered by Highcharts)
20+ chart types available: Column, Bar, Line, Area, Area-Spline, Spline, Scatter, Bubble, Pie, Donut, Funnel, Pyramid, Gauge, Heatmap, Treemap, Waterfall, Box Plot, Error Bar, 3D variants, and more.
Grid features
- Freeze rows / columns — sticky header rows and left-side row headers while scrolling.
- Column resize — drag column borders to resize. Double-click to auto-fit.
- Row/column totals — grand totals and subtotals with configurable position (top/bottom, left/right).
- Conditional formatting — color scale, data bars, and icon sets on value cells.
- Drill-through — double-click a data cell to see the underlying raw rows.
- Sparklines — display value fields as inline sparkline charts instead of numbers.
- Cell style callbacks — programmatically style rows and cells via
gridCallbacks. - Expand/collapse — multi-level row/column headers can be expanded or collapsed.
- OLAP drill-through — execute DRILLTHROUGH MDX statements for OLAP cubes.
Watermark & License Key
The Community (free) license displays a small "Powered by WPT" badge in the bottom-right corner of the component. This badge links to webpivottable.com and is required by the Community license terms.
Developer, Team, and Enterprise licenses include a license key that permanently hides the watermark for the domain(s) it covers.
Setting your license key
// Via options (most common)
wpt.setOptions({
licenseKey: 'WPT-eyJwbGFuIjoiZGV2ZWxvcGVyIi...signature'
})
// Or as the HTML attribute
<web-pivot-table
options='{"licenseKey":"WPT-eyJwbGFuIjoi..."}'
></web-pivot-table>How the key works
- The key is a signed JWT-like token:
WPT-<base64(payload)>.<hmac-sha256> - The payload encodes: plan tier, email, allowed domains, seat count, and issue date.
- Validation is 100% offline — no network call, no license server. The HMAC is verified client-side using a secret baked into the WPT build.
- Keys are domain-locked: a key for
acme.comwill not hide the watermark on a different domain.localhostalways passes (dev convenience). - Wildcard domains are supported:
*.acme.comcovers all subdomains.
Console messages
If the key is invalid, a helpful console warning explains why:
// Possible [WPT License] messages:
// "License key format is invalid. Keys must start with 'WPT-'."
// "License key signature does not match."
// "License key is not valid for this domain (your-domain.com)."
// "License key has expired."}Release Notes
v7.0 — March 2026
Major architectural rewrite. Fully backward-compatible API.
- React + Zustand core — rewritten in React with isolated per-instance Zustand stores. Multiple instances on one page are fully supported with zero cross-fire.
- Web Component standard — ships as a standard
customElementselement. No Shadow DOM; inline styles only — no global CSS leakage. - TypeScript — full TypeScript support with exported type declarations.
- AI integration — built-in LLM assistant supporting OpenAI, Anthropic, Google, and any OpenAI-compatible endpoint.
- Server mode (DuckDB) — new server-side compute mode via DuckDB. Aggregated results only; raw data never leaves the server.
- Highcharts 11 — updated charting engine with 20+ chart types.
- Themes — four built-in theme presets (default, dark, ocean, forest) with full CSS custom-property overrides.
- Running totals — new Show Values As options: Running Total by Row / Column.
- Sparklines — value fields can be displayed as inline sparkline charts.
- Conditional formatting — color scale, data bars, and icon sets.
- 20 languages — full locale support with lazy-loaded external locale files.
- License system — HMAC-SHA256 domain-locked license keys. Offline validation; no license server.
- Undo/Redo — full pivot state undo/redo (Ctrl+Z / Ctrl+Y).
- Anomaly detection — client-side z-score anomaly detection, no LLM cost.
- Cell explain — AI cell explanation popover on hover/click.
- Date grouping — group date fields by Year, Quarter, Month, Week, Day.
- Calculated fields — formula editor for computed fields.
v6.x (legacy)
- Vue 2-based implementation. No longer actively maintained.
- v7 is fully backward-compatible at the API level —
setWptFromCsvUrl,setOptions,generateWptString, etc. work identically. - v6
.wptfiles are supported by v7 (legacy format auto-upgraded on load).
Support
Community support (free)
- GitHub Repository — github.com/bright-sea/webpivottable — downloads, samples, and customer resources.
- GitHub Issues — github.com/bright-sea/webpivottable/issues — bug reports and feature requests.
- GitHub Discussions — github.com/bright-sea/webpivottable/discussions — Q&A, show and tell, general questions.
Commercial support (licensed customers)
- Priority email support — included with Developer and Team licenses. Response within 1 business day.
- Dedicated support + SLA — included with Enterprise. Direct line to the engineering team.
- Contact — webpivottable.com/contact
Datira.ai — the hosted SaaS alternative
Don't want to embed and manage WPT yourself? Datira.ai is the ready-made SaaS platform built on WPT — upload data, build pivot reports, share with your team, all in the browser. Free tier available.