Oracle Developers
Published in

Oracle Developers

A Guide to Embedding Oracle Analytics into Oracle Application Express (APEX)

Oracle Application Express (APEX)

Oracle Application Express, or APEX, is a low-code development environment that makes it easy to create your own applications. At the recent Oracle Cloud World event (‘22), APEX was used to rapidly create applications to help with the global pandemic and was highlighted in one of the keynotes.

If you’ve landed on this page, you probably already know about APEX and you may be wondering why you’d want to embed Oracle Analytics Cloud (OAC) into APEX. In fact, at a conference in 2019, I was asked that exact question, as APEX already has a rich set of reporting and visualisation capabilities with a lot of those visualisations based on Oracle JET (in both products).

My response? APEX and OAC are complimentary products with some overlap in the types of visualisations available but also offer the other product additional capabilities — resulting in a more comprehensive user experience for both data engineers and business end users.

Here are some examples I’ll describe in detail later:

I could list more, but overall, I think the use of these two products together is worth your consideration and this blog will provide details on how to get the best out of this combination.

Why the product version is important

I mentioned Oracle JET in the introduction to this blog. This is an important aspect of integrating APEX and OAC. Here is how you can find out what versions of JET each product is using.

For APEX, this is usually described in the product documentation. The versions I’ve been using to create this blog have been 21.2 (JET 11) and 22.1 (JET 12). The APEX documentation also describes how JET is used, with version 22.1 listing ‘chart’ region types as well ‘text field with autocomplete’ item types. This will impact on the method used to embed OAC content into APEX, since mixing different versions of JET on the same application page will potentially result in unpredictable outcomes.

In order to find out the version of JET that is being used by Oracle Analytics, while logged in to Analytics, open the browser developer tools console and execute the following:


I’ve been using the Sept ’22 and Nov ’22 versions of Oracle Analytics Cloud while writing this blog and the version of JET used is 11.1.0.

Oracle Analytics embedding scripts

After you have enabled the ‘Developer’ options in OAC (you set this in the Profile | Advanced menu options), you can view the developer area in OAC that includes the ‘Embed’ section.

Oracle Analytics Developer Embed Section

The link for embedding.js, offers two options, /standalone/ which is used when embedding into an application that doesn’t use Oracle JET or /jet/ which is used when the application does use Oracle JET. As we’ve seen from the APEX documentation, some aspects of APEX use JET and some don’t. Later we’ll see how this is a consideration when developing your APEX application and how you choose to embed the OAC canvases.


APEX uses authentication schemes to secure applications with a default of Oracle APEX Accounts. Oracle Analytics Cloud, uses Oracle Identity Cloud Service (IDCS) authentication.

At this stage, you could either choose for your end users to log in to the APEX application, and then require them to also log in to embedded analytics content (that may be desired if you’d like to limit access to embedded analytics, within the APEX application) or, it’s more likely that you’ll want a seamless authentication experience where a user who logs into the APEX application will also be authenticated to the analytics content. This is achieved by creating ‘Web Credentials’ and an ‘Authentication Scheme’ within APEX that use the same Oracle IDCS as analytics. Here are some links (1)(2)(3) to articles that describe how to configure APEX for IDCS authentication.

If you still see a login prompt in the region where you have embedded analytics, and you are using the <oracle-dv> HTML embedding method, then you may need to add the following to the link to embedding.js:

<script src=""https://<instance>" type="application/javascript">

Embed a URL link to Oracle Analytics workbook

The easiest way to add Oracle Analytics content to an APEX application is to reference a workbook URL as follows:

The view of the canvas that you see in APEX will depend on a number of factors that can be tailored to your requirements.


There are some settings, that have been introduced in the Sept ’22 and Nov ’22 releases of OAC that can tailor this experience further:

Not showing the header bar and showing the viewer user view provides the most seamless embedding experience.

Using Oracle Analytics JavaScript embedding

Using the Oracle Analytics JavaScript embedding framework can enable a more integrated user experience for analytics content in an APEX application. This is where the version of Oracle JET being used by APEX and OAC can be important, in addition, whether you have any APEX components that use JET (e.g., APEX charts) on the application page can potentially result in unexpected behaviour (e.g, some OAC visualisations may not fully render or there may be CSS clashes, especially if using /standalone/ path).

