Building With the QuantumLayers JDK: Load Order, Sign-In, and Your First Live Chart

The last post named the two ways into the API and left the JDK described but not yet used. This one takes that path in code. It covers the load order every module depends on, how to sign a user in from your own origin, and how to get a rendered chart on the page with a single function call.


Where This Fits

The first post argued for embedding QuantumLayers rather than rebuilding an analytics stack. The second went through the request envelope, the three authentication paths, and the choice between raw API calls and the bundled JavaScript Development Kit. The short version, if you skipped it, is that every capability is a WordPress AJAX action posted to one URL, and the JDK is a set of browser modules that build those requests for you. This post takes the JDK path and makes it concrete, drawing on the JDK reference for the exact modules and functions. The three reference pages, the Developer Guide, the API reference, and the JDK reference, remain the place to look up anything this post leaves out.

Load Order Is the Whole Game

The JDK has no build step and no npm package. Each module is a standalone file under https://quantumlayers.com/jdk/ that you pull in with a plain script tag. The catch is that the tags have to appear in a specific order, because the modules depend on each other at load time rather than through an import graph.

Three rules cover it. jQuery loads first, since every module is built on it. auth.js loads next, before any other QL module, because all of them call QLAuth.getSessionToken() to attach their Bearer header. Chart rendering adds the last rule: Chart.js 4.4.0 and its three plugins have to be present before analytics.js runs, and insights.js has to come after analytics.js, since insights hands its embedded charts to QLAnalytics.renderChart() to draw. Get the order wrong and the affected pieces fail quietly, so it is worth setting up once and leaving alone.

One more thing has to exist before auth.js runs its own init(): a global qlAuth object carrying the AJAX URL. On a third-party page you define it yourself. The nonce field is only meaningful for same-origin requests and can be left empty for cross-origin use.

The box-plot plugin is only needed for box_plot and violin charts, the date adapter for time_series and stacked_area, and the matrix plugin for heatmap and matrix. If you are not rendering those types you can drop the plugins you do not use, but the order among the ones you keep stays the same.

What “Using a Module” Means Here

The JDK is not a plain data library where you call a function and get JSON back. Each module runs init() on load, reads the current dataset ID from the page URL, finds elements by fixed IDs and CSS classes, binds event handlers to them, and renders results into the page. Give a module the DOM it expects and you get the same behavior QuantumLayers itself ships: the drag-and-drop uploader, the chart builder, the statistical modals, the insights panel.

A smaller set of functions is meant to be called directly from your own code, and those are the ones worth knowing by name: the QLAuth token helpers and QLAuth.thirdPartySignin(), plus QLAnalytics.loadChart() and the analysis functions behind the modals. So there are two ways to work with any given module. Mount its UI by supplying the elements it binds to, or drive the parts you want from JavaScript. The examples below use both.

Signing a User In From Your Own Origin

Cross-origin embedding runs through QLAuth.thirdPartySignin(). Your backend mints a short HS256 JWT, the minting code was in the previous post, and you hand it to the helper, which posts it to QuantumLayers, stores the session token it gets back, and calls your success callback with the user.

After that call, every other module picks up the stored token on its own through getSessionToken(). That function is wrapped so it fails safe: in a sandboxed iframe or a strict privacy mode where storage access throws, it returns null rather than erroring, and modules then fall back to same-origin nonce authentication. For a cross-origin embed that fallback carries no real session, which is the practical reason to establish the token through thirdPartySignin() before any module tries to fetch data.

If your page already lives on the QuantumLayers origin and the user signed in there, you skip all of this. The token is already in localStorage and getSessionToken() returns it.

A Chart in One Call

QLAnalytics.loadChart() is the function that turns a dataset column mapping into a rendered Chart.js instance. You give it a container ID, a chart type, and the columns that type needs, and it fetches the aggregated data from ql_get_chart_data and draws into the container. Filtering and aggregation happen on the server, so the browser only ever receives a finished chart config. Start with an empty container on the page:

