Creating widgets via the Sisense API
Overview Many companies and organizations use Sisense’s REST API to automate dashboard and widget creation. This can help integrate Sisense with existing automations, dynamically generate dashboards for different users, or manage large scale dashboard and widget deployments programmatically. Sisense provides an API endpoint for creating widgets directly on a dashboard. This allows developers to define widget configurations in JSON and publish them without using the Sisense UI for each new widget. Each widget’s behavior, layout, and data structure are defined in its metadata, mirroring the structure found inside Sisense dashboard export files (.dash files). This use case describes how to create widgets programmatically using the Sisense API and explains how to work with widget metadata and JAQL structures when doing so. What the solution does The Sisense Widget Creation API endpoint allows you to programmatically create widgets on an existing dashboard using a POST request: POST /api/v1/dashboards/{dashboardID}/widgets The request body is a widget metadata object defining the widget’s structure, data query, style, and layout. This metadata format is identical to what Sisense stores within a .dash file. The type property specifies the visualization type (for example, chart/pie, chart/bar, or pivot2), and the metadata section uses the JAQL query format to describe dimensions, measures, and filters. Developers can build widgets dynamically by: Defining visualization type and subtype (e.g., pie chart, bar chart, pivot table) Referencing the correct data source Configuring dimensions and measures within the metadata.panels structure Applying filters or plugin (such as JTD) behaviors Posting the configuration to the API endpoint API Reference: Full documentation for this endpoint and payload structure is available in the Sisense REST API documentation. Understanding widget Metadata Each Sisense widget contains a metadata object that defines the data query (via JAQL), chart style, and layout. A practical way to understand this format is to export a dashboard and inspect the widgets inside the resulting .dash file. Each widget entry includes: type – The widget type (for example, chart/pie, chart/bar, pivot2) datasource – Data model used metadata – A JAQL definition of dimensions, measures, and filters and any other dimensions, equivalent to the left hand panel in widget editor, plus filters style – Visual configuration options such as labels, legends, and axis settings options – Additional behaviors such as filter synchronization or drill options The JAQL format underpins the widget’s data model. It describes how dimensions, measures, and filters are applied when the widget queries the Elasticube or Live data source. References: Sisense JAQL documentation Metadata Item Widget Class Widget Metadata Example payloads Pie Chart Example (Basic Configuration) { "title": "", "type": "chart/pie", "tags": [], "datasource": { "fullname": "localhost/CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "address": "LocalHost", "database": "aCopyOfECommerce", "live": false, "title": "CopyOfECommerce" }, "subtype": "pie/classic", "style": { "legend": { "enabled": false, "position": "left" }, "labels": { "enabled": true, "categories": true, "value": false, "percent": true, "decimals": false, "fontFamily": "Open Sans", "color": "red" }, "convolution": { "enabled": true, "selectedConvolutionType": "byPercentage", "minimalIndependentSlicePercentage": 3, "independentSlicesCount": 7 }, "dataLimits": { "seriesCapacity": 100000 } }, "instanceid": "5466B-AEAE-4D", "drillToDashboardConfig": { "drilledDashboardPrefix": "_drill", "drilledDashboardsFolderPrefix": "", "displayFilterPane": true, "displayDashboardsPane": true, "displayToolbarRow": true, "displayHeaderRow": true, "volatile": false, "hideDrilledDashboards": true, "hideSharedDashboardsForNonOwner": true, "drillToDashboardMenuCaption": "Jump to dashboard", "drillToDashboardRightMenuCaption": "Jump to ", "drillToDashboardNavigateType": 1, "drillToDashboardNavigateTypePivot": 2, "drillToDashboardNavigateTypeCharts": 1, "drillToDashboardNavigateTypeOthers": 3, "excludeFilterDims": [], "includeFilterDims": [], "drilledDashboardDisplayType": 2, "dashboardIds": [], "modalWindowResize": false, "showFolderNameOnMenuSelection": false, "resetDashFiltersAfterJTD": false, "sameCubeRestriction": true, "showJTDIcon": true, "sendPieChartMeasureFiltersOnClick": true, "forceZeroInsteadNull": false, "mergeTargetDashboardFilters": false, "drillToDashboardByName": false }, "realTimeRefreshing": false, "metadata": { "ignore": { "dimensions": [], "ids": [], "all": false }, "panels": [ { "name": "categories", "items": [ { "jaql": { "table": "Brand", "column": "Brand", "dim": "[Brand.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand", "merged": true, "title": "Brand" }, "instanceid": "749C8-B7DE-7A", "field": { "id": "[Brand.Brand]", "index": 0 }, "format": { "members": {} } } ] }, { "name": "values", "items": [] }, { "name": "filters", "items": [] } ] }, "options": { "dashboardFiltersMode": "select", "selector": true, "triggersDomready": true, "autoUpdateOnEveryChange": true, "drillToAnywhere": true } } This payload demonstrates a simple pie chart with one category (dimension) and a single measure, along with styling options for labels and legends. Bar Chart Example (With Filters and Multiple Dimensions) { "title": "", "type": "chart/bar", "tags": [], "datasource": { "fullname": "localhost/CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "address": "LocalHost", "database": "aCopyOfECommerce", "live": false, "title": "CopyOfECommerce" }, "subtype": "bar/classic", "style": { "legend": { "enabled": true, "position": "bottom" }, "seriesLabels": { "enabled": false, "rotation": 0, "labels": { "enabled": false, "types": { "count": false, "percentage": false, "relative": false, "totals": false }, "stacked": false, "stackedPercentage": false } }, "xAxis": { "enabled": true, "ticks": true, "labels": { "enabled": true, "rotation": 0 }, "title": { "enabled": false }, "x2Title": { "enabled": false }, "gridLines": true, "isIntervalEnabled": false }, "yAxis": { "inactive": false, "enabled": true, "ticks": true, "labels": { "enabled": true, "rotation": 0 }, "title": { "enabled": false }, "gridLines": true, "logarithmic": false, "isIntervalEnabled": true, "hideMinMax": false }, "y2Axis": { "inactive": true, "enabled": true, "ticks": true, "labels": { "enabled": true, "rotation": 0 }, "title": { "enabled": false }, "gridLines": false, "logarithmic": false, "isIntervalEnabled": true, "hideMinMax": false }, "dataLimits": { "seriesCapacity": 50, "categoriesCapacity": 100000 }, "navigator": { "enabled": true }, "narration": { "display": "above", "verbosity": "low", "labels": [ { "id": "category", "title": "Category", "singular": "Category", "plural": "Category" }, { "id": "brand", "title": "Brand", "singular": "Brand", "plural": "Brand" } ] } }, "instanceid": "FF03B-0D74-36", "drillToDashboardConfig": { "drilledDashboardPrefix": "_drill", "drilledDashboardsFolderPrefix": "", "displayFilterPane": true, "displayDashboardsPane": true, "displayToolbarRow": true, "displayHeaderRow": true, "volatile": false, "hideDrilledDashboards": true, "hideSharedDashboardsForNonOwner": true, "drillToDashboardMenuCaption": "Jump to dashboard", "drillToDashboardRightMenuCaption": "Jump to ", "drillToDashboardNavigateType": 1, "drillToDashboardNavigateTypePivot": 2, "drillToDashboardNavigateTypeCharts": 1, "drillToDashboardNavigateTypeOthers": 3, "excludeFilterDims": [], "includeFilterDims": [], "drilledDashboardDisplayType": 2, "dashboardIds": [], "modalWindowResize": false, "showFolderNameOnMenuSelection": false, "resetDashFiltersAfterJTD": false, "sameCubeRestriction": true, "showJTDIcon": true, "sendPieChartMeasureFiltersOnClick": true, "forceZeroInsteadNull": false, "mergeTargetDashboardFilters": false, "drillToDashboardByName": false }, "realTimeRefreshing": false, "metadata": { "ignore": { "dimensions": [], "ids": [], "all": false }, "panels": [ { "name": "categories", "items": [ { "jaql": { "table": "Brand_Category_with_NULLS", "column": "Category", "dim": "[Brand_Category_with_NULLS.Category]", "datatype": "text", "columnTitle": "Category", "tableTitle": "Brand_Category_with_NULLS", "merged": true, "title": "Category" }, "instanceid": "635B0-67BA-AF", "field": { "id": "[Brand_Category_with_NULLS.Category]", "index": 0 }, "format": {}, "panel": "rows" } ] }, { "name": "values", "items": [ { "jaql": { "table": "Brand_Category_with_NULLS", "column": "Brand", "dim": "[Brand_Category_with_NULLS.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand_Category_with_NULLS", "merged": true, "title": "# of unique Brand", "agg": "count" }, "instanceid": "DDE5F-0407-39", "panel": "measures", "field": { "id": "[Brand_Category_with_NULLS.Brand]", "index": 2 }, "format": { "mask": { "type": "number", "abbreviations": { "t": true, "b": true, "m": true, "k": true }, "separated": true, "decimals": "auto", "abbreviateAll": false, "isdefault": true } } } ] }, { "name": "break by", "items": [ { "jaql": { "table": "Brand_Category_with_NULLS", "column": "Category", "dim": "[Brand_Category_with_NULLS.Category]", "datatype": "text", "columnTitle": "Category", "tableTitle": "Brand_Category_with_NULLS", "merged": true, "title": "Category" }, "instanceid": "C1963-AE15-BF", "panel": "columns", "field": { "id": "[Brand_Category_with_NULLS.Category]", "index": 1 }, "format": { "members": {} } } ] }, { "name": "filters", "items": [ { "jaql": { "table": "Brand", "column": "Brand", "dim": "[Brand.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand", "merged": true, "isPrimary": false, "isDashboardFilter": false, "datasource": { "fullname": "localhost/CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "address": "LocalHost", "database": "aCopyOfECommerce", "live": false, "title": "CopyOfECommerce" }, "locale": "en-us", "title": "Brand", "collapsed": true, "filter": { "explicit": true, "multiSelection": true, "members": [ "Adbananor WorldWide " ] } }, "instanceid": "7B315-30EC-C0", "panel": "scope" } ] } ] }, "options": { "dashboardFiltersMode": "filter", "selector": true, "triggersDomready": true, "autoUpdateOnEveryChange": true, "drillToAnywhere": true, "previousScrollerLocation": { "min": null, "max": null } } } This example includes multiple JAQL panels (categories, measures, and breakby dimensions), along with explicit filters and advanced style options. It also shows how to define navigation and plugin (such as JTD) configurations. Working with dashboard files Existing dashboard files (.dash) can serve as valuable templates for widget creation. Each widget definition inside a dashboard export can be used as a direct payload for the API. To do this: Export a dashboard from Sisense. Open the .dash file in a text editor. Locate the widget definition under the "widgets" array. Use that widget object as the body of your POST request to the API. This approach allows developers to automate dashboard replication or dynamically add widgets that follow consistent design patterns. Full Dashboard File Example { "title": "TestExport", "oid": "68f924f4b7958b87a83905c3", "desc": "", "source": null, "type": "dashboard", "style": { "palette": { "name": "Vivid", "colors": [ "#00cee6", "#9b9bd7", "#6EDA55", "#fc7570", "#fbb755", "#218A8C" ] } }, "layout": { "instanceid": "87457-1EB6-EA", "type": "columnar", "columns": [ { "width": 100, "cells": [ { "subcells": [ { "elements": [ { "minHeight": 128, "maxHeight": 2048, "minWidth": 128, "maxWidth": 2048, "height": "756px", "defaultWidth": 512, "widgetid": "68f92503b7958b87a83905c5", "autoHeight": "756px" } ], "width": 100, "stretchable": false, "pxlWidth": 647, "index": 0 } ] }, { "subcells": [ { "elements": [ { "minHeight": 96, "maxHeight": 2048, "minWidth": 128, "maxWidth": 2048, "height": 384, "defaultWidth": 512, "widgetid": "68f925dbb7958b87a83905c9" } ], "width": 100, "stretchable": false, "pxlWidth": 647, "index": 0 } ] }, { "subcells": [ { "elements": [ { "minHeight": 96, "maxHeight": 2048, "minWidth": 128, "maxWidth": 2048, "height": 384, "defaultWidth": 512, "widgetid": "68f9269db7958b87a83905cc" } ] } ] } ], "pxlWidth": 647, "index": 0 } ] }, "original": null, "dataExploration": false, "lastOpened": null, "previewLayout": [], "datasource": { "address": "LocalHost", "title": "CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "database": "aCopyOfECommerce", "fullname": "localhost/CopyOfECommerce", "live": false }, "filters": [], "editing": true, "settings": { "autoUpdateOnFiltersChange": true }, "widgets": [ { "title": "", "type": "pivot2", "subtype": "pivot2", "oid": "68f92503b7958b87a83905c5", "desc": null, "source": null, "datasource": { "address": "LocalHost", "title": "CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "database": "aCopyOfECommerce", "fullname": "localhost/CopyOfECommerce", "live": false }, "selection": null, "metadata": { "ignore": { "dimensions": [], "ids": [], "all": false }, "panels": [ { "name": "rows", "items": [ { "jaql": { "table": "Brand", "column": "Brand", "dim": "[Brand.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand", "merged": true, "title": "Brand" }, "instanceid": "D2FFC-C3EB-81", "panel": "rows", "field": { "id": "[Brand.Brand]", "index": 0 } } ] }, { "name": "values", "items": [] }, { "name": "columns", "items": [] }, { "name": "filters", "items": [] } ], "usedFormulasMapping": {} }, "style": { "scroll": false, "pageSize": 25, "automaticHeight": true, "colors": { "rows": true, "columns": false, "headers": false, "members": false, "totals": false } }, "instanceid": "012C6-D97F-BF", "realTimeRefreshing": false, "options": { "dashboardFiltersMode": "filter", "selector": false, "triggersDomready": true, "drillToAnywhere": true }, "dashboardid": "68f924f4b7958b87a83905c3", "query": { "datasource": { "fullname": "localhost/CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "address": "LocalHost", "database": "aCopyOfECommerce", "live": false, "title": "CopyOfECommerce" }, "format": "pivot", "grandTotals": { "title": "Grand Total" }, "metadata": [ { "jaql": { "table": "Brand", "column": "Brand", "dim": "[Brand.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand", "merged": true, "title": "Brand" }, "instanceid": "D2FFC-C3EB-81", "panel": "rows", "field": { "id": "[Brand.Brand]", "index": 0 }, "handlers": [] } ], "m2mThresholdFlag": 0 } }, { "title": "", "type": "chart/pie", "subtype": "pie/classic", "oid": "68f925dbb7958b87a83905c9", "desc": null, "source": null, "datasource": { "address": "LocalHost", "title": "CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "database": "aCopyOfECommerce", "fullname": "localhost/CopyOfECommerce", "live": false }, "selection": null, "metadata": { "ignore": { "dimensions": [], "ids": [], "all": false }, "panels": [ { "name": "categories", "items": [ { "jaql": { "table": "Brand", "column": "Brand", "dim": "[Brand.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand", "merged": true, "title": "Brand" }, "instanceid": "749C8-B7DE-7A", "field": { "id": "[Brand.Brand]", "index": 0 }, "format": { "members": {} } } ] }, { "name": "values", "items": [] }, { "name": "filters", "items": [] } ], "usedFormulasMapping": {} }, "style": { "legend": { "enabled": false, "position": "left" }, "labels": { "enabled": true, "categories": true, "value": false, "percent": true, "decimals": false, "fontFamily": "Open Sans", "color": "red" }, "convolution": { "enabled": true, "selectedConvolutionType": "byPercentage", "minimalIndependentSlicePercentage": 3, "independentSlicesCount": 7 }, "dataLimits": { "seriesCapacity": 100000 } }, "instanceid": "5466B-AEAE-4D", "drillToDashboardConfig": { "drilledDashboardPrefix": "_drill", "drilledDashboardsFolderPrefix": "", "displayFilterPane": true, "displayDashboardsPane": true, "displayToolbarRow": true, "displayHeaderRow": true, "volatile": false, "hideDrilledDashboards": true, "hideSharedDashboardsForNonOwner": true, "drillToDashboardMenuCaption": "Jump to dashboard", "drillToDashboardRightMenuCaption": "Jump to ", "drillToDashboardNavigateType": 1, "drillToDashboardNavigateTypePivot": 2, "drillToDashboardNavigateTypeCharts": 1, "drillToDashboardNavigateTypeOthers": 3, "excludeFilterDims": [], "includeFilterDims": [], "drilledDashboardDisplayType": 2, "dashboardIds": [], "modalWindowResize": false, "showFolderNameOnMenuSelection": false, "resetDashFiltersAfterJTD": false, "sameCubeRestriction": true, "showJTDIcon": true, "sendPieChartMeasureFiltersOnClick": true, "forceZeroInsteadNull": false, "mergeTargetDashboardFilters": false, "drillToDashboardByName": false }, "realTimeRefreshing": false, "options": { "dashboardFiltersMode": "select", "selector": true, "triggersDomready": true, "autoUpdateOnEveryChange": true, "drillToAnywhere": true }, "dashboardid": "68f924f4b7958b87a83905c3" }, { "title": "", "type": "chart/bar", "subtype": "bar/classic", "oid": "68f9269db7958b87a83905cc", "desc": null, "source": null, "datasource": { "address": "LocalHost", "title": "CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "database": "aCopyOfECommerce", "fullname": "localhost/CopyOfECommerce", "live": false }, "selection": null, "metadata": { "ignore": { "dimensions": [], "ids": [], "all": false }, "panels": [ { "name": "categories", "items": [ { "jaql": { "table": "Brand_Category_with_NULLS", "column": "Category", "dim": "[Brand_Category_with_NULLS.Category]", "datatype": "text", "columnTitle": "Category", "tableTitle": "Brand_Category_with_NULLS", "merged": true, "title": "Category" }, "instanceid": "635B0-67BA-AF", "field": { "id": "[Brand_Category_with_NULLS.Category]", "index": 0 }, "format": {}, "panel": "rows" } ] }, { "name": "values", "items": [ { "jaql": { "table": "Brand_Category_with_NULLS", "column": "Brand", "dim": "[Brand_Category_with_NULLS.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand_Category_with_NULLS", "merged": true, "title": "# of unique Brand", "agg": "count" }, "instanceid": "DDE5F-0407-39", "panel": "measures", "field": { "id": "[Brand_Category_with_NULLS.Brand]", "index": 2 }, "format": { "mask": { "type": "number", "abbreviations": { "t": true, "b": true, "m": true, "k": true }, "separated": true, "decimals": "auto", "abbreviateAll": false, "isdefault": true } } } ] }, { "name": "break by", "items": [ { "jaql": { "table": "Brand_Category_with_NULLS", "column": "Category", "dim": "[Brand_Category_with_NULLS.Category]", "datatype": "text", "columnTitle": "Category", "tableTitle": "Brand_Category_with_NULLS", "merged": true, "title": "Category" }, "instanceid": "C1963-AE15-BF", "panel": "columns", "field": { "id": "[Brand_Category_with_NULLS.Category]", "index": 1 }, "format": { "members": {} } } ] }, { "name": "filters", "items": [ { "jaql": { "table": "Brand", "column": "Brand", "dim": "[Brand.Brand]", "datatype": "text", "columnTitle": "Brand", "tableTitle": "Brand", "merged": true, "isPrimary": false, "isDashboardFilter": false, "datasource": { "fullname": "localhost/CopyOfECommerce", "id": "localhost_aCopyOfECommerce", "address": "LocalHost", "database": "aCopyOfECommerce", "live": false, "title": "CopyOfECommerce" }, "locale": "en-us", "title": "Brand", "collapsed": true, "filter": { "explicit": true, "multiSelection": true, "members": [ "Adbananor WorldWide " ] } }, "instanceid": "7B315-30EC-C0", "panel": "scope" } ] } ], "usedFormulasMapping": {} }, "style": { "legend": { "enabled": true, "position": "bottom" }, "seriesLabels": { "enabled": false, "rotation": 0, "labels": { "enabled": false, "types": { "count": false, "percentage": false, "relative": false, "totals": false }, "stacked": false, "stackedPercentage": false } }, "xAxis": { "enabled": true, "ticks": true, "labels": { "enabled": true, "rotation": 0 }, "title": { "enabled": false }, "x2Title": { "enabled": false }, "gridLines": true, "isIntervalEnabled": false }, "yAxis": { "inactive": false, "enabled": true, "ticks": true, "labels": { "enabled": true, "rotation": 0 }, "title": { "enabled": false }, "gridLines": true, "logarithmic": false, "isIntervalEnabled": true, "hideMinMax": false }, "y2Axis": { "inactive": true, "enabled": true, "ticks": true, "labels": { "enabled": true, "rotation": 0 }, "title": { "enabled": false }, "gridLines": false, "logarithmic": false, "isIntervalEnabled": true, "hideMinMax": false }, "dataLimits": { "seriesCapacity": 50, "categoriesCapacity": 100000 }, "navigator": { "enabled": true }, "narration": { "display": "above", "verbosity": "low", "labels": [ { "id": "category", "title": "Category", "singular": "Category", "plural": "Category" }, { "id": "brand", "title": "Brand", "singular": "Brand", "plural": "Brand" } ] } }, "instanceid": "FF03B-0D74-36", "drillToDashboardConfig": { "drilledDashboardPrefix": "_drill", "drilledDashboardsFolderPrefix": "", "displayFilterPane": true, "displayDashboardsPane": true, "displayToolbarRow": true, "displayHeaderRow": true, "volatile": false, "hideDrilledDashboards": true, "hideSharedDashboardsForNonOwner": true, "drillToDashboardMenuCaption": "Jump to dashboard", "drillToDashboardRightMenuCaption": "Jump to ", "drillToDashboardNavigateType": 1, "drillToDashboardNavigateTypePivot": 2, "drillToDashboardNavigateTypeCharts": 1, "drillToDashboardNavigateTypeOthers": 3, "excludeFilterDims": [], "includeFilterDims": [], "drilledDashboardDisplayType": 2, "dashboardIds": [], "modalWindowResize": false, "showFolderNameOnMenuSelection": false, "resetDashFiltersAfterJTD": false, "sameCubeRestriction": true, "showJTDIcon": true, "sendPieChartMeasureFiltersOnClick": true, "forceZeroInsteadNull": false, "mergeTargetDashboardFilters": false, "drillToDashboardByName": false }, "realTimeRefreshing": false, "options": { "dashboardFiltersMode": "filter", "selector": true, "triggersDomready": true, "autoUpdateOnEveryChange": true, "drillToAnywhere": true, "previousScrollerLocation": { "min": null, "max": null } }, "dashboardid": "68f924f4b7958b87a83905c3" } ], "hierarchies": [] } Why it’s useful Creating widgets through the Sisense API offers significant benefits for developers and system administrators: Automation: Supports large scale or dynamic creation of dashboards and widgets without manual effort. Consistency: Enables teams to apply standardized widget templates across multiple dashboards or environments. Integration: Makes it easy to connect Sisense with external systems or automated workflows. Scalability: Allows for the creation of thousands of widgets or dashboards using consistent metadata. Flexibility: By editing the JAQL and style properties, teams can tailor each widget to specific data or design requirements. Programmatic widget creation is particularly valuable for embedding Sisense into larger analytics workflows, for multi-tenant deployments, or for any scenario where dashboards must be created and maintained dynamically. Outcome Using the Widget Creation API endpoint, organizations can generate Sisense dashboards and visualizations in a consistent, repeatable way. Developers can define complex widgets, including data dimensions, filtering, and styling such as color schemes, entirely through JSON payloads, enabling uniform design and reusable frameworks across a large number of programmatically created widgets. By combining automation with Sisense’s flexible JAQL and metadata structure, teams can scale dashboard and widget deployment while maintaining full control over layout, behavior, and visual standards.27Views0likes0CommentsWeek over week analysis with custom fiscal year: Use case of a fuel and convenience retail operator
Introduction Week-over-week (WoW) analysis is a key part of performance tracking for fast-moving, high-traffic businesses such as convenience stores, gas stations, and car washes. For these organizations, aligning the fiscal calendar with operational cycles rather than the standard calendar year makes reporting more meaningful. In this use case, the fiscal year begins on the closest Sunday to January 1st, ensuring each year starts with a full week. This structure simplifies weekly reporting and keeps week-to-week comparisons consistent across years, which is important for tracking trends like fuel sales, store traffic, and service volumes. While nonstandard, this setup is commonly used in practice. What the Solution Does For standard, fixed calendar or fiscal years, week-over-week analysis can be achieved using the “First Month of Fiscal Calendar” and “First Day of Week” settings, along with the PASTYEAR function. However, for dynamic fiscal years that begin on a weekday closest to January 1st, these features don’t provide a usable solution, since the start date can fall in the previous or following calendar year. The solution uses the Filtered Measure certified add-on and a custom dashboard script to handle the custom fiscal year. Two year filters are added to the dashboard: one represents the selected fiscal year (user-selectable), and the other represents the prior year for comparison (locked and optionally hidden), which is automatically set with a dashboard script. The Filtered Measure plugin applies the selected-year filter to the measure for the chosen period, while the prior-year filter applies to the measure for the corresponding period in the previous year. This approach ensures that week-over-week calculations respect the custom fiscal calendar, providing accurate comparisons across equivalent weeks. Note: In this particular implementation, the fiscal years and week numbers are pre-calculated in the database and stored as numeric columns. To create a Date dimension table in your Elasticube with fiscal years starting on the first Sunday closest to January 1st, refer to the SQL example below. Why It’s Useful This solution addresses the native functional limitation by respecting the custom fiscal calendar, ensuring weekly trends are comparable across years. As a result, teams can reliably track key metrics, such as fuel sales, store traffic, and service volumes, on a true week-by-week basis, supporting better operational planning and more informed decision-making. Attachments WeekoverWeekAnalysiswithCustomFiscalYear.dash.txt (dashboard) Sample ECommerce - Custom Fiscal Year.smodel.txt (elasticube) JS Script - Automatic Update for Second Year Filter.txt (dashboard script) SQL Query - Dim Date with Custom Fiscal Year.txt (custom table SQL query) For the script to hide the second filter, refer to this BINextLevel article: Hide dashboard filters. Note: remove the .txt extension before importing the dashboard (.dash) and the Elasticube (.smodel) files.111Views1like0CommentsConnection Tool - Programmatically Remove Unused Datasource Connections, and List All Connections
Managing connections within your Sisense environment can become complex over time, if there are a large number of connections, and connections are often added, and replace earlier datasource connections. In some scenarios unused connections can accumulate, potentially cluttering the connection manager UI with no longer relevant connections. Although unused connections typically represent minimal direct security risk, it's considered best practice to maintain a clean, organized list of connections, and in some scenarios it can be desired to remove all unused connections. Sisense prevents the deletion of connections actively used in datasources, safeguarding your dashboards and datasources from disruptions. However, inactive or "orphaned" connections remain after datasources are deleted or a connection is replaced, potentially contributing to unnecessary UI complexity in the connection manager UI. Connections can be of any type Sisense supports, common types include various SQL connections, Excel files, and CSV files, as well as many data providers, such as Big Panda. This tool can also be used to list all connections, with no automatic deletion of unused connections.460Views4likes3CommentsResolving "Internal Server Error" When Importing Model with Generic JDBC Connector [LINUX]
Resolving "Internal Server Error" When Importing Model with Generic JDBC Connector This article addresses the issue of encountering an "Internal Server Error" when importing a model from a local desktop to a production environment using the Generic JDBC connector in Sisense. This error often arises due to compatibility issues with older JDBC frameworks. Here, we provide a solution to resolve this error by updating the JDBC connector and connections. Step-by-Step Guide: Identify the Error: a. When importing the model, if you receive an error message resembling: Unexpected error value: { timestamp: {}, status: 500, error: "Internal Server Error", path: "/api/v1/internal/live_connectors/auth/GenericJDBC… } b. This error could indicate a problem with the outdated Generic JDBC connector. Understand the Cause: The error is due to the Generic JDBC connector using an older framework that is incompatible with the latest Sisense versions. Update the JDBC Connector: Deploy the JDBC connector using the new JDBC framework. Ensure all connections within the cube in the original environment where the model was exported are updated accordingly. Deploying the New Framework: Follow the step-by-step instructions detailed in the Sisense documentation for deploying a custom connector with the new JDBC framework. Access the documentation here: Deploying a Custom Connector - Sisense Documentation. Re-attempt the Model Import: Once the JDBC connector is updated, try importing the model again into the production environment. Conclusion: In conclusion, updating the Generic JDBC connector to align with the new JDBC framework and ensuring the connections are properly configured should resolve the "Internal Server Error" encountered during the import process. Following the above steps will help ensure a smooth and successful model import. References/Related Content: Deploying a Custom Connector - Sisense Documentation Sisense Community Support Forum Introduction to Data Sources Disclaimer: This post outlines a potential custom workaround for a specific use case or provides instructions regarding a specific task. The solution may not work in all scenarios or Sisense versions, so we strongly recommend testing it in your environment before deployment. If you need further assistance with this please let us know.208Views1like0CommentsResolving "Internal Server Error" When Importing Model with Generic JDBC Connector
This article addresses the issue of encountering an "Internal Server Error" when importing a model from a local desktop to a production environment using the Generic JDBC connector in Sisense. This error often arises due to compatibility issues with older JDBC frameworks. Here, we provide a solution to resolve this error by updating the JDBC connector and connections.306Views1like0CommentsRedirect users to different dashboards based on dashboard filters
This article discusses and shares the full code of a dashboard script that redirects users to a different dashboard ID based on the user's filter selections or initial loaded filter state. In the particular example shared in this article, the script checks whether the selected date filter (either from a members filter or a from/to filter range) includes an earlier date than the earliest date in the current dashboard's datasource. If this is the case, the script redirects the user to a specified alternate dashboard, preserving any additional URL segments and query parameters in the URL. Any other type of filter state can also be used to determine on when the script should redirect, including non-date filters using similar scripts.489Views1like0CommentsFilter BETWEEN two dates in the model
Filter BETWEEN two dates in the model This article explains how to create a filter to return data between two fields in the model. The following cases will be covered: Show only active contracts on the given date; To show the status of the record on the given date. The first challenge is to show only active contracts on the given date. Let’s assume that we have the following columns in the table “History”: Id; From; To. Let's assume that the contract is active if the given date is between [From] and [To]. To filter the dates we will create two filters on the dashboard using these fields. Now, end-users can choose the same date in these filters. This is not a good user experience, because the user will have to update two filters. To improve user experience we will do the following: Lock these filters - a user will not update these filters manually. Use element Input.Date of the widget “BloX” to let a user provide a date; Create a custom action to update the filters [From] and [To]. Let’s create the action “betweenDates”: const { data, widget } = payload; const { selectedDate, fromDateDim, toDateDim } = data; if (!(selectedDate && fromDateDim && toDateDim)) { return; } const fromFilter = widget.dashboard.filters.item(true, fromDateDim); const toFilter = widget.dashboard.filters.item(true, toDateDim); if (!(toFilter && fromFilter)) { return; } setNewDatesInFilters(fromFilter, toFilter, selectedDate); widget.dashboard.refresh(); function setNewDatesInFilters(fromFilter, toFilter, newDate) { toFilter.jaql.filter = { from: newDate }; fromFilter.jaql.filter = { to: newDate }; updateFilter(toFilter.jaql); updateFilter(fromFilter.jaql, true); } function updateFilter(filterObject, save = false) { widget.dashboard.filters.update({ jaql: filterObject }, { save, refresh: false }) } Snippet of this action: { "type": "betweenDates", "title": "Apply", "data": { "selectedDate": "", "fromDateDim": "", "toDateDim": "" } } Let’s use this action in the BloX. Also, we will add the element “Input.Date”. As the result, we will get the following BloX JSON: { "style": "", "script": "", "title": "", "showCarousel": true, "body": [ { "type": "Container", "items": [ { "type": "Input.Date", "id": "data.selectedDate", "class": "" } ] } ], "actions": [ { "type": "betweenDates", "title": "Apply", "data": { "selectedDate": "", "fromDateDim": "[History.From (Calendar)]", "toDateDim": "[History.To (Calendar)]" } } ] } Now, you can choose a date and after clicking “Apply” both filters will be updated with the selected date. The only issue - input field is cleared. We will fix this by adding a simple widget’s script to the widget BloX - this script will persist the selected date in the input field: widget.on('ready', () => { const toFilter = widget.dashboard.filters.item('[History.To (Calendar)]'); const selectedDate = $$get(toFilter, "jaql.filter.from"); if (selectedDate && document.getElementById('data.selectedDate')) { document.getElementById('data.selectedDate').value = selectedDate; } }) Now, when the dashboard is loaded, the script finds the previously selected date and fills in the input field. Also, when a user changes the date, the newly input date is shown. Let’s solve the second challenge to show statuses of the record on the given date. Let’s assume that we have table “Cases”. In this table we have historical information about cases: Id - unique identifier of the record; CaseId - case’s identifier; Status - status of the case; Date - date when case status was changed. Sample of the data in this table: [ALT text: A table displaying case information with the following columns: Id, CaseId, Status, and Date. The table includes rows showing various case entries with status updates such as "New," "Open," "Reopen," and "Closed," along with corresponding timestamps for each case.] Use-case: as an end-user, I want to input the date and Sisense should return the status of the case in the given date. To accomplish this, let’s create a new custom table “History”, where we will compute the first date of the status and its last date. This custom table will be populated with the next SQL query: SELECT CaseId, [Old Status], [New Status], [From], [To] FROM ( SELECT c.[CaseId], c.[Status] "Old status", cc.[Status] "New status", c.[Date] "From", cc.[Date] "To", RankCompetitionAsc(c.CaseId, c.[Status], c.Date, cc.Date) "Rank" FROM Cases c INNER JOIN Cases cc ON c.[CaseId] = cc.[CaseId] and c.date < cc.date ) c WHERE c.Rank = 1 UNION ( SELECT c.[CaseId], c.[Status] "Old Status", '' "New status", c.date "From", CreateDate(2999, 12, 31) "To" FROM Cases c INNER JOIN ( select caseId, max(date) "MaxDate" from cases group by caseId ) latestStatus ON c.[CaseId] = latestStatus.caseId and latestStatus.MaxDate = c.date ) This query contains two parts: The first part returns statuses, which were already changed and we have information about the status after the change; The second part shows the current status of the record. As a result of the data transformation, we will have the following structure: [ALT Text: A table displaying status updates with columns labeled "CaseId," "Old Status," "New Status," "From," and "To." There are five rows of data showing various cases, their old and new statuses, and corresponding timestamps for when the status changes occurred. The "From" and "To" columns indicate the date and time of the changes. Some cases are marked as "New," "Open," "Closed," and "Reopen."] Now, we will use approach from the first part of this article to create dashboard’s filters and utilize BloX to input the date and custom action to update the dashboard’s filters. Conclusion In this article we reviewed a possible way to manipulate date filters. A similar approach you can use for embedding cases. Since the filters will be controlled from the BloX widget and filters will be locked for manual editing, you can even hide these dates filters using the following plugin: https://www.sisense.com/marketplace/add-on/hide-filters Similar Content: Sisense Docs Disclaimer: This post outlines a potential custom workaround for a specific use case or provides instructions regarding a specific task. The solution may not work in all scenarios or Sisense versions, so we strongly recommend testing it in your environment before deployment. If you need further assistance with this please let us know.464Views1like0CommentsResolving Missing Parse Option in SQL DB Connection
This article addresses the issue of the missing "Parse" option when connecting to an SQL database in Sisense. Users may encounter this problem when attempting to parse data from SQL DB connections. This guide will explain why the "Parse" option might be unavailable and provide steps to resolve the issue.370Views1like0Comments