OAC and APEX on same JET version

In this scenario, set the following at the APEX page level ‘JavaScript’ field, note the [require jet] in addition to using the /jet/ path to embedding.js:

Note that the usual requirejs dependencies and knockout apply bindings may not be required for you to see the embedded analytics.

You will then add the <oracle-dv> tag in an APEX static content region, in the ‘Source’ field:

If you use the /standalone/ path to embedding.js, then you don’t need to use the [require jet] in the JavaScript section.

OAC and APEX on different JET versions

If different JET versions are present, it then depends on what other APEX items are on the same application page as the one you wish to embed OAC content. If the APEX items on the application page don’t use JET, then you can use the /jet/ path, but it still may be the case that not all OAC visualisation types will render.

In general, the most reliable way to embed analytics given the possibility of different JET versions being present is to use an iFrame. I’ve written about this method in this blog, including how to pass parameters into the iFrame using windows messaging from APEX UI controls such as selectors and faceted searches which is where the real benefits of using OAC and APEX together can be realised.

Data sources

Ideally, both OAC and APEX should use the same data source. It’s easy to get data into both OAC and APEX, either using XLS files that are uploaded into a DB table, in the case of APEX or by creating data sources in OAC either from uploaded XLS or by creating connections to a DB and then creating a suitable data source.

Using the same data source will most likely require a connection from OAC to the schema that APEX uses to store application data. For my examples, I’ll be using an APEX application built using data on NYC Schools from this live lab.

I will assume that the data has been uploaded according to the live lab and the APEX application has been created. You will also need to have a connection and datasource created in OAC to the schema used by APEX for the application. You’ll be able to discover this using the SQL Workshop in APEX. If you are not able to get the connection wallet for the DB used by APEX, then you could upload the NYC Schools data directly to OAC.

The key requirement is that both OAC and APEX are able to access the same data set, whether that is stored in the same place or not.

Creating user experiences that add value

In this section, I’ll describe how the combination of OAC and APEX can add value to a users experience. I’ve defined ‘value’ as OAC doing something that might not be available out of the box with APEX (e.g. adding natural language narratives) and vice versa (e.g., using APEX faceted searches with embedded analytics).

Add OAC TAG cloud and NLG to an APEX app

This animation illustrates the user experience we’re going to build, both using an iFrame and without an iFrame.

As a pre-requisite, I’ll assume that you’ve created a datasource in OAC that is using the same data as the APEX application and that you’ve created a workbook in OAC that shows a Tag Cloud and Natural Language Generation (NLG) visualisations. I’ve copied the application page ‘NYC Highschools Report’ from the live lab APEX app and we will add the OAC tag cloud and NLG visualisation to that page.

Embedding without using an iFrame

Add a select list item to the application page. This will get a list of values from a SQL statement and the selection will be stored in P7_SELECT_BOROUGH (you may have a different item name) :

select distinct BOROUGH d, BOROUGH r
order by 1

Use the following HTML code within this static region, note that the active-tab-id number has been obtained from the OAC developer | embed menu in my workbook that’s being used for the embed. The items in {{ }} are known as observables and will be populated using code that will be defined at the application page level:

<div style='width:1024px; height:800px' ><oracle-dv id='Filter'
project-options='{"bDisableMobileLayout":true, "bShowFilterBar":false}'