Then call loadChart with the mapping the chart type expects. A bar chart takes a category column and one or more value columns; a scatter takes an x and a y:

The signature is loadChart(containerId, chartType, x, y, z, color), and the later arguments are only used by the types that need them: z for the size axis of a bubble chart or the value of a matrix, color for a bubble chart’s color dimension. The x and y arguments accept an array wherever a type allows several columns, such as the value columns of a bar or time series, or the multiple x columns of a regression.

The Statistical Modals

The four analysis functions each open a modal, request their data, and render a table plus, in three of the four cases, a chart. On a page that includes the analytics markup, init() already binds them to their buttons, so supplying a button with the right ID is enough to get the feature:

The bound IDs are #ql-correlation-btn, #ql-pca-btn, #ql-anova-btn, and #ql-stats-btn. You can also call any of them yourself:

Correlation returns a Pearson matrix rendered as a color-coded table, a heatmap, and a bar chart of the strongest pairs. PCA returns explained variance, a scree plot, a loadings table, and a scatter of the first two components. ANOVA reports F-statistics, p-values, and significance for every categorical-by-numeric pairing. The summary is a single adaptive table, numeric columns showing mean and standard deviation, categorical columns showing unique counts and the most frequent value.

AI Insights

QLInsights is the one module that departs from the pattern. It is an ES6 class instantiated once on load as insightsPanel, and it is not exposed on window, so you drive it entirely through the DOM rather than by calling it. The trigger is a button:

Clicking it reads the filter and column controls from the page, requests insights from ql_get_insights, and renders the returned cards as narrative text with severity badges and view-chart actions. Because those embedded charts are drawn by QLAnalytics.renderChart(), this is the module that leans hardest on the load order above: analytics.js has to have run first, or the charts inside the insights fall back to an unavailable placeholder. An optional column multi-select, #ql-insights-column-selector, and the shared date and category filters narrow what gets analyzed when they are present.

Upload, and Everything Past It

QLUpload gives you the full ingestion page for the cost of a form. The module looks for #ql-upload-form, a #file-drop-zone, a #csv_file input, and a #dataset_name field, then wires up drag-and-drop, a 50MB client-side size check, a live progress bar driven by upload events, and a redirect to the dashboard with ?uploaded=1&dataset_id= once processing finishes. Open the same page with a numeric dataset ID in the query string and it switches to edit mode, where the CSV becomes optional and only the name or visibility need change.

The remaining modules follow the same shape. QLDashboard renders the dataset inventory and scheduled-reports panel and owns the lifecycle actions, delete, resync, and visibility, that redirect back with a status flag. QLMergeDatasets builds SQL-style joins between datasets through checkboxes and dropdowns. QLReportScheduler assembles the nested per-section config for a recurring PDF or HTML report. QLOrganizations handles seats and billing, and is the one module with an extra dependency, Paddle.js v2 loaded before it for the checkout overlay. QLAgent wraps the conversational loop, running one turn per user message and rendering the reply, charts included, through the same analytics rendering path.

A Realistic First Page

Put together, a first embed is short. You define qlAuth, load jQuery and auth.js, and sign the user in with thirdPartySignin() using a JWT from your backend. You load Chart.js with its plugins and analytics.js, drop an empty container on the page, and call loadChart(). That is a live, server-aggregated chart with no ingestion code, no aggregation code, and no request plumbing on your side.

Adding correlation next to it is one button. Turning it into a conversational surface is agent.js and the same token. The request shape never changes, so each thing you add costs about as much as the first, and the reference pages are there for the exact parameter or response field when you reach it.


This is the third post in the QuantumLayers series on embedded analytics. Start with the Developer Guide for prerequisites and authentication, the API reference for every endpoint, and the JDK reference for every module and function. Start building at www.quantumlayers.com.