At the application page level, add code similar to this (appropriate for your instance and the OAC user who owns the data set (in the path for ‘sColFormula’):

In the File URLs, is the link (/jet/) to embedding.js for the OAC instance, and the parameter [require jet]. This example is using the three-legged auth parameter but please refer to earlier in this blog about configuring your APEX instance to use IDCS authentication:

[require jet]

In the ‘Function and Global Variable Declaration’ section, there is code to assign the value of the P7_SELECT_BOROUGH defined earlier to a JavaScript variable:

let vBoroughName = apex.item("P7_SELECT_BOROUGH").getValue();

In the ‘Execute When Page Loads’ section, the observables are defined for the <oracle-dv> tag as well as the filter JSON used by the embedded OAC canvas. The ‘sColFormula’ can be obtained from the OAC workbook developer | JSON menu option:

requirejs(['jquery', 'knockout', 'obitech-application/application', 'ojs/ojcore', 'ojs/ojknockout', 'ojs/ojcomposite',  'jet-composites/oracle-dv/loader'],
function($, ko, application) {
function model() {
var self = this;
self.projectPath = ko.observable('/@Catalog/shared/Embed/APEX/APEX NYC Schools');
self.filters = ko.observableArray([{
'sColFormula': "XSA('<data-set-owner>'.'APEX NYC HIGHSCHOOLS').\"NYC_HIGHSCHOOLS\".\"BOROUGH\"",
'sColName': 'BOROUGH',
'sOperator': 'in',
'isNumericCol': false,
'isDateCol': false,
'bIsDoubleColumn': false,
'aCodeValues': [],
'aDisplayValues': [vBoroughName]}]);
ko.applyBindings(new model());

This is executed when the selector for P7_SELECT_BOROUGH is used (due to the ‘Page Submit’ option), obtaining the value into the variable vBoroughName and then passing that into the filter JSON for the embedded OAC canvas. The ‘aDisplayValues’ is expecting an array, so the value passed (vBoroughName) needs to be enclosed in [ ] brackets.

At this point, run the application and test that changing selector values changes the borough shown in the APEX table report and embedded OAC content.

Embedding using an iFrame

If you have different versions of JET in use (as described earlier) then you most likely need to use an iFrame to embed OAC canvases into an APEX application. The following illustrates this type of deployment for an application page:

The key difference with using an iFrame is that all the OAC embedding code i.e., the link /standalone/ to embedding.js, the <oracle-dv> tag, the requirejs dependencies and knockout applybindings are all contained within the iFrame. The iFrame then acts as a re-usable block that can be embedded in multiple application pages, with minor changes if needed as described later in this blog. The mechanism to pass filter values into the iFrame is contentWindow.postMessage.

The APEX static region that includes the OAC embedded content includes HTML code that defines the iFrame using the srcdoc parameter:

<iframe  id='OACiFrameEmbed' width="1024" height="800" srcdoc="<!DOCTYPE HTML><html dir='ltr'><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'><script src='https://<OAC-INSTANCE>' type='application/javascript'></script></head><body><div style='width:1024px; height:800px' ><oracle-dv id='Filter'project-path='<PATH-TO-EMBEDDED-WORKBOOK'active-page='canvas'active-tab-id='1'project-options='{&quot;bDisableMobileLayout&quot;:true, &quot;bShowFilterBar&quot;:false}'filters='{{filters}}'></oracle-dv></div><script>requirejs(['jquery','knockout','ojs/ojcore', 'ojs/ojknockout', 'ojs/ojcomposite', 'obitech-application/application', 'jet-composites/oracle-dv/loader'],function($, ko, application) {function model() {var self = this;self.filters = ko.observableArray([{'sColFormula': &quot;XSA('<OAC-USER-ID>'.'APEX NYC HIGHSCHOOLS').\&quot;NYC_HIGHSCHOOLS\&quot;.\&quot;BOROUGH\&quot;&quot;,'sColName': 'BOROUGH','sOperator': 'in','isNumericCol': false,'isDateCol': false,'bIsDoubleColumn': false,'aCodeValues': [],'aDisplayValues': ['Select Borough']}]);window.addEventListener('message', (event) => {if ((typeof === 'string' || instanceof String) && event.origin == 'https://<APEX-DOMAIN>') {self.filters([{'sColFormula': &quot;XSA('<OAC-USER-ID>'.'APEX NYC HIGHSCHOOLS').\&quot;NYC_HIGHSCHOOLS\&quot;.\&quot;BOROUGH\&quot;&quot;,'sColName': 'BOROUGH','sOperator': 'in','isNumericCol': false,'isDateCol': false,'bIsDoubleColumn': false,'aCodeValues': [],'aDisplayValues': []}]);}}, false);}ko.applyBindings(new model);});</script></body></html>"></iframe>

Since the srcdoc parameter value is enclosed in double quotes, then any double quotes used within the srcdoc code need to be escaped to &quot;

This is required for the project-options and sColFormula. Also, the domain that is passing the message into the iFrame needs to be specified at the point the message is passed in addition to the listener in the iFrame. For these examples, that domain is the APEX instance.

The APEX selector, has ‘Submit Page’ as the ‘Page Action on Selection’. In order to pass the selected value into the iFrame, set code such as the following for the ‘Execute when Page Loads’ page level property. The setTimeout is to avoid any race conditions that may occur:

vBoroughName = apex.item("P9_SELECT_BOROUGH").getValue();
setTimeout(() => { document.getElementById(‘OACiFrameEmbed’).contentWindow.postMessage(vBoroughName, ‘https://<APEX-INSTANCE>’); }, 2500);

Changes needed to enable a multi-select

If you want to enable users to select more than one borough, here are the changes you need to make.

Modify the selector, P9_SELECT_BOROUGH so that the ‘Page Action on Selection’ is ‘None’.

Add a button to the page, I’ve placed it below the selector item itself on my application page.

One key difference when dealing with multiple selections is that it is now an array object that is being passed to the embedded Oracle Analytics canvas. As such, there are some changes needed to the code in the iFrame, compared to the single select use case.

if ((Array.isArray( && event.origin == 'https://<APEX-INSTANCE>') {self.filters([{'sColFormula': &quot;XSA('<USER>'.'APEX NYC HIGHSCHOOLS').\&quot;NYC_HIGHSCHOOLS\&quot;.\&quot;BOROUGH\&quot;&quot;,'sColName': 'BOROUGH','sOperator': 'in','isNumericCol': false,'isDateCol': false,'bIsDoubleColumn': false,'aCodeValues': [],'aDisplayValues':}]);}}, false);

Using APEX faceted search to filter embedded analytics

Adding embedded analytics (in an iFrame) to an APEX page that contains a faceted search is very similar to the previous embedding scenarios.

vBoroughName = apex.item("P8_BOROUGH").getValue();aBoroughArray = vBoroughName.split(":");setTimeout(() => { document.getElementById('OACiFrameEmbed').contentWindow.postMessage(aBoroughArray, 'https://<APEX-INSTANCE>'); }, 2000);


Using Oracle Analytics (OAC) with APEX can add value to your applications. In this blog I’ve described the importance of the JET version as well as provided links to descriptions of how to configure APEX to use the same Oracle Identity Cloud Service as OAC to provide a seamless experience.

Using iFrames (in particular the ‘srcdoc’ parameter) to embed the analytics content, offers a way to deal with the possibility of different JET versions being present, by sandboxing the analytic content.

It is still possible to pass parameters to the embedded iFrame using the ‘postMessage’ method. The general approach is that the iFrame contains the self-contained analytics embedding code — links to embedding framework, HTML for the <oracle-dv> embed tag, requirejs dependency management and observable definitions.

The definition of the filters applied to the embedded content is defined as an observable array and differences are required depending on if the use case is a single select (add [ ] brackets around the or multi-select / faceted search (don’t require [ ] brackets as is an array).

The other key aspect of this type of embedding is when the parameter values are chosen by the end user there needs to be a way to send these values to the iFrame by either using the APEX page level ‘Execute when Page Loads’ parameter or by using a Dynamic Action that is invoked when the faceted search values change.


Thanks for reading, I hope this blog has been useful and provided some ideas of how you can embed Oracle Analytics in your own projects. I’d like to acknowledge Arun, Matt, Lior, Jackie and Roel for their help and assistance with APEX.

If you’re curious about the goings-on of Oracle Developers in their natural habitat, come join us on our public Slack channel! We don’t mind being your fish bowl 🐠



Aggregation of articles from Oracle engineers, Groundbreaker Ambassadors, Oracle ACEs, and Java Champions on all things Oracle technology. The views expressed are those of the authors and not necessarily of Oracle.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Mike Durran

Analytics Product Manager at Oracle. [All content and opinions are my own]